mirror of
https://github.com/d4rken-org/capod.git
synced 2026-09-15 02:36:12 -04:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c23de67cd2 | ||
|
|
e9bb4868c8 | ||
|
|
ae6fd0eabd | ||
|
|
f4f73906bc | ||
|
|
c437decbbf | ||
|
|
1d36677ead | ||
|
|
542b69ca92 | ||
|
|
8547c9c396 | ||
|
|
4e258e65c1 | ||
|
|
9f49b470fe | ||
|
|
4a71cfe65a | ||
|
|
d06959f964 | ||
|
|
8c339ca2eb |
@@ -1,3 +1,4 @@
|
|||||||
.idea
|
.idea
|
||||||
.gradle
|
.gradle
|
||||||
build/
|
build/
|
||||||
|
/fastlane/report.xml
|
||||||
|
|||||||
+218
@@ -0,0 +1,218 @@
|
|||||||
|
GEM
|
||||||
|
remote: https://rubygems.org/
|
||||||
|
specs:
|
||||||
|
CFPropertyList (3.0.5)
|
||||||
|
rexml
|
||||||
|
addressable (2.8.0)
|
||||||
|
public_suffix (>= 2.0.2, < 5.0)
|
||||||
|
artifactory (3.0.15)
|
||||||
|
atomos (0.1.3)
|
||||||
|
aws-eventstream (1.2.0)
|
||||||
|
aws-partitions (1.554.0)
|
||||||
|
aws-sdk-core (3.126.0)
|
||||||
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
|
aws-partitions (~> 1, >= 1.525.0)
|
||||||
|
aws-sigv4 (~> 1.1)
|
||||||
|
jmespath (~> 1.0)
|
||||||
|
aws-sdk-kms (1.54.0)
|
||||||
|
aws-sdk-core (~> 3, >= 3.126.0)
|
||||||
|
aws-sigv4 (~> 1.1)
|
||||||
|
aws-sdk-s3 (1.112.0)
|
||||||
|
aws-sdk-core (~> 3, >= 3.126.0)
|
||||||
|
aws-sdk-kms (~> 1)
|
||||||
|
aws-sigv4 (~> 1.4)
|
||||||
|
aws-sigv4 (1.4.0)
|
||||||
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
|
babosa (1.0.4)
|
||||||
|
claide (1.1.0)
|
||||||
|
colored (1.2)
|
||||||
|
colored2 (3.1.2)
|
||||||
|
commander (4.6.0)
|
||||||
|
highline (~> 2.0.0)
|
||||||
|
declarative (0.0.20)
|
||||||
|
digest-crc (0.6.4)
|
||||||
|
rake (>= 12.0.0, < 14.0.0)
|
||||||
|
domain_name (0.5.20190701)
|
||||||
|
unf (>= 0.0.5, < 1.0.0)
|
||||||
|
dotenv (2.7.6)
|
||||||
|
emoji_regex (3.2.3)
|
||||||
|
excon (0.91.0)
|
||||||
|
faraday (1.9.3)
|
||||||
|
faraday-em_http (~> 1.0)
|
||||||
|
faraday-em_synchrony (~> 1.0)
|
||||||
|
faraday-excon (~> 1.1)
|
||||||
|
faraday-httpclient (~> 1.0)
|
||||||
|
faraday-multipart (~> 1.0)
|
||||||
|
faraday-net_http (~> 1.0)
|
||||||
|
faraday-net_http_persistent (~> 1.0)
|
||||||
|
faraday-patron (~> 1.0)
|
||||||
|
faraday-rack (~> 1.0)
|
||||||
|
faraday-retry (~> 1.0)
|
||||||
|
ruby2_keywords (>= 0.0.4)
|
||||||
|
faraday-cookie_jar (0.0.7)
|
||||||
|
faraday (>= 0.8.0)
|
||||||
|
http-cookie (~> 1.0.0)
|
||||||
|
faraday-em_http (1.0.0)
|
||||||
|
faraday-em_synchrony (1.0.0)
|
||||||
|
faraday-excon (1.1.0)
|
||||||
|
faraday-httpclient (1.0.1)
|
||||||
|
faraday-multipart (1.0.3)
|
||||||
|
multipart-post (>= 1.2, < 3)
|
||||||
|
faraday-net_http (1.0.1)
|
||||||
|
faraday-net_http_persistent (1.2.0)
|
||||||
|
faraday-patron (1.0.0)
|
||||||
|
faraday-rack (1.0.0)
|
||||||
|
faraday-retry (1.0.3)
|
||||||
|
faraday_middleware (1.2.0)
|
||||||
|
faraday (~> 1.0)
|
||||||
|
fastimage (2.2.6)
|
||||||
|
fastlane (2.204.3)
|
||||||
|
CFPropertyList (>= 2.3, < 4.0.0)
|
||||||
|
addressable (>= 2.8, < 3.0.0)
|
||||||
|
artifactory (~> 3.0)
|
||||||
|
aws-sdk-s3 (~> 1.0)
|
||||||
|
babosa (>= 1.0.3, < 2.0.0)
|
||||||
|
bundler (>= 1.12.0, < 3.0.0)
|
||||||
|
colored
|
||||||
|
commander (~> 4.6)
|
||||||
|
dotenv (>= 2.1.1, < 3.0.0)
|
||||||
|
emoji_regex (>= 0.1, < 4.0)
|
||||||
|
excon (>= 0.71.0, < 1.0.0)
|
||||||
|
faraday (~> 1.0)
|
||||||
|
faraday-cookie_jar (~> 0.0.6)
|
||||||
|
faraday_middleware (~> 1.0)
|
||||||
|
fastimage (>= 2.1.0, < 3.0.0)
|
||||||
|
gh_inspector (>= 1.1.2, < 2.0.0)
|
||||||
|
google-apis-androidpublisher_v3 (~> 0.3)
|
||||||
|
google-apis-playcustomapp_v1 (~> 0.1)
|
||||||
|
google-cloud-storage (~> 1.31)
|
||||||
|
highline (~> 2.0)
|
||||||
|
json (< 3.0.0)
|
||||||
|
jwt (>= 2.1.0, < 3)
|
||||||
|
mini_magick (>= 4.9.4, < 5.0.0)
|
||||||
|
multipart-post (~> 2.0.0)
|
||||||
|
naturally (~> 2.2)
|
||||||
|
optparse (~> 0.1.1)
|
||||||
|
plist (>= 3.1.0, < 4.0.0)
|
||||||
|
rubyzip (>= 2.0.0, < 3.0.0)
|
||||||
|
security (= 0.1.3)
|
||||||
|
simctl (~> 1.6.3)
|
||||||
|
terminal-notifier (>= 2.0.0, < 3.0.0)
|
||||||
|
terminal-table (>= 1.4.5, < 2.0.0)
|
||||||
|
tty-screen (>= 0.6.3, < 1.0.0)
|
||||||
|
tty-spinner (>= 0.8.0, < 1.0.0)
|
||||||
|
word_wrap (~> 1.0.0)
|
||||||
|
xcodeproj (>= 1.13.0, < 2.0.0)
|
||||||
|
xcpretty (~> 0.3.0)
|
||||||
|
xcpretty-travis-formatter (>= 0.0.3)
|
||||||
|
gh_inspector (1.1.3)
|
||||||
|
google-apis-androidpublisher_v3 (0.16.0)
|
||||||
|
google-apis-core (>= 0.4, < 2.a)
|
||||||
|
google-apis-core (0.4.2)
|
||||||
|
addressable (~> 2.5, >= 2.5.1)
|
||||||
|
googleauth (>= 0.16.2, < 2.a)
|
||||||
|
httpclient (>= 2.8.1, < 3.a)
|
||||||
|
mini_mime (~> 1.0)
|
||||||
|
representable (~> 3.0)
|
||||||
|
retriable (>= 2.0, < 4.a)
|
||||||
|
rexml
|
||||||
|
webrick
|
||||||
|
google-apis-iamcredentials_v1 (0.10.0)
|
||||||
|
google-apis-core (>= 0.4, < 2.a)
|
||||||
|
google-apis-playcustomapp_v1 (0.7.0)
|
||||||
|
google-apis-core (>= 0.4, < 2.a)
|
||||||
|
google-apis-storage_v1 (0.11.0)
|
||||||
|
google-apis-core (>= 0.4, < 2.a)
|
||||||
|
google-cloud-core (1.6.0)
|
||||||
|
google-cloud-env (~> 1.0)
|
||||||
|
google-cloud-errors (~> 1.0)
|
||||||
|
google-cloud-env (1.5.0)
|
||||||
|
faraday (>= 0.17.3, < 2.0)
|
||||||
|
google-cloud-errors (1.2.0)
|
||||||
|
google-cloud-storage (1.36.1)
|
||||||
|
addressable (~> 2.8)
|
||||||
|
digest-crc (~> 0.4)
|
||||||
|
google-apis-iamcredentials_v1 (~> 0.1)
|
||||||
|
google-apis-storage_v1 (~> 0.1)
|
||||||
|
google-cloud-core (~> 1.6)
|
||||||
|
googleauth (>= 0.16.2, < 2.a)
|
||||||
|
mini_mime (~> 1.0)
|
||||||
|
googleauth (1.1.0)
|
||||||
|
faraday (>= 0.17.3, < 2.0)
|
||||||
|
jwt (>= 1.4, < 3.0)
|
||||||
|
memoist (~> 0.16)
|
||||||
|
multi_json (~> 1.11)
|
||||||
|
os (>= 0.9, < 2.0)
|
||||||
|
signet (>= 0.16, < 2.a)
|
||||||
|
highline (2.0.3)
|
||||||
|
http-cookie (1.0.4)
|
||||||
|
domain_name (~> 0.5)
|
||||||
|
httpclient (2.8.3)
|
||||||
|
jmespath (1.5.0)
|
||||||
|
json (2.6.1)
|
||||||
|
jwt (2.3.0)
|
||||||
|
memoist (0.16.2)
|
||||||
|
mini_magick (4.11.0)
|
||||||
|
mini_mime (1.1.2)
|
||||||
|
multi_json (1.15.0)
|
||||||
|
multipart-post (2.0.0)
|
||||||
|
nanaimo (0.3.0)
|
||||||
|
naturally (2.2.1)
|
||||||
|
optparse (0.1.1)
|
||||||
|
os (1.1.4)
|
||||||
|
plist (3.6.0)
|
||||||
|
public_suffix (4.0.6)
|
||||||
|
rake (13.0.6)
|
||||||
|
representable (3.1.1)
|
||||||
|
declarative (< 0.1.0)
|
||||||
|
trailblazer-option (>= 0.1.1, < 0.2.0)
|
||||||
|
uber (< 0.2.0)
|
||||||
|
retriable (3.1.2)
|
||||||
|
rexml (3.2.5)
|
||||||
|
rouge (2.0.7)
|
||||||
|
ruby2_keywords (0.0.5)
|
||||||
|
rubyzip (2.3.2)
|
||||||
|
security (0.1.3)
|
||||||
|
signet (0.16.0)
|
||||||
|
addressable (~> 2.8)
|
||||||
|
faraday (>= 0.17.3, < 2.0)
|
||||||
|
jwt (>= 1.5, < 3.0)
|
||||||
|
multi_json (~> 1.10)
|
||||||
|
simctl (1.6.8)
|
||||||
|
CFPropertyList
|
||||||
|
naturally
|
||||||
|
terminal-notifier (2.0.0)
|
||||||
|
terminal-table (1.8.0)
|
||||||
|
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||||
|
trailblazer-option (0.1.2)
|
||||||
|
tty-cursor (0.7.1)
|
||||||
|
tty-screen (0.8.1)
|
||||||
|
tty-spinner (0.9.3)
|
||||||
|
tty-cursor (~> 0.7)
|
||||||
|
uber (0.1.0)
|
||||||
|
unf (0.1.4)
|
||||||
|
unf_ext
|
||||||
|
unf_ext (0.0.8)
|
||||||
|
unicode-display_width (1.8.0)
|
||||||
|
webrick (1.7.0)
|
||||||
|
word_wrap (1.0.0)
|
||||||
|
xcodeproj (1.21.0)
|
||||||
|
CFPropertyList (>= 2.3.3, < 4.0)
|
||||||
|
atomos (~> 0.1.3)
|
||||||
|
claide (>= 1.0.2, < 2.0)
|
||||||
|
colored2 (~> 3.1)
|
||||||
|
nanaimo (~> 0.3.0)
|
||||||
|
rexml (~> 3.2.4)
|
||||||
|
xcpretty (0.3.0)
|
||||||
|
rouge (~> 2.0.7)
|
||||||
|
xcpretty-travis-formatter (1.0.1)
|
||||||
|
xcpretty (~> 0.2, >= 0.0.7)
|
||||||
|
|
||||||
|
PLATFORMS
|
||||||
|
x86_64-linux
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
fastlane
|
||||||
|
|
||||||
|
BUNDLED WITH
|
||||||
|
2.2.8
|
||||||
@@ -1,2 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources></resources>
|
<resources>
|
||||||
|
<string name="foss_upgrade_donate_label">Donar</string>
|
||||||
|
<string name="foss_upgrade_alreadydonated_label">Ya doné</string>
|
||||||
|
<string name="foss_upgrade_no_money_label">Gasto todo mi dinero en AirPods</string>
|
||||||
|
</resources>
|
||||||
|
|||||||
@@ -1,2 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources></resources>
|
<resources>
|
||||||
|
<string name="foss_upgrade_donate_label">दान करना</string>
|
||||||
|
<string name="foss_upgrade_alreadydonated_label">मैंने पहले ही दान कर दिया है</string>
|
||||||
|
<string name="foss_upgrade_no_money_label">मैं अपना सारा पैसा AirPods पर खर्च करता हूं</string>
|
||||||
|
</resources>
|
||||||
|
|||||||
@@ -1,2 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources></resources>
|
<resources>
|
||||||
|
<string name="upgrades_gplay_unavailable_error">Los servicios de Google Play no están disponibles.</string>
|
||||||
|
<string name="upgrades_no_purchases_found_check_account">No se han encontrado compras. ¿Estás usando la cuenta correcta?</string>
|
||||||
|
</resources>
|
||||||
|
|||||||
@@ -1,2 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources></resources>
|
<resources>
|
||||||
|
<string name="upgrades_gplay_unavailable_error">Google Play सेवाएं अनुपलब्ध हैं।</string>
|
||||||
|
<string name="upgrades_no_purchases_found_check_account">कोई खरीदारी नहीं मिली. क्या आप सही खाते का उपयोग कर रहे हैं?</string>
|
||||||
|
</resources>
|
||||||
|
|||||||
@@ -56,7 +56,11 @@ class BleScanner @Inject constructor(
|
|||||||
lastScanAt = System.currentTimeMillis()
|
lastScanAt = System.currentTimeMillis()
|
||||||
"onScanResult(delay=${delay}ms, callbackType=$callbackType, result=$result)"
|
"onScanResult(delay=${delay}ms, callbackType=$callbackType, result=$result)"
|
||||||
}
|
}
|
||||||
val toSend = if (supportsOffloadFiltering || filters.isEmpty() || filters.any { it.matches(result) }) {
|
val toSend = if (
|
||||||
|
supportsOffloadFiltering
|
||||||
|
|| filters.isEmpty()
|
||||||
|
|| filters.any { it.matchesSafe(result) }
|
||||||
|
) {
|
||||||
listOf(BleScanResult.fromScanResult(result))
|
listOf(BleScanResult.fromScanResult(result))
|
||||||
} else {
|
} else {
|
||||||
log(TAG, VERBOSE) { "Manual filtering: No match for $result" }
|
log(TAG, VERBOSE) { "Manual filtering: No match for $result" }
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
package eu.darken.capod.common.bluetooth
|
|
||||||
|
|
||||||
import android.bluetooth.BluetoothDevice
|
|
||||||
import android.os.ParcelUuid
|
|
||||||
|
|
||||||
fun BluetoothDevice.hasFeature(uuid: ParcelUuid): Boolean {
|
|
||||||
return uuids?.contains(uuid) ?: false
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package eu.darken.capod.common.bluetooth
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothDevice
|
||||||
|
import android.bluetooth.le.ScanFilter
|
||||||
|
import android.bluetooth.le.ScanResult
|
||||||
|
import android.os.ParcelUuid
|
||||||
|
import eu.darken.capod.common.debug.logging.asLog
|
||||||
|
import eu.darken.capod.common.debug.logging.log
|
||||||
|
|
||||||
|
fun BluetoothDevice.hasFeature(uuid: ParcelUuid): Boolean {
|
||||||
|
return uuids?.contains(uuid) ?: false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.util.SparseArray.get(int)' on a null object reference
|
||||||
|
* at android.bluetooth.le.ScanRecord.getManufacturerSpecificData(ScanRecord.java:118)
|
||||||
|
* at android.bluetooth.le.ScanFilter.matches(ScanFilter.java:369)
|
||||||
|
* ZenFone Max Pro M1 (ZB602KL) (WW) / Max Pro M1 (ZB601KL) (IN) (ZB602KL), Android 9, PKQ1.WW_Phone-16.2017.2009.087-20200826
|
||||||
|
* Intel Gemini Lake Chromebook (octopus), Android 9, R99-14469.59.0 release-keys
|
||||||
|
*/
|
||||||
|
fun ScanFilter.matchesSafe(scanResult: ScanResult): Boolean = try {
|
||||||
|
matches(scanResult)
|
||||||
|
} catch (e: NullPointerException) {
|
||||||
|
log { "AOSP error: ${e.asLog()}" }
|
||||||
|
false
|
||||||
|
}
|
||||||
@@ -14,9 +14,8 @@ import eu.darken.capod.common.lists.modular.mods.TypedVHCreatorMod
|
|||||||
import eu.darken.capod.main.ui.overview.cards.BluetoothDisabledVH
|
import eu.darken.capod.main.ui.overview.cards.BluetoothDisabledVH
|
||||||
import eu.darken.capod.main.ui.overview.cards.MissingMainDeviceVH
|
import eu.darken.capod.main.ui.overview.cards.MissingMainDeviceVH
|
||||||
import eu.darken.capod.main.ui.overview.cards.PermissionCardVH
|
import eu.darken.capod.main.ui.overview.cards.PermissionCardVH
|
||||||
import eu.darken.capod.main.ui.overview.cards.pods.BasicSingleApplePodsCardVH
|
import eu.darken.capod.main.ui.overview.cards.pods.DualPodsCardVH
|
||||||
import eu.darken.capod.main.ui.overview.cards.pods.DualApplePodsCardVH
|
import eu.darken.capod.main.ui.overview.cards.pods.SinglePodsCardVH
|
||||||
import eu.darken.capod.main.ui.overview.cards.pods.SingleApplePodsCardVH
|
|
||||||
import eu.darken.capod.main.ui.overview.cards.pods.UnknownPodDeviceCardVH
|
import eu.darken.capod.main.ui.overview.cards.pods.UnknownPodDeviceCardVH
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@@ -29,9 +28,8 @@ class OverviewAdapter @Inject constructor() :
|
|||||||
init {
|
init {
|
||||||
modules.add(DataBinderMod(data))
|
modules.add(DataBinderMod(data))
|
||||||
modules.add(TypedVHCreatorMod({ data[it] is PermissionCardVH.Item }) { PermissionCardVH(it) })
|
modules.add(TypedVHCreatorMod({ data[it] is PermissionCardVH.Item }) { PermissionCardVH(it) })
|
||||||
modules.add(TypedVHCreatorMod({ data[it] is DualApplePodsCardVH.Item }) { DualApplePodsCardVH(it) })
|
modules.add(TypedVHCreatorMod({ data[it] is DualPodsCardVH.Item }) { DualPodsCardVH(it) })
|
||||||
modules.add(TypedVHCreatorMod({ data[it] is SingleApplePodsCardVH.Item }) { SingleApplePodsCardVH(it) })
|
modules.add(TypedVHCreatorMod({ data[it] is SinglePodsCardVH.Item }) { SinglePodsCardVH(it) })
|
||||||
modules.add(TypedVHCreatorMod({ data[it] is BasicSingleApplePodsCardVH.Item }) { BasicSingleApplePodsCardVH(it) })
|
|
||||||
modules.add(TypedVHCreatorMod({ data[it] is MissingMainDeviceVH.Item }) { MissingMainDeviceVH(it) })
|
modules.add(TypedVHCreatorMod({ data[it] is MissingMainDeviceVH.Item }) { MissingMainDeviceVH(it) })
|
||||||
modules.add(TypedVHCreatorMod({ data[it] is BluetoothDisabledVH.Item }) { BluetoothDisabledVH(it) })
|
modules.add(TypedVHCreatorMod({ data[it] is BluetoothDisabledVH.Item }) { BluetoothDisabledVH(it) })
|
||||||
modules.add(TypedVHCreatorMod({ data[it] is UnknownPodDeviceCardVH.Item }) { UnknownPodDeviceCardVH(it) })
|
modules.add(TypedVHCreatorMod({ data[it] is UnknownPodDeviceCardVH.Item }) { UnknownPodDeviceCardVH(it) })
|
||||||
|
|||||||
@@ -20,23 +20,23 @@ import eu.darken.capod.main.core.PermissionTool
|
|||||||
import eu.darken.capod.main.ui.overview.cards.BluetoothDisabledVH
|
import eu.darken.capod.main.ui.overview.cards.BluetoothDisabledVH
|
||||||
import eu.darken.capod.main.ui.overview.cards.MissingMainDeviceVH
|
import eu.darken.capod.main.ui.overview.cards.MissingMainDeviceVH
|
||||||
import eu.darken.capod.main.ui.overview.cards.PermissionCardVH
|
import eu.darken.capod.main.ui.overview.cards.PermissionCardVH
|
||||||
import eu.darken.capod.main.ui.overview.cards.pods.*
|
import eu.darken.capod.main.ui.overview.cards.pods.DualPodsCardVH
|
||||||
|
import eu.darken.capod.main.ui.overview.cards.pods.SinglePodsCardVH
|
||||||
|
import eu.darken.capod.main.ui.overview.cards.pods.UnknownPodDeviceCardVH
|
||||||
import eu.darken.capod.monitor.core.PodMonitor
|
import eu.darken.capod.monitor.core.PodMonitor
|
||||||
import eu.darken.capod.monitor.core.worker.MonitorControl
|
import eu.darken.capod.monitor.core.worker.MonitorControl
|
||||||
|
import eu.darken.capod.pods.core.DualPodDevice
|
||||||
import eu.darken.capod.pods.core.PodDevice
|
import eu.darken.capod.pods.core.PodDevice
|
||||||
import eu.darken.capod.pods.core.apple.BasicSingleApplePods
|
import eu.darken.capod.pods.core.SinglePodDevice
|
||||||
import eu.darken.capod.pods.core.apple.DualApplePods
|
|
||||||
import eu.darken.capod.pods.core.apple.SingleApplePods
|
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.util.*
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class OverviewFragmentVM @Inject constructor(
|
class OverviewFragmentVM @Inject constructor(
|
||||||
handle: SavedStateHandle,
|
@Suppress("UNUSED_PARAMETER") handle: SavedStateHandle,
|
||||||
dispatcherProvider: DispatcherProvider,
|
dispatcherProvider: DispatcherProvider,
|
||||||
private val monitorControl: MonitorControl,
|
private val monitorControl: MonitorControl,
|
||||||
private val podMonitor: PodMonitor,
|
private val podMonitor: PodMonitor,
|
||||||
@@ -74,7 +74,7 @@ class OverviewFragmentVM @Inject constructor(
|
|||||||
monitorControl.startMonitor()
|
monitorControl.startMonitor()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.map { Unit }
|
.map { }
|
||||||
.asLiveData2()
|
.asLiveData2()
|
||||||
|
|
||||||
val requestPermissionEvent = SingleLiveEvent<Permission>()
|
val requestPermissionEvent = SingleLiveEvent<Permission>()
|
||||||
@@ -129,19 +129,13 @@ class OverviewFragmentVM @Inject constructor(
|
|||||||
pods.map {
|
pods.map {
|
||||||
val now = Instant.now()
|
val now = Instant.now()
|
||||||
when (it) {
|
when (it) {
|
||||||
is DualApplePods -> DualApplePodsCardVH.Item(
|
is DualPodDevice -> DualPodsCardVH.Item(
|
||||||
now = now,
|
now = now,
|
||||||
device = it,
|
device = it,
|
||||||
showDebug = isDebugMode,
|
showDebug = isDebugMode,
|
||||||
isMainPod = it == mainPod,
|
isMainPod = it == mainPod,
|
||||||
)
|
)
|
||||||
is SingleApplePods -> SingleApplePodsCardVH.Item(
|
is SinglePodDevice -> SinglePodsCardVH.Item(
|
||||||
now = now,
|
|
||||||
device = it,
|
|
||||||
showDebug = isDebugMode,
|
|
||||||
isMainPod = it == mainPod,
|
|
||||||
)
|
|
||||||
is BasicSingleApplePods -> BasicSingleApplePodsCardVH.Item(
|
|
||||||
now = now,
|
now = now,
|
||||||
device = it,
|
device = it,
|
||||||
showDebug = isDebugMode,
|
showDebug = isDebugMode,
|
||||||
|
|||||||
-58
@@ -1,58 +0,0 @@
|
|||||||
package eu.darken.capod.main.ui.overview.cards.pods
|
|
||||||
|
|
||||||
import android.graphics.Typeface
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.view.isGone
|
|
||||||
import eu.darken.capod.R
|
|
||||||
import eu.darken.capod.common.lists.binding
|
|
||||||
import eu.darken.capod.databinding.OverviewPodsAppleSingleBasicItemBinding
|
|
||||||
import eu.darken.capod.pods.core.apple.BasicSingleApplePods
|
|
||||||
import eu.darken.capod.pods.core.getBatteryDrawable
|
|
||||||
import eu.darken.capod.pods.core.getBatteryLevelHeadset
|
|
||||||
import eu.darken.capod.pods.core.lastSeenFormatted
|
|
||||||
import java.time.Instant
|
|
||||||
|
|
||||||
class BasicSingleApplePodsCardVH(parent: ViewGroup) :
|
|
||||||
PodDeviceVH<BasicSingleApplePodsCardVH.Item, OverviewPodsAppleSingleBasicItemBinding>(
|
|
||||||
R.layout.overview_pods_apple_single_basic_item,
|
|
||||||
parent
|
|
||||||
) {
|
|
||||||
|
|
||||||
override val viewBinding = lazy { OverviewPodsAppleSingleBasicItemBinding.bind(itemView) }
|
|
||||||
|
|
||||||
override val onBindData = binding(payload = true) { item: Item ->
|
|
||||||
val device = item.device
|
|
||||||
|
|
||||||
name.apply {
|
|
||||||
text = device.getLabel(context)
|
|
||||||
if (item.isMainPod) setTypeface(typeface, Typeface.BOLD)
|
|
||||||
else setTypeface(typeface, Typeface.NORMAL)
|
|
||||||
}
|
|
||||||
|
|
||||||
deviceIcon.setImageResource(device.iconRes)
|
|
||||||
|
|
||||||
lastSeen.text = device.lastSeenFormatted(item.now)
|
|
||||||
|
|
||||||
reception.text = item.getReceptionText()
|
|
||||||
|
|
||||||
batteryLabel.text = device.getBatteryLevelHeadset(context)
|
|
||||||
batteryIcon.setImageResource(getBatteryDrawable(device.batteryHeadsetPercent))
|
|
||||||
|
|
||||||
status.apply {
|
|
||||||
val sb = StringBuilder()
|
|
||||||
if (item.showDebug) {
|
|
||||||
sb.append("--- Debug ---")
|
|
||||||
sb.append("\n").append(device.rawDataHex)
|
|
||||||
}
|
|
||||||
text = sb
|
|
||||||
isGone = !item.showDebug
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class Item(
|
|
||||||
override val now: Instant,
|
|
||||||
override val device: BasicSingleApplePods,
|
|
||||||
override val showDebug: Boolean,
|
|
||||||
override val isMainPod: Boolean,
|
|
||||||
) : PodDeviceVH.Item
|
|
||||||
}
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
package eu.darken.capod.main.ui.overview.cards.pods
|
|
||||||
|
|
||||||
import android.graphics.Typeface
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.view.isGone
|
|
||||||
import androidx.core.view.isInvisible
|
|
||||||
import eu.darken.capod.R
|
|
||||||
import eu.darken.capod.common.lists.binding
|
|
||||||
import eu.darken.capod.databinding.OverviewPodsAppleDualItemBinding
|
|
||||||
import eu.darken.capod.pods.core.*
|
|
||||||
import eu.darken.capod.pods.core.apple.DualApplePods
|
|
||||||
import eu.darken.capod.pods.core.apple.DualApplePods.DeviceColor
|
|
||||||
import eu.darken.capod.pods.core.apple.DualApplePods.LidState
|
|
||||||
import java.time.Duration
|
|
||||||
import java.time.Instant
|
|
||||||
|
|
||||||
class DualApplePodsCardVH(parent: ViewGroup) :
|
|
||||||
PodDeviceVH<DualApplePodsCardVH.Item, OverviewPodsAppleDualItemBinding>(
|
|
||||||
R.layout.overview_pods_apple_dual_item,
|
|
||||||
parent
|
|
||||||
) {
|
|
||||||
|
|
||||||
override val viewBinding = lazy { OverviewPodsAppleDualItemBinding.bind(itemView) }
|
|
||||||
|
|
||||||
override val onBindData = binding(payload = true) { item: Item ->
|
|
||||||
val device = item.device
|
|
||||||
name.apply {
|
|
||||||
val sb = StringBuilder(device.getLabel(context))
|
|
||||||
if (!listOf(DeviceColor.WHITE, DeviceColor.UNKNOWN).contains(device.deviceColor)) {
|
|
||||||
sb.append(" (${device.deviceColor.name})")
|
|
||||||
}
|
|
||||||
text = sb
|
|
||||||
if (item.isMainPod) setTypeface(typeface, Typeface.BOLD)
|
|
||||||
else setTypeface(typeface, Typeface.NORMAL)
|
|
||||||
if (item.showDebug) {
|
|
||||||
append(" [${device.primaryPod.name}]")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
deviceIcon.setImageResource(device.iconRes)
|
|
||||||
|
|
||||||
lastSeen.text = context.getString(R.string.last_seen_x, device.lastSeenFormatted(item.now))
|
|
||||||
firstSeen.text = context.getString(R.string.first_seen_x, device.firstSeenFormatted(item.now))
|
|
||||||
firstSeen.isGone = Duration.between(device.seenFirstAt, device.seenLastAt).toMinutes() < 1
|
|
||||||
|
|
||||||
reception.text = item.getReceptionText()
|
|
||||||
|
|
||||||
// Left Pod
|
|
||||||
device.apply {
|
|
||||||
podLeftBatteryIcon.setImageResource(getBatteryDrawable(batteryLeftPodPercent))
|
|
||||||
podLeftBatteryLabel.text = getBatteryLevelLeftPod(context)
|
|
||||||
|
|
||||||
podLeftChargingIcon.isInvisible = !isLeftPodCharging
|
|
||||||
podLeftChargingLabel.isInvisible = !isLeftPodCharging
|
|
||||||
|
|
||||||
podLeftMicrophoneIcon.isInvisible = !isLeftPodMicrophone
|
|
||||||
podLeftMicrophoneLabel.isInvisible = !isLeftPodMicrophone
|
|
||||||
|
|
||||||
podLeftWearIcon.isInvisible = !isLeftPodInEar
|
|
||||||
podLeftWearLabel.isInvisible = !isLeftPodInEar
|
|
||||||
}
|
|
||||||
|
|
||||||
// Right Pod
|
|
||||||
device.apply {
|
|
||||||
podRightBatteryIcon.setImageResource(getBatteryDrawable(batteryRightPodPercent))
|
|
||||||
podRightBatteryLabel.text = getBatteryLevelRightPod(context)
|
|
||||||
|
|
||||||
podRightChargingIcon.isInvisible = !isRightPodCharging
|
|
||||||
podRightChargingLabel.isInvisible = !isRightPodCharging
|
|
||||||
|
|
||||||
podRightMicrophoneIcon.isInvisible = !isRightPodMicrophone
|
|
||||||
podRightMicrophoneLabel.isInvisible = !isRightPodMicrophone
|
|
||||||
|
|
||||||
podRightWearIcon.isInvisible = !isRightPodInEar
|
|
||||||
podRightWearLabel.isInvisible = !isRightPodInEar
|
|
||||||
}
|
|
||||||
|
|
||||||
// Case
|
|
||||||
device.apply {
|
|
||||||
podCaseBatteryIcon.setImageResource(getBatteryDrawable(batteryCasePercent))
|
|
||||||
podCaseBatteryLabel.text = getBatteryLevelCase(context)
|
|
||||||
|
|
||||||
podCaseChargingIcon.isInvisible = !isCaseCharging
|
|
||||||
podCaseChargingLabel.isInvisible = !isCaseCharging
|
|
||||||
|
|
||||||
podCaseLidLabel.text = when (caseLidState) {
|
|
||||||
LidState.OPEN -> context.getString(R.string.pods_case_status_open_label)
|
|
||||||
LidState.CLOSED -> context.getString(R.string.pods_case_status_closed_label)
|
|
||||||
else -> context.getString(R.string.pods_case_unknown_state)
|
|
||||||
}
|
|
||||||
|
|
||||||
val hideInfo = !listOf(LidState.OPEN, LidState.CLOSED).contains(caseLidState)
|
|
||||||
podCaseLidIcon.isInvisible = hideInfo
|
|
||||||
podCaseLidLabel.isInvisible = hideInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
status.apply {
|
|
||||||
val sb = StringBuilder(device.getConnectionStateLabel(context))
|
|
||||||
if (item.showDebug) {
|
|
||||||
sb.append("\n\n").append("---Debug---")
|
|
||||||
sb.append("\n").append(device.rawDataHex)
|
|
||||||
}
|
|
||||||
text = sb
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class Item(
|
|
||||||
override val now: Instant,
|
|
||||||
override val device: DualApplePods,
|
|
||||||
override val showDebug: Boolean,
|
|
||||||
override val isMainPod: Boolean,
|
|
||||||
) : PodDeviceVH.Item
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
package eu.darken.capod.main.ui.overview.cards.pods
|
||||||
|
|
||||||
|
import android.graphics.Typeface
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.view.isGone
|
||||||
|
import androidx.core.view.isInvisible
|
||||||
|
import eu.darken.capod.R
|
||||||
|
import eu.darken.capod.common.lists.binding
|
||||||
|
import eu.darken.capod.databinding.OverviewPodsDualItemBinding
|
||||||
|
import eu.darken.capod.pods.core.*
|
||||||
|
import eu.darken.capod.pods.core.apple.DualAirPods
|
||||||
|
import eu.darken.capod.pods.core.apple.DualAirPods.LidState
|
||||||
|
import java.time.Duration
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
class DualPodsCardVH(parent: ViewGroup) :
|
||||||
|
PodDeviceVH<DualPodsCardVH.Item, OverviewPodsDualItemBinding>(
|
||||||
|
R.layout.overview_pods_dual_item,
|
||||||
|
parent
|
||||||
|
) {
|
||||||
|
|
||||||
|
override val viewBinding = lazy { OverviewPodsDualItemBinding.bind(itemView) }
|
||||||
|
|
||||||
|
override val onBindData = binding(payload = true) { item: Item ->
|
||||||
|
val device = item.device
|
||||||
|
name.apply {
|
||||||
|
val sb = StringBuilder(device.getLabel(context))
|
||||||
|
if (device is HasPodStyle && item.showDebug) {
|
||||||
|
val style = device.podStyle
|
||||||
|
sb.append(" (${style.getColor(context)})")
|
||||||
|
}
|
||||||
|
text = sb
|
||||||
|
|
||||||
|
if (item.isMainPod) setTypeface(typeface, Typeface.BOLD)
|
||||||
|
else setTypeface(typeface, Typeface.NORMAL)
|
||||||
|
|
||||||
|
if (device is DualAirPods && item.showDebug) {
|
||||||
|
append(" [${device.primaryPod.name}]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deviceIcon.setImageResource(device.iconRes)
|
||||||
|
|
||||||
|
lastSeen.text = context.getString(R.string.last_seen_x, device.lastSeenFormatted(item.now))
|
||||||
|
firstSeen.text = context.getString(R.string.first_seen_x, device.firstSeenFormatted(item.now))
|
||||||
|
firstSeen.isGone = Duration.between(device.seenFirstAt, device.seenLastAt).toMinutes() < 1
|
||||||
|
|
||||||
|
reception.text = item.getReceptionText()
|
||||||
|
|
||||||
|
// Pods battery state
|
||||||
|
device.apply {
|
||||||
|
podLeftBatteryIcon.setImageResource(getBatteryDrawable(batteryLeftPodPercent))
|
||||||
|
podLeftBatteryLabel.text = getBatteryLevelLeftPod(context)
|
||||||
|
|
||||||
|
podRightBatteryIcon.setImageResource(getBatteryDrawable(batteryRightPodPercent))
|
||||||
|
podRightBatteryLabel.text = getBatteryLevelRightPod(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pods charging state
|
||||||
|
device.apply {
|
||||||
|
if (this is HasChargeDetectionDual) {
|
||||||
|
podLeftChargingIcon.isInvisible = !isLeftPodCharging
|
||||||
|
podLeftChargingLabel.isInvisible = !isLeftPodCharging
|
||||||
|
|
||||||
|
podRightChargingIcon.isInvisible = !isRightPodCharging
|
||||||
|
podRightChargingLabel.isInvisible = !isRightPodCharging
|
||||||
|
} else {
|
||||||
|
podLeftChargingIcon.isGone = true
|
||||||
|
podLeftChargingLabel.isGone = true
|
||||||
|
|
||||||
|
podRightChargingIcon.isGone = true
|
||||||
|
podRightChargingLabel.isGone = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Microphone state
|
||||||
|
device.apply {
|
||||||
|
if (this is HasDualMicrophone) {
|
||||||
|
podLeftMicrophoneIcon.isInvisible = !isLeftPodMicrophone
|
||||||
|
podLeftMicrophoneLabel.isInvisible = !isLeftPodMicrophone
|
||||||
|
|
||||||
|
podRightMicrophoneIcon.isInvisible = !isRightPodMicrophone
|
||||||
|
podRightMicrophoneLabel.isInvisible = !isRightPodMicrophone
|
||||||
|
} else {
|
||||||
|
podLeftMicrophoneIcon.isGone = true
|
||||||
|
podLeftMicrophoneLabel.isGone = true
|
||||||
|
|
||||||
|
podRightMicrophoneIcon.isGone = true
|
||||||
|
podRightMicrophoneLabel.isGone = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pods wear state
|
||||||
|
device.apply {
|
||||||
|
if (this is HasEarDetectionDual) {
|
||||||
|
podLeftWearIcon.isInvisible = !isLeftPodInEar
|
||||||
|
podLeftWearLabel.isInvisible = !isLeftPodInEar
|
||||||
|
|
||||||
|
podRightWearIcon.isInvisible = !isRightPodInEar
|
||||||
|
podRightWearLabel.isInvisible = !isRightPodInEar
|
||||||
|
} else {
|
||||||
|
podLeftWearIcon.isGone = true
|
||||||
|
podLeftWearLabel.isGone = true
|
||||||
|
|
||||||
|
podRightWearIcon.isGone = true
|
||||||
|
podRightWearLabel.isGone = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case charge state
|
||||||
|
device.apply {
|
||||||
|
if (this is HasCase) {
|
||||||
|
podCaseBatteryIcon.isGone = false
|
||||||
|
podCaseBatteryIcon.setImageResource(getBatteryDrawable(batteryCasePercent))
|
||||||
|
podCaseBatteryLabel.text = getBatteryLevelCase(context)
|
||||||
|
|
||||||
|
podCaseChargingIcon.isInvisible = !isCaseCharging
|
||||||
|
podCaseChargingLabel.isInvisible = !isCaseCharging
|
||||||
|
} else {
|
||||||
|
podCaseBatteryIcon.isGone = true
|
||||||
|
podCaseBatteryLabel.isGone = true
|
||||||
|
|
||||||
|
podCaseChargingIcon.isGone = true
|
||||||
|
podCaseChargingLabel.isGone = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case lid state
|
||||||
|
device.apply {
|
||||||
|
if (this is DualAirPods) {
|
||||||
|
podCaseLidLabel.text = when (caseLidState) {
|
||||||
|
LidState.OPEN -> context.getString(R.string.pods_case_status_open_label)
|
||||||
|
LidState.CLOSED -> context.getString(R.string.pods_case_status_closed_label)
|
||||||
|
else -> context.getString(R.string.pods_case_unknown_state)
|
||||||
|
}
|
||||||
|
|
||||||
|
val hideInfo = !listOf(LidState.OPEN, LidState.CLOSED).contains(caseLidState)
|
||||||
|
podCaseLidIcon.isInvisible = hideInfo
|
||||||
|
podCaseLidLabel.isInvisible = hideInfo
|
||||||
|
} else {
|
||||||
|
podCaseLidIcon.isGone = true
|
||||||
|
podCaseLidLabel.isGone = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connection state
|
||||||
|
device.apply {
|
||||||
|
val sb = StringBuilder()
|
||||||
|
if (this is HasStateDetection) {
|
||||||
|
sb.append(state.getLabel(context))
|
||||||
|
}
|
||||||
|
if (item.showDebug) {
|
||||||
|
sb.append("\n\n").append("---Debug---")
|
||||||
|
sb.append("\n").append(rawDataHex)
|
||||||
|
}
|
||||||
|
status.text = sb
|
||||||
|
status.isGone = sb.isEmpty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Item(
|
||||||
|
override val now: Instant,
|
||||||
|
override val device: DualPodDevice,
|
||||||
|
override val showDebug: Boolean,
|
||||||
|
override val isMainPod: Boolean,
|
||||||
|
) : PodDeviceVH.Item
|
||||||
|
}
|
||||||
-65
@@ -1,65 +0,0 @@
|
|||||||
package eu.darken.capod.main.ui.overview.cards.pods
|
|
||||||
|
|
||||||
import android.graphics.Typeface
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.view.isGone
|
|
||||||
import androidx.core.view.isInvisible
|
|
||||||
import eu.darken.capod.R
|
|
||||||
import eu.darken.capod.common.lists.binding
|
|
||||||
import eu.darken.capod.databinding.OverviewPodsAppleSingleItemBinding
|
|
||||||
import eu.darken.capod.pods.core.apple.SingleApplePods
|
|
||||||
import eu.darken.capod.pods.core.getBatteryDrawable
|
|
||||||
import eu.darken.capod.pods.core.getBatteryLevelHeadset
|
|
||||||
import eu.darken.capod.pods.core.lastSeenFormatted
|
|
||||||
import java.time.Instant
|
|
||||||
|
|
||||||
class SingleApplePodsCardVH(parent: ViewGroup) :
|
|
||||||
PodDeviceVH<SingleApplePodsCardVH.Item, OverviewPodsAppleSingleItemBinding>(
|
|
||||||
R.layout.overview_pods_apple_single_item,
|
|
||||||
parent
|
|
||||||
) {
|
|
||||||
|
|
||||||
override val viewBinding = lazy { OverviewPodsAppleSingleItemBinding.bind(itemView) }
|
|
||||||
|
|
||||||
override val onBindData = binding(payload = true) { item: Item ->
|
|
||||||
val device = item.device
|
|
||||||
|
|
||||||
name.apply {
|
|
||||||
text = device.getLabel(context)
|
|
||||||
if (item.isMainPod) setTypeface(typeface, Typeface.BOLD)
|
|
||||||
else setTypeface(typeface, Typeface.NORMAL)
|
|
||||||
}
|
|
||||||
|
|
||||||
deviceIcon.setImageResource(device.iconRes)
|
|
||||||
|
|
||||||
lastSeen.text = device.lastSeenFormatted(item.now)
|
|
||||||
|
|
||||||
reception.text = item.getReceptionText()
|
|
||||||
|
|
||||||
batteryLabel.text = device.getBatteryLevelHeadset(context)
|
|
||||||
batteryIcon.setImageResource(getBatteryDrawable(device.batteryHeadsetPercent))
|
|
||||||
|
|
||||||
chargingIcon.isInvisible = device.isHeadsetBeingCharged
|
|
||||||
chargingLabel.isInvisible = device.isHeadsetBeingCharged
|
|
||||||
|
|
||||||
wearIcon.isInvisible = device.isHeadphonesBeingWorn
|
|
||||||
wearLabel.isInvisible = device.isHeadphonesBeingWorn
|
|
||||||
|
|
||||||
status.apply {
|
|
||||||
val sb = StringBuilder()
|
|
||||||
if (item.showDebug) {
|
|
||||||
sb.append("--- Debug ---")
|
|
||||||
sb.append("\n").append(device.rawDataHex)
|
|
||||||
}
|
|
||||||
text = sb
|
|
||||||
isGone = !item.showDebug
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class Item(
|
|
||||||
override val now: Instant,
|
|
||||||
override val device: SingleApplePods,
|
|
||||||
override val showDebug: Boolean,
|
|
||||||
override val isMainPod: Boolean,
|
|
||||||
) : PodDeviceVH.Item
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package eu.darken.capod.main.ui.overview.cards.pods
|
||||||
|
|
||||||
|
import android.graphics.Typeface
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.view.isGone
|
||||||
|
import androidx.core.view.isInvisible
|
||||||
|
import eu.darken.capod.R
|
||||||
|
import eu.darken.capod.common.lists.binding
|
||||||
|
import eu.darken.capod.databinding.OverviewPodsSingleItemBinding
|
||||||
|
import eu.darken.capod.pods.core.*
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
class SinglePodsCardVH(parent: ViewGroup) :
|
||||||
|
PodDeviceVH<SinglePodsCardVH.Item, OverviewPodsSingleItemBinding>(
|
||||||
|
R.layout.overview_pods_single_item,
|
||||||
|
parent
|
||||||
|
) {
|
||||||
|
|
||||||
|
override val viewBinding = lazy { OverviewPodsSingleItemBinding.bind(itemView) }
|
||||||
|
|
||||||
|
override val onBindData = binding(payload = true) { item: Item ->
|
||||||
|
val device = item.device
|
||||||
|
|
||||||
|
name.apply {
|
||||||
|
text = device.getLabel(context)
|
||||||
|
if (item.isMainPod) setTypeface(typeface, Typeface.BOLD)
|
||||||
|
else setTypeface(typeface, Typeface.NORMAL)
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceIcon.setImageResource(device.iconRes)
|
||||||
|
|
||||||
|
lastSeen.text = device.lastSeenFormatted(item.now)
|
||||||
|
|
||||||
|
reception.text = item.getReceptionText()
|
||||||
|
|
||||||
|
// Battery level
|
||||||
|
device.apply {
|
||||||
|
batteryLabel.text = getBatteryLevelHeadset(context)
|
||||||
|
batteryIcon.setImageResource(getBatteryDrawable(batteryHeadsetPercent))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Charge state
|
||||||
|
device.apply {
|
||||||
|
if (this is HasChargeDetection) {
|
||||||
|
chargingIcon.isInvisible = isHeadsetBeingCharged
|
||||||
|
chargingLabel.isInvisible = isHeadsetBeingCharged
|
||||||
|
} else {
|
||||||
|
chargingIcon.isGone = true
|
||||||
|
chargingLabel.isGone = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Has ear detection
|
||||||
|
device.apply {
|
||||||
|
if (this is HasEarDetection) {
|
||||||
|
wearIcon.isInvisible = isBeingWorn
|
||||||
|
wearLabel.isInvisible = isBeingWorn
|
||||||
|
} else {
|
||||||
|
wearIcon.isGone = true
|
||||||
|
wearLabel.isGone = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status.apply {
|
||||||
|
val sb = StringBuilder()
|
||||||
|
if (item.showDebug) {
|
||||||
|
sb.append("--- Debug ---")
|
||||||
|
sb.append("\n").append(device.rawDataHex)
|
||||||
|
}
|
||||||
|
text = sb
|
||||||
|
isGone = !item.showDebug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Item(
|
||||||
|
override val now: Instant,
|
||||||
|
override val device: SinglePodDevice,
|
||||||
|
override val showDebug: Boolean,
|
||||||
|
override val isMainPod: Boolean,
|
||||||
|
) : PodDeviceVH.Item
|
||||||
|
}
|
||||||
@@ -6,8 +6,7 @@ import android.widget.RemoteViews
|
|||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import eu.darken.capod.R
|
import eu.darken.capod.R
|
||||||
import eu.darken.capod.pods.core.*
|
import eu.darken.capod.pods.core.*
|
||||||
import eu.darken.capod.pods.core.apple.BasicSingleApplePods
|
import eu.darken.capod.pods.core.apple.DualAirPods
|
||||||
import eu.darken.capod.pods.core.apple.DualApplePods
|
|
||||||
import eu.darken.capod.pods.core.apple.SingleApplePods
|
import eu.darken.capod.pods.core.apple.SingleApplePods
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@@ -17,13 +16,12 @@ class MonitorNotificationViewFactory @Inject constructor(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
fun createContentView(device: PodDevice): RemoteViews = when (device) {
|
fun createContentView(device: PodDevice): RemoteViews = when (device) {
|
||||||
is DualApplePods -> createDualApplePods(device)
|
is DualAirPods -> createDualApplePods(device)
|
||||||
is SingleApplePods -> createSingleApplePods(device)
|
is SingleApplePods -> createSingleApplePods(device)
|
||||||
is BasicSingleApplePods -> createSingleBasicApplePods(device)
|
|
||||||
else -> createUnknownDevice(device)
|
else -> createUnknownDevice(device)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createDualApplePods(device: DualApplePods): RemoteViews = RemoteViews(
|
private fun createDualApplePods(device: DualAirPods): RemoteViews = RemoteViews(
|
||||||
context.packageName,
|
context.packageName,
|
||||||
R.layout.monitor_notification_dual_pods_small
|
R.layout.monitor_notification_dual_pods_small
|
||||||
).apply {
|
).apply {
|
||||||
@@ -52,19 +50,12 @@ class MonitorNotificationViewFactory @Inject constructor(
|
|||||||
setTextViewText(R.id.headphones_label, getLabel(context))
|
setTextViewText(R.id.headphones_label, getLabel(context))
|
||||||
setImageViewResource(R.id.headphones_battery_icon, getBatteryDrawable(batteryHeadsetPercent))
|
setImageViewResource(R.id.headphones_battery_icon, getBatteryDrawable(batteryHeadsetPercent))
|
||||||
setTextViewText(R.id.headphones_battery_label, getBatteryLevelHeadset(context))
|
setTextViewText(R.id.headphones_battery_label, getBatteryLevelHeadset(context))
|
||||||
setViewVisibility(R.id.headphones_charging, if (isHeadsetBeingCharged) View.VISIBLE else View.GONE)
|
if (this is HasEarDetection) {
|
||||||
setViewVisibility(R.id.headphones_worn, if (isHeadphonesBeingWorn) View.VISIBLE else View.GONE)
|
setViewVisibility(R.id.headphones_worn, if (isBeingWorn) View.VISIBLE else View.GONE)
|
||||||
}
|
}
|
||||||
}
|
if (this is HasChargeDetectionDual) {
|
||||||
|
setViewVisibility(R.id.headphones_charging, if (isHeadsetBeingCharged) View.VISIBLE else View.GONE)
|
||||||
private fun createSingleBasicApplePods(device: BasicSingleApplePods): RemoteViews = RemoteViews(
|
}
|
||||||
context.packageName,
|
|
||||||
R.layout.monitor_notification_single_pods_basic_small
|
|
||||||
).apply {
|
|
||||||
device.apply {
|
|
||||||
setTextViewText(R.id.headphones_label, getLabel(context))
|
|
||||||
setImageViewResource(R.id.headphones_battery_icon, getBatteryDrawable(batteryHeadsetPercent))
|
|
||||||
setTextViewText(R.id.headphones_battery_label, getBatteryLevelHeadset(context))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
package eu.darken.capod.pods.core
|
package eu.darken.capod.pods.core
|
||||||
|
|
||||||
interface HasDualPods {
|
interface DualPodDevice : PodDevice {
|
||||||
|
|
||||||
enum class Pod {
|
enum class Pod {
|
||||||
LEFT,
|
LEFT,
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package eu.darken.capod.pods.core
|
||||||
|
|
||||||
|
interface HasChargeDetection {
|
||||||
|
|
||||||
|
val isHeadsetBeingCharged: Boolean
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package eu.darken.capod.pods.core
|
||||||
|
|
||||||
|
interface HasChargeDetectionDual : HasChargeDetection {
|
||||||
|
|
||||||
|
val isLeftPodCharging: Boolean
|
||||||
|
|
||||||
|
val isRightPodCharging: Boolean
|
||||||
|
|
||||||
|
val isEitherPodCharging: Boolean
|
||||||
|
get() = isLeftPodCharging || isRightPodCharging
|
||||||
|
|
||||||
|
override val isHeadsetBeingCharged: Boolean
|
||||||
|
get() = isEitherPodCharging
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package eu.darken.capod.pods.core
|
||||||
|
|
||||||
|
interface HasDualMicrophone {
|
||||||
|
|
||||||
|
val isLeftPodMicrophone: Boolean
|
||||||
|
|
||||||
|
val isRightPodMicrophone: Boolean
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package eu.darken.capod.pods.core
|
package eu.darken.capod.pods.core
|
||||||
|
|
||||||
interface HasEarDetection : PodDevice {
|
interface HasEarDetection {
|
||||||
|
|
||||||
val isBeingWorn: Boolean
|
val isBeingWorn: Boolean
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
package eu.darken.capod.pods.core
|
package eu.darken.capod.pods.core
|
||||||
|
|
||||||
interface HasDualEarDetection : HasEarDetection {
|
interface HasEarDetectionDual : HasEarDetection {
|
||||||
|
|
||||||
val isLeftPodInEar: Boolean
|
val isLeftPodInEar: Boolean
|
||||||
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package eu.darken.capod.pods.core
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.annotation.ColorRes
|
||||||
|
|
||||||
|
interface HasPodStyle {
|
||||||
|
|
||||||
|
val podStyle: PodStyle
|
||||||
|
|
||||||
|
interface PodStyle {
|
||||||
|
fun getLabel(context: Context): String
|
||||||
|
|
||||||
|
@ColorRes
|
||||||
|
fun getColor(context: Context): Int
|
||||||
|
|
||||||
|
val identifier: String
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package eu.darken.capod.pods.core
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
|
||||||
|
interface HasStateDetection {
|
||||||
|
|
||||||
|
val state: State
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
fun getLabel(context: Context): String
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -103,6 +103,9 @@ interface PodDevice {
|
|||||||
@Json(name = "fakes.tws.i99999") TWS_I99999(
|
@Json(name = "fakes.tws.i99999") TWS_I99999(
|
||||||
"TWS i99999"
|
"TWS i99999"
|
||||||
),
|
),
|
||||||
|
@Json(name = "fakes.varunr.airpodspro") VARUNR_AIRPODS_PRO(
|
||||||
|
"Varunr AirPods Pro"
|
||||||
|
),
|
||||||
@Json(name = "unknown") UNKNOWN(
|
@Json(name = "unknown") UNKNOWN(
|
||||||
"Unknown"
|
"Unknown"
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ import java.time.Duration
|
|||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
fun HasDualPods.getBatteryLevelLeftPod(context: Context): String =
|
fun DualPodDevice.getBatteryLevelLeftPod(context: Context): String =
|
||||||
batteryLeftPodPercent?.let { "${(it * 100).roundToInt()}%" }
|
batteryLeftPodPercent?.let { "${(it * 100).roundToInt()}%" }
|
||||||
?: context.getString(R.string.general_value_not_available_label)
|
?: context.getString(R.string.general_value_not_available_label)
|
||||||
|
|
||||||
fun HasDualPods.getBatteryLevelRightPod(context: Context): String =
|
fun DualPodDevice.getBatteryLevelRightPod(context: Context): String =
|
||||||
batteryRightPodPercent?.let { "${(it * 100).roundToInt()}%" }
|
batteryRightPodPercent?.let { "${(it * 100).roundToInt()}%" }
|
||||||
?: context.getString(R.string.general_value_not_available_label)
|
?: context.getString(R.string.general_value_not_available_label)
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ fun HasCase.getBatteryLevelCase(context: Context): String =
|
|||||||
batteryCasePercent?.let { "${(it * 100).roundToInt()}%" }
|
batteryCasePercent?.let { "${(it * 100).roundToInt()}%" }
|
||||||
?: context.getString(R.string.general_value_not_available_label)
|
?: context.getString(R.string.general_value_not_available_label)
|
||||||
|
|
||||||
fun HasSinglePod.getBatteryLevelHeadset(context: Context): String =
|
fun SinglePodDevice.getBatteryLevelHeadset(context: Context): String =
|
||||||
batteryHeadsetPercent?.let { "${(it * 100).roundToInt()}%" }
|
batteryHeadsetPercent?.let { "${(it * 100).roundToInt()}%" }
|
||||||
?: context.getString(R.string.general_value_not_available_label)
|
?: context.getString(R.string.general_value_not_available_label)
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
package eu.darken.capod.pods.core
|
package eu.darken.capod.pods.core
|
||||||
|
|
||||||
interface HasSinglePod {
|
interface SinglePodDevice : PodDevice {
|
||||||
|
|
||||||
val batteryHeadsetPercent: Float?
|
val batteryHeadsetPercent: Float?
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,7 @@ import eu.darken.capod.common.debug.logging.asLog
|
|||||||
import eu.darken.capod.common.debug.logging.log
|
import eu.darken.capod.common.debug.logging.log
|
||||||
import eu.darken.capod.common.debug.logging.logTag
|
import eu.darken.capod.common.debug.logging.logTag
|
||||||
import eu.darken.capod.pods.core.PodDevice
|
import eu.darken.capod.pods.core.PodDevice
|
||||||
|
import eu.darken.capod.pods.core.apple.misc.UnknownAppleDevice
|
||||||
import eu.darken.capod.pods.core.apple.protocol.ContinuityProtocol
|
import eu.darken.capod.pods.core.apple.protocol.ContinuityProtocol
|
||||||
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ import dagger.hilt.components.SingletonComponent
|
|||||||
import dagger.multibindings.IntoSet
|
import dagger.multibindings.IntoSet
|
||||||
import eu.darken.capod.pods.core.apple.airpods.*
|
import eu.darken.capod.pods.core.apple.airpods.*
|
||||||
import eu.darken.capod.pods.core.apple.beats.*
|
import eu.darken.capod.pods.core.apple.beats.*
|
||||||
import eu.darken.capod.pods.core.apple.fakes.Twsi99999
|
import eu.darken.capod.pods.core.apple.misc.Twsi99999
|
||||||
|
import eu.darken.capod.pods.core.apple.misc.VarunrAirPodsPro
|
||||||
|
|
||||||
@InstallIn(SingletonComponent::class)
|
@InstallIn(SingletonComponent::class)
|
||||||
@Module
|
@Module
|
||||||
@@ -28,4 +29,6 @@ abstract class AppleFactoryModule {
|
|||||||
@Binds @IntoSet abstract fun powerBeatsPro(factory: PowerBeatsPro.Factory): ApplePodsFactory<out ApplePods>
|
@Binds @IntoSet abstract fun powerBeatsPro(factory: PowerBeatsPro.Factory): ApplePodsFactory<out ApplePods>
|
||||||
|
|
||||||
@Binds @IntoSet abstract fun fakesTwsi999999(factory: Twsi99999.Factory): ApplePodsFactory<out ApplePods>
|
@Binds @IntoSet abstract fun fakesTwsi999999(factory: Twsi99999.Factory): ApplePodsFactory<out ApplePods>
|
||||||
|
@Binds @IntoSet
|
||||||
|
abstract fun fakesVarunrAirPodsPro(factory: VarunrAirPodsPro.Factory): ApplePodsFactory<out ApplePods>
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,9 @@ import eu.darken.capod.common.debug.logging.Logging.Priority.VERBOSE
|
|||||||
import eu.darken.capod.common.debug.logging.log
|
import eu.darken.capod.common.debug.logging.log
|
||||||
import eu.darken.capod.common.lowerNibble
|
import eu.darken.capod.common.lowerNibble
|
||||||
import eu.darken.capod.common.upperNibble
|
import eu.darken.capod.common.upperNibble
|
||||||
|
import eu.darken.capod.pods.core.HasCase
|
||||||
import eu.darken.capod.pods.core.PodDevice
|
import eu.darken.capod.pods.core.PodDevice
|
||||||
|
import eu.darken.capod.pods.core.apple.airpods.AirPodsPro
|
||||||
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
@@ -21,7 +23,7 @@ abstract class ApplePodsFactory<PodType : ApplePods>(private val tag: String) {
|
|||||||
val deviceColor: UByte,
|
val deviceColor: UByte,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun ProximityPairing.Message.getApplePodsMarkings(): Markings = Markings(
|
private fun ProximityPairing.Message.getApplePodsMarkings(): Markings = Markings(
|
||||||
vendor = ProximityPairing.CONTINUITY_PROTOCOL_MESSAGE_TYPE_PROXIMITY_PAIRING,
|
vendor = ProximityPairing.CONTINUITY_PROTOCOL_MESSAGE_TYPE_PROXIMITY_PAIRING,
|
||||||
length = ProximityPairing.PAIRING_MESSAGE_LENGTH.toUByte(),
|
length = ProximityPairing.PAIRING_MESSAGE_LENGTH.toUByte(),
|
||||||
device = (((data[1].toInt() and 255) shl 8) or (data[2].toInt() and 255)).toUShort(),
|
device = (((data[1].toInt() and 255) shl 8) or (data[2].toInt() and 255)).toUShort(),
|
||||||
@@ -70,6 +72,22 @@ abstract class ApplePodsFactory<PodType : ApplePods>(private val tag: String) {
|
|||||||
|
|
||||||
internal val knownDevices = mutableMapOf<PodDevice.Id, KnownDevice>()
|
internal val knownDevices = mutableMapOf<PodDevice.Id, KnownDevice>()
|
||||||
|
|
||||||
|
|
||||||
|
fun KnownDevice.getLatestCaseBattery(): Float? = history
|
||||||
|
.filterIsInstance<HasCase>()
|
||||||
|
.mapNotNull { it.batteryCasePercent }
|
||||||
|
.lastOrNull()
|
||||||
|
|
||||||
|
fun KnownDevice.getLatestCaseLidState(basic: DualAirPods): DualAirPods.LidState? {
|
||||||
|
val definitive = setOf(DualAirPods.LidState.OPEN, DualAirPods.LidState.CLOSED)
|
||||||
|
if (definitive.contains(basic.caseLidState)) return null
|
||||||
|
|
||||||
|
return history
|
||||||
|
.filterIsInstance<AirPodsPro>()
|
||||||
|
.lastOrNull { it.caseLidState != DualAirPods.LidState.NOT_IN_CASE }
|
||||||
|
?.caseLidState
|
||||||
|
}
|
||||||
|
|
||||||
internal open fun searchHistory(current: PodType): KnownDevice? {
|
internal open fun searchHistory(current: PodType): KnownDevice? {
|
||||||
val scanResult = current.scanResult
|
val scanResult = current.scanResult
|
||||||
val message = current.proximityMessage
|
val message = current.proximityMessage
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
package eu.darken.capod.pods.core.apple
|
|
||||||
|
|
||||||
import eu.darken.capod.common.debug.logging.log
|
|
||||||
import eu.darken.capod.common.lowerNibble
|
|
||||||
import eu.darken.capod.pods.core.HasSinglePod
|
|
||||||
|
|
||||||
interface BasicSingleApplePods : ApplePods, HasSinglePod {
|
|
||||||
|
|
||||||
override val batteryHeadsetPercent: Float?
|
|
||||||
get() = when (val value = rawPodsBattery.lowerNibble.toInt()) {
|
|
||||||
15 -> null
|
|
||||||
else -> if (value > 10) {
|
|
||||||
log { "Left pod: Above 100% battery: $value" }
|
|
||||||
1.0f
|
|
||||||
} else {
|
|
||||||
(value / 10f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
package eu.darken.capod.pods.core.apple
|
|
||||||
|
|
||||||
abstract class BasicSingleApplePodsFactory(private val tag: String) : ApplePodsFactory<BasicSingleApplePods>(tag)
|
|
||||||
+12
-36
@@ -7,12 +7,11 @@ import eu.darken.capod.common.debug.logging.log
|
|||||||
import eu.darken.capod.common.isBitSet
|
import eu.darken.capod.common.isBitSet
|
||||||
import eu.darken.capod.common.lowerNibble
|
import eu.darken.capod.common.lowerNibble
|
||||||
import eu.darken.capod.common.upperNibble
|
import eu.darken.capod.common.upperNibble
|
||||||
import eu.darken.capod.pods.core.HasCase
|
import eu.darken.capod.pods.core.*
|
||||||
import eu.darken.capod.pods.core.HasDualEarDetection
|
import eu.darken.capod.pods.core.DualPodDevice.Pod
|
||||||
import eu.darken.capod.pods.core.HasDualPods
|
|
||||||
import eu.darken.capod.pods.core.HasDualPods.Pod
|
|
||||||
|
|
||||||
interface DualApplePods : ApplePods, HasDualPods, HasDualEarDetection, HasCase {
|
interface DualAirPods : ApplePods, HasChargeDetectionDual, DualPodDevice, HasEarDetectionDual, HasCase,
|
||||||
|
HasStateDetection, HasDualMicrophone, HasAppleColor {
|
||||||
|
|
||||||
val primaryPod: Pod
|
val primaryPod: Pod
|
||||||
get() = when (rawStatus.isBitSet(5)) {
|
get() = when (rawStatus.isBitSet(5)) {
|
||||||
@@ -86,23 +85,23 @@ interface DualApplePods : ApplePods, HasDualPods, HasDualEarDetection, HasCase {
|
|||||||
* The data flip bit is set if the left pod is primary.
|
* The data flip bit is set if the left pod is primary.
|
||||||
* For the pod that is in the case, this is flipped again though.
|
* For the pod that is in the case, this is flipped again though.
|
||||||
*/
|
*/
|
||||||
val isLeftPodMicrophone: Boolean
|
override val isLeftPodMicrophone: Boolean
|
||||||
get() = rawStatus.isBitSet(5) xor isThisPodInThecase
|
get() = rawStatus.isBitSet(5) xor isThisPodInThecase
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data flip bit is UNset if the right pod is primary.
|
* The data flip bit is UNset if the right pod is primary.
|
||||||
* For the pod that is in the case, this is flipped again though.
|
* For the pod that is in the case, this is flipped again though.
|
||||||
*/
|
*/
|
||||||
val isRightPodMicrophone: Boolean
|
override val isRightPodMicrophone: Boolean
|
||||||
get() = !rawStatus.isBitSet(5) xor isThisPodInThecase
|
get() = !rawStatus.isBitSet(5) xor isThisPodInThecase
|
||||||
|
|
||||||
val isLeftPodCharging: Boolean
|
override val isLeftPodCharging: Boolean
|
||||||
get() = when (areValuesFlipped) {
|
get() = when (areValuesFlipped) {
|
||||||
false -> rawFlags.isBitSet(0)
|
false -> rawFlags.isBitSet(0)
|
||||||
true -> rawFlags.isBitSet(1)
|
true -> rawFlags.isBitSet(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
val isRightPodCharging: Boolean
|
override val isRightPodCharging: Boolean
|
||||||
get() = when (areValuesFlipped) {
|
get() = when (areValuesFlipped) {
|
||||||
false -> rawFlags.isBitSet(1)
|
false -> rawFlags.isBitSet(1)
|
||||||
true -> rawFlags.isBitSet(0)
|
true -> rawFlags.isBitSet(0)
|
||||||
@@ -143,35 +142,10 @@ interface DualApplePods : ApplePods, HasDualPods, HasDualEarDetection, HasCase {
|
|||||||
UNKNOWN(0xFF..0xFF);
|
UNKNOWN(0xFF..0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
val deviceColor: DeviceColor
|
override val state: ConnectionState
|
||||||
get() = DeviceColor.values().firstOrNull { it.raw == rawDeviceColor } ?: DeviceColor.UNKNOWN
|
|
||||||
|
|
||||||
enum class DeviceColor(val raw: UByte?) {
|
|
||||||
|
|
||||||
WHITE(0x00),
|
|
||||||
BLACK(0x01),
|
|
||||||
RED(0x02),
|
|
||||||
BLUE(0x03),
|
|
||||||
PINK(0x04),
|
|
||||||
GRAY(0x05),
|
|
||||||
SILVER(0x06),
|
|
||||||
GOLD(0x07),
|
|
||||||
ROSE_GOLD(0x08),
|
|
||||||
SPACE_GRAY(0x09),
|
|
||||||
DARK_BLUE(0x0a),
|
|
||||||
LIGHT_BLUE(0x0b),
|
|
||||||
YELLOW(0x0c),
|
|
||||||
UNKNOWN(null);
|
|
||||||
|
|
||||||
constructor(raw: Int) : this(raw.toUByte())
|
|
||||||
}
|
|
||||||
|
|
||||||
val connectionState: ConnectionState
|
|
||||||
get() = ConnectionState.values().firstOrNull { rawSuffix == it.raw } ?: ConnectionState.UNKNOWN
|
get() = ConnectionState.values().firstOrNull { rawSuffix == it.raw } ?: ConnectionState.UNKNOWN
|
||||||
|
|
||||||
fun getConnectionStateLabel(context: Context): String = context.getString(connectionState.labelRes)
|
enum class ConnectionState(val raw: UByte?, @StringRes val labelRes: Int) : HasStateDetection.State {
|
||||||
|
|
||||||
enum class ConnectionState(val raw: UByte?, @StringRes val labelRes: Int) {
|
|
||||||
DISCONNECTED(0x00, R.string.pods_connection_state_disconnected_label),
|
DISCONNECTED(0x00, R.string.pods_connection_state_disconnected_label),
|
||||||
IDLE(0x04, R.string.pods_connection_state_idle_label),
|
IDLE(0x04, R.string.pods_connection_state_idle_label),
|
||||||
MUSIC(0x05, R.string.pods_connection_state_music_label),
|
MUSIC(0x05, R.string.pods_connection_state_music_label),
|
||||||
@@ -180,6 +154,8 @@ interface DualApplePods : ApplePods, HasDualPods, HasDualEarDetection, HasCase {
|
|||||||
HANGING_UP(0x09, R.string.pods_connection_state_hanging_up_label),
|
HANGING_UP(0x09, R.string.pods_connection_state_hanging_up_label),
|
||||||
UNKNOWN(null, R.string.pods_connection_state_unknown_label);
|
UNKNOWN(null, R.string.pods_connection_state_unknown_label);
|
||||||
|
|
||||||
|
override fun getLabel(context: Context): String = context.getString(labelRes)
|
||||||
|
|
||||||
constructor(raw: Int, @StringRes labelRes: Int) : this(raw.toUByte(), labelRes)
|
constructor(raw: Int, @StringRes labelRes: Int) : this(raw.toUByte(), labelRes)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3,18 +3,17 @@ package eu.darken.capod.pods.core.apple
|
|||||||
import eu.darken.capod.common.debug.logging.Logging.Priority.DEBUG
|
import eu.darken.capod.common.debug.logging.Logging.Priority.DEBUG
|
||||||
import eu.darken.capod.common.debug.logging.log
|
import eu.darken.capod.common.debug.logging.log
|
||||||
import eu.darken.capod.pods.core.PodDevice
|
import eu.darken.capod.pods.core.PodDevice
|
||||||
import eu.darken.capod.pods.core.apple.airpods.AirPodsPro
|
|
||||||
|
|
||||||
abstract class DualApplePodsFactory(private val tag: String) : ApplePodsFactory<DualApplePods>(tag) {
|
abstract class DualApplePodsFactory(private val tag: String) : ApplePodsFactory<DualAirPods>(tag) {
|
||||||
|
|
||||||
fun DualApplePods.getCaseMatchMarkings() = SplitPodsMarkings(
|
fun DualAirPods.getCaseMatchMarkings() = SplitPodsMarkings(
|
||||||
leftPodBattery = batteryLeftPodPercent,
|
leftPodBattery = batteryLeftPodPercent,
|
||||||
rightPodBattery = batteryRightPodPercent,
|
rightPodBattery = batteryRightPodPercent,
|
||||||
microPhoneLeft = isLeftPodMicrophone,
|
microPhoneLeft = isLeftPodMicrophone,
|
||||||
microPhoneRight = isRightPodMicrophone,
|
microPhoneRight = isRightPodMicrophone,
|
||||||
chargingLeft = isLeftPodCharging,
|
chargingLeft = isLeftPodCharging,
|
||||||
chargingRight = isRightPodCharging,
|
chargingRight = isRightPodCharging,
|
||||||
color = deviceColor,
|
color = rawDeviceColor,
|
||||||
model = model
|
model = model
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,36 +27,21 @@ abstract class DualApplePodsFactory(private val tag: String) : ApplePodsFactory<
|
|||||||
val microPhoneRight: Boolean,
|
val microPhoneRight: Boolean,
|
||||||
val chargingLeft: Boolean,
|
val chargingLeft: Boolean,
|
||||||
val chargingRight: Boolean,
|
val chargingRight: Boolean,
|
||||||
val color: DualApplePods.DeviceColor,
|
val color: UByte,
|
||||||
val model: PodDevice.Model,
|
val model: PodDevice.Model,
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun Collection<KnownDevice>.findSplitPodsMatch(device: DualApplePods): Collection<KnownDevice> {
|
private fun Collection<KnownDevice>.findSplitPodsMatch(device: DualAirPods): Collection<KnownDevice> {
|
||||||
val target = device.getCaseMatchMarkings()
|
val target = device.getCaseMatchMarkings()
|
||||||
|
|
||||||
return filter { known ->
|
return filter { known ->
|
||||||
known.history
|
known.history
|
||||||
.filterIsInstance<DualApplePods>()
|
.filterIsInstance<DualAirPods>()
|
||||||
.any { it.getCaseMatchMarkings() == target }
|
.any { it.getCaseMatchMarkings() == target }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun KnownDevice.getLatestCaseBattery(): Float? = history
|
override fun searchHistory(current: DualAirPods): KnownDevice? {
|
||||||
.filterIsInstance<DualApplePods>()
|
|
||||||
.mapNotNull { it.batteryCasePercent }
|
|
||||||
.lastOrNull()
|
|
||||||
|
|
||||||
fun KnownDevice.getLatestCaseLidState(basic: DualApplePods): DualApplePods.LidState? {
|
|
||||||
val definitive = setOf(DualApplePods.LidState.OPEN, DualApplePods.LidState.CLOSED)
|
|
||||||
if (definitive.contains(basic.caseLidState)) return null
|
|
||||||
|
|
||||||
return history
|
|
||||||
.filterIsInstance<AirPodsPro>()
|
|
||||||
.lastOrNull { it.caseLidState != DualApplePods.LidState.NOT_IN_CASE }
|
|
||||||
?.caseLidState
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchHistory(current: DualApplePods): KnownDevice? {
|
|
||||||
val basicResult = super.searchHistory(current)
|
val basicResult = super.searchHistory(current)
|
||||||
|
|
||||||
val caseIgnored = knownDevices.values.findSplitPodsMatch(current)
|
val caseIgnored = knownDevices.values.findSplitPodsMatch(current)
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package eu.darken.capod.pods.core.apple
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import eu.darken.capod.pods.core.HasPodStyle
|
||||||
|
|
||||||
|
interface HasAppleColor : ApplePods, HasPodStyle {
|
||||||
|
|
||||||
|
override val podStyle: HasPodStyle.PodStyle
|
||||||
|
get() = DeviceColor.values()
|
||||||
|
.firstOrNull { it.raw == rawDeviceColor }
|
||||||
|
?: DeviceColor.UNKNOWN
|
||||||
|
|
||||||
|
enum class DeviceColor(val raw: UByte?) : HasPodStyle.PodStyle {
|
||||||
|
WHITE(0x00),
|
||||||
|
BLACK(0x01),
|
||||||
|
RED(0x02),
|
||||||
|
BLUE(0x03),
|
||||||
|
PINK(0x04),
|
||||||
|
GRAY(0x05),
|
||||||
|
SILVER(0x06),
|
||||||
|
GOLD(0x07),
|
||||||
|
ROSE_GOLD(0x08),
|
||||||
|
SPACE_GRAY(0x09),
|
||||||
|
DARK_BLUE(0x0a),
|
||||||
|
LIGHT_BLUE(0x0b),
|
||||||
|
YELLOW(0x0c),
|
||||||
|
UNKNOWN(null);
|
||||||
|
|
||||||
|
override fun getLabel(context: Context): String = this.name
|
||||||
|
|
||||||
|
override fun getColor(context: Context): Int = android.R.color.white
|
||||||
|
|
||||||
|
override val identifier: String
|
||||||
|
get() = name
|
||||||
|
|
||||||
|
constructor(raw: Int) : this(raw.toUByte())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,17 +1,22 @@
|
|||||||
package eu.darken.capod.pods.core.apple
|
package eu.darken.capod.pods.core.apple
|
||||||
|
|
||||||
import eu.darken.capod.common.isBitSet
|
import eu.darken.capod.common.debug.logging.log
|
||||||
import eu.darken.capod.pods.core.HasEarDetection
|
import eu.darken.capod.common.lowerNibble
|
||||||
import eu.darken.capod.pods.core.HasSinglePod
|
import eu.darken.capod.pods.core.SinglePodDevice
|
||||||
|
|
||||||
interface SingleApplePods : BasicSingleApplePods, HasEarDetection, HasSinglePod {
|
/**
|
||||||
|
* Devices that only present a single charge level, e.g. most Beats devices
|
||||||
|
*/
|
||||||
|
interface SingleApplePods : ApplePods, SinglePodDevice, HasAppleColor {
|
||||||
|
|
||||||
val isHeadphonesBeingWorn: Boolean
|
override val batteryHeadsetPercent: Float?
|
||||||
get() = rawStatus.isBitSet(1)
|
get() = when (val value = rawPodsBattery.lowerNibble.toInt()) {
|
||||||
|
15 -> null
|
||||||
val isHeadsetBeingCharged: Boolean
|
else -> if (value > 10) {
|
||||||
get() = rawFlags.isBitSet(0)
|
log { "Headset above 100% battery: $value" }
|
||||||
|
1.0f
|
||||||
override val isBeingWorn: Boolean
|
} else {
|
||||||
get() = isHeadphonesBeingWorn
|
(value / 10f)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ import eu.darken.capod.common.bluetooth.BleScanResult
|
|||||||
import eu.darken.capod.common.debug.logging.logTag
|
import eu.darken.capod.common.debug.logging.logTag
|
||||||
import eu.darken.capod.pods.core.PodDevice
|
import eu.darken.capod.pods.core.PodDevice
|
||||||
import eu.darken.capod.pods.core.apple.ApplePods
|
import eu.darken.capod.pods.core.apple.ApplePods
|
||||||
import eu.darken.capod.pods.core.apple.DualApplePods
|
import eu.darken.capod.pods.core.apple.DualAirPods
|
||||||
import eu.darken.capod.pods.core.apple.DualApplePodsFactory
|
import eu.darken.capod.pods.core.apple.DualApplePodsFactory
|
||||||
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
@@ -20,15 +20,15 @@ data class AirPodsGen1 constructor(
|
|||||||
override val confidence: Float = PodDevice.BASE_CONFIDENCE,
|
override val confidence: Float = PodDevice.BASE_CONFIDENCE,
|
||||||
private val rssiAverage: Int? = null,
|
private val rssiAverage: Int? = null,
|
||||||
private val cachedBatteryPercentage: Float? = null,
|
private val cachedBatteryPercentage: Float? = null,
|
||||||
private val cachedCaseState: DualApplePods.LidState? = null
|
private val cachedCaseState: DualAirPods.LidState? = null
|
||||||
) : DualApplePods {
|
) : DualAirPods {
|
||||||
|
|
||||||
override val model: PodDevice.Model = PodDevice.Model.AIRPODS_GEN1
|
override val model: PodDevice.Model = PodDevice.Model.AIRPODS_GEN1
|
||||||
|
|
||||||
override val batteryCasePercent: Float?
|
override val batteryCasePercent: Float?
|
||||||
get() = super.batteryCasePercent ?: cachedBatteryPercentage
|
get() = super.batteryCasePercent ?: cachedBatteryPercentage
|
||||||
|
|
||||||
override val caseLidState: DualApplePods.LidState
|
override val caseLidState: DualAirPods.LidState
|
||||||
get() = cachedCaseState ?: super.caseLidState
|
get() = cachedCaseState ?: super.caseLidState
|
||||||
|
|
||||||
override val rssi: Int
|
override val rssi: Int
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import eu.darken.capod.common.bluetooth.BleScanResult
|
|||||||
import eu.darken.capod.common.debug.logging.logTag
|
import eu.darken.capod.common.debug.logging.logTag
|
||||||
import eu.darken.capod.pods.core.PodDevice
|
import eu.darken.capod.pods.core.PodDevice
|
||||||
import eu.darken.capod.pods.core.apple.ApplePods
|
import eu.darken.capod.pods.core.apple.ApplePods
|
||||||
import eu.darken.capod.pods.core.apple.DualApplePods
|
import eu.darken.capod.pods.core.apple.DualAirPods
|
||||||
import eu.darken.capod.pods.core.apple.DualApplePodsFactory
|
import eu.darken.capod.pods.core.apple.DualApplePodsFactory
|
||||||
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
@@ -20,15 +20,15 @@ data class AirPodsGen2 constructor(
|
|||||||
override val confidence: Float = PodDevice.BASE_CONFIDENCE,
|
override val confidence: Float = PodDevice.BASE_CONFIDENCE,
|
||||||
private val rssiAverage: Int? = null,
|
private val rssiAverage: Int? = null,
|
||||||
private val cachedBatteryPercentage: Float? = null,
|
private val cachedBatteryPercentage: Float? = null,
|
||||||
private val cachedCaseState: DualApplePods.LidState? = null
|
private val cachedCaseState: DualAirPods.LidState? = null
|
||||||
) : DualApplePods {
|
) : DualAirPods {
|
||||||
|
|
||||||
override val model: PodDevice.Model = PodDevice.Model.AIRPODS_GEN2
|
override val model: PodDevice.Model = PodDevice.Model.AIRPODS_GEN2
|
||||||
|
|
||||||
override val batteryCasePercent: Float?
|
override val batteryCasePercent: Float?
|
||||||
get() = super.batteryCasePercent ?: cachedBatteryPercentage
|
get() = super.batteryCasePercent ?: cachedBatteryPercentage
|
||||||
|
|
||||||
override val caseLidState: DualApplePods.LidState
|
override val caseLidState: DualAirPods.LidState
|
||||||
get() = cachedCaseState ?: super.caseLidState
|
get() = cachedCaseState ?: super.caseLidState
|
||||||
|
|
||||||
override val rssi: Int
|
override val rssi: Int
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import eu.darken.capod.common.bluetooth.BleScanResult
|
|||||||
import eu.darken.capod.common.debug.logging.logTag
|
import eu.darken.capod.common.debug.logging.logTag
|
||||||
import eu.darken.capod.pods.core.PodDevice
|
import eu.darken.capod.pods.core.PodDevice
|
||||||
import eu.darken.capod.pods.core.apple.ApplePods
|
import eu.darken.capod.pods.core.apple.ApplePods
|
||||||
import eu.darken.capod.pods.core.apple.DualApplePods
|
import eu.darken.capod.pods.core.apple.DualAirPods
|
||||||
import eu.darken.capod.pods.core.apple.DualApplePodsFactory
|
import eu.darken.capod.pods.core.apple.DualApplePodsFactory
|
||||||
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
@@ -20,14 +20,14 @@ data class AirPodsGen3 constructor(
|
|||||||
override val confidence: Float = PodDevice.BASE_CONFIDENCE,
|
override val confidence: Float = PodDevice.BASE_CONFIDENCE,
|
||||||
private val rssiAverage: Int? = null,
|
private val rssiAverage: Int? = null,
|
||||||
private val cachedBatteryPercentage: Float? = null,
|
private val cachedBatteryPercentage: Float? = null,
|
||||||
private val cachedCaseState: DualApplePods.LidState? = null
|
private val cachedCaseState: DualAirPods.LidState? = null
|
||||||
) : DualApplePods {
|
) : DualAirPods {
|
||||||
override val model: PodDevice.Model = PodDevice.Model.AIRPODS_GEN3
|
override val model: PodDevice.Model = PodDevice.Model.AIRPODS_GEN3
|
||||||
|
|
||||||
override val batteryCasePercent: Float?
|
override val batteryCasePercent: Float?
|
||||||
get() = super.batteryCasePercent ?: cachedBatteryPercentage
|
get() = super.batteryCasePercent ?: cachedBatteryPercentage
|
||||||
|
|
||||||
override val caseLidState: DualApplePods.LidState
|
override val caseLidState: DualAirPods.LidState
|
||||||
get() = cachedCaseState ?: super.caseLidState
|
get() = cachedCaseState ?: super.caseLidState
|
||||||
|
|
||||||
override val rssi: Int
|
override val rssi: Int
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package eu.darken.capod.pods.core.apple.airpods
|
|||||||
|
|
||||||
import eu.darken.capod.common.bluetooth.BleScanResult
|
import eu.darken.capod.common.bluetooth.BleScanResult
|
||||||
import eu.darken.capod.common.debug.logging.logTag
|
import eu.darken.capod.common.debug.logging.logTag
|
||||||
|
import eu.darken.capod.common.isBitSet
|
||||||
|
import eu.darken.capod.pods.core.HasEarDetection
|
||||||
import eu.darken.capod.pods.core.PodDevice
|
import eu.darken.capod.pods.core.PodDevice
|
||||||
import eu.darken.capod.pods.core.apple.ApplePods
|
import eu.darken.capod.pods.core.apple.ApplePods
|
||||||
import eu.darken.capod.pods.core.apple.SingleApplePods
|
import eu.darken.capod.pods.core.apple.SingleApplePods
|
||||||
@@ -19,13 +21,22 @@ data class AirPodsMax(
|
|||||||
override val proximityMessage: ProximityPairing.Message,
|
override val proximityMessage: ProximityPairing.Message,
|
||||||
override val confidence: Float = PodDevice.BASE_CONFIDENCE,
|
override val confidence: Float = PodDevice.BASE_CONFIDENCE,
|
||||||
private val rssiAverage: Int? = null,
|
private val rssiAverage: Int? = null,
|
||||||
) : SingleApplePods {
|
) : SingleApplePods, HasEarDetection {
|
||||||
|
|
||||||
override val model: PodDevice.Model = PodDevice.Model.AIRPODS_MAX
|
override val model: PodDevice.Model = PodDevice.Model.AIRPODS_MAX
|
||||||
|
|
||||||
override val rssi: Int
|
override val rssi: Int
|
||||||
get() = rssiAverage ?: super.rssi
|
get() = rssiAverage ?: super.rssi
|
||||||
|
|
||||||
|
val isHeadphonesBeingWorn: Boolean
|
||||||
|
get() = rawStatus.isBitSet(1)
|
||||||
|
|
||||||
|
val isHeadsetBeingCharged: Boolean
|
||||||
|
get() = rawFlags.isBitSet(0)
|
||||||
|
|
||||||
|
override val isBeingWorn: Boolean
|
||||||
|
get() = isHeadphonesBeingWorn
|
||||||
|
|
||||||
class Factory @Inject constructor() : SingleApplePodsFactory(TAG) {
|
class Factory @Inject constructor() : SingleApplePodsFactory(TAG) {
|
||||||
|
|
||||||
override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run {
|
override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run {
|
||||||
@@ -49,7 +60,6 @@ data class AirPodsMax(
|
|||||||
rssiAverage = result.averageRssi(basic.rssi),
|
rssiAverage = result.averageRssi(basic.rssi),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import eu.darken.capod.common.bluetooth.BleScanResult
|
|||||||
import eu.darken.capod.common.debug.logging.logTag
|
import eu.darken.capod.common.debug.logging.logTag
|
||||||
import eu.darken.capod.pods.core.PodDevice
|
import eu.darken.capod.pods.core.PodDevice
|
||||||
import eu.darken.capod.pods.core.apple.ApplePods
|
import eu.darken.capod.pods.core.apple.ApplePods
|
||||||
import eu.darken.capod.pods.core.apple.DualApplePods
|
import eu.darken.capod.pods.core.apple.DualAirPods
|
||||||
import eu.darken.capod.pods.core.apple.DualApplePods.LidState
|
import eu.darken.capod.pods.core.apple.DualAirPods.LidState
|
||||||
import eu.darken.capod.pods.core.apple.DualApplePodsFactory
|
import eu.darken.capod.pods.core.apple.DualApplePodsFactory
|
||||||
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
@@ -22,7 +22,7 @@ data class AirPodsPro(
|
|||||||
private val rssiAverage: Int? = null,
|
private val rssiAverage: Int? = null,
|
||||||
private val cachedBatteryPercentage: Float? = null,
|
private val cachedBatteryPercentage: Float? = null,
|
||||||
private val cachedCaseState: LidState? = null
|
private val cachedCaseState: LidState? = null
|
||||||
) : DualApplePods {
|
) : DualAirPods {
|
||||||
|
|
||||||
override val model: PodDevice.Model = PodDevice.Model.AIRPODS_PRO
|
override val model: PodDevice.Model = PodDevice.Model.AIRPODS_PRO
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import eu.darken.capod.common.bluetooth.BleScanResult
|
|||||||
import eu.darken.capod.common.debug.logging.logTag
|
import eu.darken.capod.common.debug.logging.logTag
|
||||||
import eu.darken.capod.pods.core.PodDevice
|
import eu.darken.capod.pods.core.PodDevice
|
||||||
import eu.darken.capod.pods.core.apple.ApplePods
|
import eu.darken.capod.pods.core.apple.ApplePods
|
||||||
import eu.darken.capod.pods.core.apple.BasicSingleApplePods
|
import eu.darken.capod.pods.core.apple.SingleApplePods
|
||||||
import eu.darken.capod.pods.core.apple.BasicSingleApplePodsFactory
|
import eu.darken.capod.pods.core.apple.SingleApplePodsFactory
|
||||||
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -19,14 +19,14 @@ data class BeatsFlex(
|
|||||||
override val proximityMessage: ProximityPairing.Message,
|
override val proximityMessage: ProximityPairing.Message,
|
||||||
override val confidence: Float = PodDevice.BASE_CONFIDENCE,
|
override val confidence: Float = PodDevice.BASE_CONFIDENCE,
|
||||||
private val rssiAverage: Int? = null,
|
private val rssiAverage: Int? = null,
|
||||||
) : BasicSingleApplePods {
|
) : SingleApplePods {
|
||||||
|
|
||||||
override val model: PodDevice.Model = PodDevice.Model.BEATS_FLEX
|
override val model: PodDevice.Model = PodDevice.Model.BEATS_FLEX
|
||||||
|
|
||||||
override val rssi: Int
|
override val rssi: Int
|
||||||
get() = rssiAverage ?: super.rssi
|
get() = rssiAverage ?: super.rssi
|
||||||
|
|
||||||
class Factory @Inject constructor() : BasicSingleApplePodsFactory(TAG) {
|
class Factory @Inject constructor() : SingleApplePodsFactory(TAG) {
|
||||||
|
|
||||||
override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run {
|
override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run {
|
||||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import eu.darken.capod.common.bluetooth.BleScanResult
|
|||||||
import eu.darken.capod.common.debug.logging.logTag
|
import eu.darken.capod.common.debug.logging.logTag
|
||||||
import eu.darken.capod.pods.core.PodDevice
|
import eu.darken.capod.pods.core.PodDevice
|
||||||
import eu.darken.capod.pods.core.apple.ApplePods
|
import eu.darken.capod.pods.core.apple.ApplePods
|
||||||
import eu.darken.capod.pods.core.apple.BasicSingleApplePods
|
import eu.darken.capod.pods.core.apple.SingleApplePods
|
||||||
import eu.darken.capod.pods.core.apple.BasicSingleApplePodsFactory
|
import eu.darken.capod.pods.core.apple.SingleApplePodsFactory
|
||||||
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -19,13 +19,13 @@ data class BeatsSolo3(
|
|||||||
override val proximityMessage: ProximityPairing.Message,
|
override val proximityMessage: ProximityPairing.Message,
|
||||||
override val confidence: Float = PodDevice.BASE_CONFIDENCE,
|
override val confidence: Float = PodDevice.BASE_CONFIDENCE,
|
||||||
private val rssiAverage: Int? = null,
|
private val rssiAverage: Int? = null,
|
||||||
) : BasicSingleApplePods {
|
) : SingleApplePods {
|
||||||
|
|
||||||
override val model: PodDevice.Model = PodDevice.Model.BEATS_SOLO_3
|
override val model: PodDevice.Model = PodDevice.Model.BEATS_SOLO_3
|
||||||
override val rssi: Int
|
override val rssi: Int
|
||||||
get() = rssiAverage ?: super.rssi
|
get() = rssiAverage ?: super.rssi
|
||||||
|
|
||||||
class Factory @Inject constructor() : BasicSingleApplePodsFactory(TAG) {
|
class Factory @Inject constructor() : SingleApplePodsFactory(TAG) {
|
||||||
|
|
||||||
override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run {
|
override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run {
|
||||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import eu.darken.capod.common.bluetooth.BleScanResult
|
|||||||
import eu.darken.capod.common.debug.logging.logTag
|
import eu.darken.capod.common.debug.logging.logTag
|
||||||
import eu.darken.capod.pods.core.PodDevice
|
import eu.darken.capod.pods.core.PodDevice
|
||||||
import eu.darken.capod.pods.core.apple.ApplePods
|
import eu.darken.capod.pods.core.apple.ApplePods
|
||||||
import eu.darken.capod.pods.core.apple.BasicSingleApplePods
|
import eu.darken.capod.pods.core.apple.SingleApplePods
|
||||||
import eu.darken.capod.pods.core.apple.BasicSingleApplePodsFactory
|
import eu.darken.capod.pods.core.apple.SingleApplePodsFactory
|
||||||
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -19,11 +19,11 @@ data class BeatsStudio3(
|
|||||||
override val proximityMessage: ProximityPairing.Message,
|
override val proximityMessage: ProximityPairing.Message,
|
||||||
override val confidence: Float = PodDevice.BASE_CONFIDENCE,
|
override val confidence: Float = PodDevice.BASE_CONFIDENCE,
|
||||||
private val rssiAverage: Int? = null,
|
private val rssiAverage: Int? = null,
|
||||||
) : BasicSingleApplePods {
|
) : SingleApplePods {
|
||||||
|
|
||||||
override val model: PodDevice.Model = PodDevice.Model.BEATS_STUDIO_3
|
override val model: PodDevice.Model = PodDevice.Model.BEATS_STUDIO_3
|
||||||
|
|
||||||
class Factory @Inject constructor() : BasicSingleApplePodsFactory(TAG) {
|
class Factory @Inject constructor() : SingleApplePodsFactory(TAG) {
|
||||||
|
|
||||||
override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run {
|
override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run {
|
||||||
getModelInfo().dirty == DEVICE_CODE_DIRTY && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
getModelInfo().dirty == DEVICE_CODE_DIRTY && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||||
@@ -46,7 +46,6 @@ data class BeatsStudio3(
|
|||||||
rssiAverage = result.averageRssi(basic.rssi),
|
rssiAverage = result.averageRssi(basic.rssi),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import eu.darken.capod.common.bluetooth.BleScanResult
|
|||||||
import eu.darken.capod.common.debug.logging.logTag
|
import eu.darken.capod.common.debug.logging.logTag
|
||||||
import eu.darken.capod.pods.core.PodDevice
|
import eu.darken.capod.pods.core.PodDevice
|
||||||
import eu.darken.capod.pods.core.apple.ApplePods
|
import eu.darken.capod.pods.core.apple.ApplePods
|
||||||
import eu.darken.capod.pods.core.apple.BasicSingleApplePods
|
import eu.darken.capod.pods.core.apple.SingleApplePods
|
||||||
import eu.darken.capod.pods.core.apple.BasicSingleApplePodsFactory
|
import eu.darken.capod.pods.core.apple.SingleApplePodsFactory
|
||||||
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -19,14 +19,14 @@ data class BeatsX(
|
|||||||
override val proximityMessage: ProximityPairing.Message,
|
override val proximityMessage: ProximityPairing.Message,
|
||||||
override val confidence: Float = PodDevice.BASE_CONFIDENCE,
|
override val confidence: Float = PodDevice.BASE_CONFIDENCE,
|
||||||
private val rssiAverage: Int? = null,
|
private val rssiAverage: Int? = null,
|
||||||
) : BasicSingleApplePods {
|
) : SingleApplePods {
|
||||||
|
|
||||||
override val model: PodDevice.Model = PodDevice.Model.BEATS_X
|
override val model: PodDevice.Model = PodDevice.Model.BEATS_X
|
||||||
|
|
||||||
override val rssi: Int
|
override val rssi: Int
|
||||||
get() = rssiAverage ?: super.rssi
|
get() = rssiAverage ?: super.rssi
|
||||||
|
|
||||||
class Factory @Inject constructor() : BasicSingleApplePodsFactory(TAG) {
|
class Factory @Inject constructor() : SingleApplePodsFactory(TAG) {
|
||||||
|
|
||||||
override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run {
|
override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run {
|
||||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import eu.darken.capod.common.bluetooth.BleScanResult
|
|||||||
import eu.darken.capod.common.debug.logging.logTag
|
import eu.darken.capod.common.debug.logging.logTag
|
||||||
import eu.darken.capod.pods.core.PodDevice
|
import eu.darken.capod.pods.core.PodDevice
|
||||||
import eu.darken.capod.pods.core.apple.ApplePods
|
import eu.darken.capod.pods.core.apple.ApplePods
|
||||||
import eu.darken.capod.pods.core.apple.BasicSingleApplePods
|
import eu.darken.capod.pods.core.apple.SingleApplePods
|
||||||
import eu.darken.capod.pods.core.apple.BasicSingleApplePodsFactory
|
import eu.darken.capod.pods.core.apple.SingleApplePodsFactory
|
||||||
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -19,13 +19,14 @@ data class PowerBeats3(
|
|||||||
override val proximityMessage: ProximityPairing.Message,
|
override val proximityMessage: ProximityPairing.Message,
|
||||||
override val confidence: Float = PodDevice.BASE_CONFIDENCE,
|
override val confidence: Float = PodDevice.BASE_CONFIDENCE,
|
||||||
private val rssiAverage: Int? = null,
|
private val rssiAverage: Int? = null,
|
||||||
) : BasicSingleApplePods {
|
) : SingleApplePods {
|
||||||
|
|
||||||
override val model: PodDevice.Model = PodDevice.Model.POWERBEATS_3
|
override val model: PodDevice.Model = PodDevice.Model.POWERBEATS_3
|
||||||
|
|
||||||
override val rssi: Int
|
override val rssi: Int
|
||||||
get() = rssiAverage ?: super.rssi
|
get() = rssiAverage ?: super.rssi
|
||||||
|
|
||||||
class Factory @Inject constructor() : BasicSingleApplePodsFactory(TAG) {
|
class Factory @Inject constructor() : SingleApplePodsFactory(TAG) {
|
||||||
|
|
||||||
override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run {
|
override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run {
|
||||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import eu.darken.capod.common.bluetooth.BleScanResult
|
|||||||
import eu.darken.capod.common.debug.logging.logTag
|
import eu.darken.capod.common.debug.logging.logTag
|
||||||
import eu.darken.capod.pods.core.PodDevice
|
import eu.darken.capod.pods.core.PodDevice
|
||||||
import eu.darken.capod.pods.core.apple.ApplePods
|
import eu.darken.capod.pods.core.apple.ApplePods
|
||||||
import eu.darken.capod.pods.core.apple.DualApplePods
|
import eu.darken.capod.pods.core.apple.DualAirPods
|
||||||
import eu.darken.capod.pods.core.apple.DualApplePodsFactory
|
import eu.darken.capod.pods.core.apple.DualApplePodsFactory
|
||||||
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
@@ -20,15 +20,15 @@ data class PowerBeatsPro(
|
|||||||
override val confidence: Float = PodDevice.BASE_CONFIDENCE,
|
override val confidence: Float = PodDevice.BASE_CONFIDENCE,
|
||||||
private val rssiAverage: Int? = null,
|
private val rssiAverage: Int? = null,
|
||||||
private val cachedBatteryPercentage: Float? = null,
|
private val cachedBatteryPercentage: Float? = null,
|
||||||
private val cachedCaseState: DualApplePods.LidState? = null
|
private val cachedCaseState: DualAirPods.LidState? = null
|
||||||
) : DualApplePods {
|
) : DualAirPods {
|
||||||
|
|
||||||
override val model: PodDevice.Model = PodDevice.Model.POWERBEATS_PRO
|
override val model: PodDevice.Model = PodDevice.Model.POWERBEATS_PRO
|
||||||
|
|
||||||
override val batteryCasePercent: Float?
|
override val batteryCasePercent: Float?
|
||||||
get() = super.batteryCasePercent ?: cachedBatteryPercentage
|
get() = super.batteryCasePercent ?: cachedBatteryPercentage
|
||||||
|
|
||||||
override val caseLidState: DualApplePods.LidState
|
override val caseLidState: DualAirPods.LidState
|
||||||
get() = cachedCaseState ?: super.caseLidState
|
get() = cachedCaseState ?: super.caseLidState
|
||||||
|
|
||||||
override val rssi: Int
|
override val rssi: Int
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
package eu.darken.capod.pods.core.apple.fakes
|
|
||||||
|
|
||||||
import eu.darken.capod.common.bluetooth.BleScanResult
|
|
||||||
import eu.darken.capod.common.debug.logging.logTag
|
|
||||||
import eu.darken.capod.pods.core.PodDevice
|
|
||||||
import eu.darken.capod.pods.core.apple.ApplePods
|
|
||||||
import eu.darken.capod.pods.core.apple.DualApplePods
|
|
||||||
import eu.darken.capod.pods.core.apple.DualApplePodsFactory
|
|
||||||
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
|
||||||
import java.time.Instant
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Basically an AirPods GEN1 clone
|
|
||||||
*/
|
|
||||||
data class Twsi99999 constructor(
|
|
||||||
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 confidence: Float = PodDevice.BASE_CONFIDENCE,
|
|
||||||
private val rssiAverage: Int? = null,
|
|
||||||
private val cachedBatteryPercentage: Float? = null,
|
|
||||||
private val cachedCaseState: DualApplePods.LidState? = null
|
|
||||||
) : DualApplePods {
|
|
||||||
|
|
||||||
override val model: PodDevice.Model = PodDevice.Model.TWS_I99999
|
|
||||||
|
|
||||||
override val batteryCasePercent: Float?
|
|
||||||
get() = super.batteryCasePercent ?: cachedBatteryPercentage
|
|
||||||
|
|
||||||
override val caseLidState: DualApplePods.LidState
|
|
||||||
get() = cachedCaseState ?: super.caseLidState
|
|
||||||
|
|
||||||
override val rssi: Int
|
|
||||||
get() = rssiAverage ?: super.rssi
|
|
||||||
|
|
||||||
class Factory @Inject constructor() : DualApplePodsFactory(TAG) {
|
|
||||||
|
|
||||||
override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run {
|
|
||||||
// Official message length is 19HEX, i.e. binary 25, did they copy this wrong?
|
|
||||||
getModelInfo().full == DEVICE_CODE && length == 19
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun create(scanResult: BleScanResult, message: ProximityPairing.Message): ApplePods {
|
|
||||||
var basic = Twsi99999(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,
|
|
||||||
seenCounter = result.seenCounter,
|
|
||||||
confidence = result.confidence,
|
|
||||||
cachedBatteryPercentage = result.getLatestCaseBattery(),
|
|
||||||
rssiAverage = result.averageRssi(basic.rssi),
|
|
||||||
cachedCaseState = result.getLatestCaseLidState(basic)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val DEVICE_CODE = 0x0220.toUShort()
|
|
||||||
private val TAG = logTag("PodDevice", "Apple", "TWS", "i99999")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
package eu.darken.capod.pods.core.apple.misc
|
||||||
|
|
||||||
|
import eu.darken.capod.common.bluetooth.BleScanResult
|
||||||
|
import eu.darken.capod.common.debug.logging.log
|
||||||
|
import eu.darken.capod.common.debug.logging.logTag
|
||||||
|
import eu.darken.capod.common.isBitSet
|
||||||
|
import eu.darken.capod.common.lowerNibble
|
||||||
|
import eu.darken.capod.common.upperNibble
|
||||||
|
import eu.darken.capod.pods.core.DualPodDevice
|
||||||
|
import eu.darken.capod.pods.core.HasCase
|
||||||
|
import eu.darken.capod.pods.core.HasDualMicrophone
|
||||||
|
import eu.darken.capod.pods.core.PodDevice
|
||||||
|
import eu.darken.capod.pods.core.apple.ApplePods
|
||||||
|
import eu.darken.capod.pods.core.apple.ApplePodsFactory
|
||||||
|
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
||||||
|
import java.time.Instant
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basically an AirPods GEN1 clone
|
||||||
|
* Similar data structure but a lot of placeholder values or hardcoded values
|
||||||
|
*/
|
||||||
|
data class Twsi99999 constructor(
|
||||||
|
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 confidence: Float = PodDevice.BASE_CONFIDENCE,
|
||||||
|
private val rssiAverage: Int? = null,
|
||||||
|
private val cachedBatteryPercentage: Float? = null,
|
||||||
|
) : ApplePods, DualPodDevice, HasDualMicrophone, HasCase {
|
||||||
|
|
||||||
|
override val model: PodDevice.Model = PodDevice.Model.TWS_I99999
|
||||||
|
|
||||||
|
override val rssi: Int
|
||||||
|
get() = rssiAverage ?: super<ApplePods>.rssi
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normally values for the left pod are in the lower nibbles, if the left pod is primary (microphone)
|
||||||
|
* If the right pod is the primary, the values are flipped.
|
||||||
|
*/
|
||||||
|
val areValuesFlipped: Boolean
|
||||||
|
get() = !rawStatus.isBitSet(5)
|
||||||
|
|
||||||
|
override val batteryLeftPodPercent: Float?
|
||||||
|
get() {
|
||||||
|
val value = when (areValuesFlipped) {
|
||||||
|
true -> rawPodsBattery.upperNibble.toInt()
|
||||||
|
false -> rawPodsBattery.lowerNibble.toInt()
|
||||||
|
}
|
||||||
|
return when (value) {
|
||||||
|
15 -> null
|
||||||
|
else -> if (value > 10) {
|
||||||
|
log { "Left pod: Above 100% battery: $value" }
|
||||||
|
1.0f
|
||||||
|
} else {
|
||||||
|
(value / 10f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val batteryRightPodPercent: Float?
|
||||||
|
get() {
|
||||||
|
val value = when (areValuesFlipped) {
|
||||||
|
true -> rawPodsBattery.lowerNibble.toInt()
|
||||||
|
false -> rawPodsBattery.upperNibble.toInt()
|
||||||
|
}
|
||||||
|
return when (value) {
|
||||||
|
15 -> null
|
||||||
|
else -> if (value > 10) {
|
||||||
|
log { "Right pod: Above 100% battery: $value" }
|
||||||
|
1.0f
|
||||||
|
} else {
|
||||||
|
value / 10f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val isThisPodInThecase: Boolean
|
||||||
|
get() = rawStatus.isBitSet(6)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data flip bit is set if the left pod is primary.
|
||||||
|
* For the pod that is in the case, this is flipped again though.
|
||||||
|
*/
|
||||||
|
override val isLeftPodMicrophone: Boolean
|
||||||
|
get() = rawStatus.isBitSet(5) xor isThisPodInThecase
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data flip bit is UNset if the right pod is primary.
|
||||||
|
* For the pod that is in the case, this is flipped again though.
|
||||||
|
*/
|
||||||
|
override val isRightPodMicrophone: Boolean
|
||||||
|
get() = !rawStatus.isBitSet(5) xor isThisPodInThecase
|
||||||
|
|
||||||
|
override val batteryCasePercent: Float?
|
||||||
|
get() = when (val value = rawCaseBattery.toInt()) {
|
||||||
|
15 -> cachedBatteryPercentage
|
||||||
|
else -> if (value > 10) {
|
||||||
|
log { "Case: Above 100% battery: $value" }
|
||||||
|
1.0f
|
||||||
|
} else {
|
||||||
|
value / 10f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val isCaseCharging: Boolean
|
||||||
|
get() = rawFlags.isBitSet(2)
|
||||||
|
|
||||||
|
class Factory @Inject constructor() : ApplePodsFactory<Twsi99999>(TAG) {
|
||||||
|
|
||||||
|
override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run {
|
||||||
|
// Official message length is 19HEX, i.e. binary 25, did they copy this wrong?
|
||||||
|
getModelInfo().full == DEVICE_CODE && length == 19
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun create(scanResult: BleScanResult, message: ProximityPairing.Message): ApplePods {
|
||||||
|
var basic = Twsi99999(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,
|
||||||
|
seenCounter = result.seenCounter,
|
||||||
|
confidence = result.confidence,
|
||||||
|
cachedBatteryPercentage = result.getLatestCaseBattery(),
|
||||||
|
rssiAverage = result.averageRssi(basic.rssi),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val DEVICE_CODE = 0x0220.toUShort()
|
||||||
|
private val TAG = logTag("PodDevice", "Apple", "TWS", "i99999")
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-1
@@ -1,10 +1,12 @@
|
|||||||
package eu.darken.capod.pods.core.apple
|
package eu.darken.capod.pods.core.apple.misc
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import eu.darken.capod.R
|
import eu.darken.capod.R
|
||||||
import eu.darken.capod.common.bluetooth.BleScanResult
|
import eu.darken.capod.common.bluetooth.BleScanResult
|
||||||
import eu.darken.capod.common.debug.logging.logTag
|
import eu.darken.capod.common.debug.logging.logTag
|
||||||
import eu.darken.capod.pods.core.PodDevice
|
import eu.darken.capod.pods.core.PodDevice
|
||||||
|
import eu.darken.capod.pods.core.apple.ApplePods
|
||||||
|
import eu.darken.capod.pods.core.apple.ApplePodsFactory
|
||||||
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
package eu.darken.capod.pods.core.apple.misc
|
||||||
|
|
||||||
|
import eu.darken.capod.common.bluetooth.BleScanResult
|
||||||
|
import eu.darken.capod.common.debug.logging.log
|
||||||
|
import eu.darken.capod.common.debug.logging.logTag
|
||||||
|
import eu.darken.capod.common.isBitSet
|
||||||
|
import eu.darken.capod.common.lowerNibble
|
||||||
|
import eu.darken.capod.common.upperNibble
|
||||||
|
import eu.darken.capod.pods.core.DualPodDevice
|
||||||
|
import eu.darken.capod.pods.core.HasCase
|
||||||
|
import eu.darken.capod.pods.core.HasDualMicrophone
|
||||||
|
import eu.darken.capod.pods.core.PodDevice
|
||||||
|
import eu.darken.capod.pods.core.apple.ApplePods
|
||||||
|
import eu.darken.capod.pods.core.apple.ApplePodsFactory
|
||||||
|
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
||||||
|
import java.time.Instant
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AirPods Pro clone similar to Twsi999999.
|
||||||
|
* Shorter data structure.
|
||||||
|
*/
|
||||||
|
data class VarunrAirPodsPro constructor(
|
||||||
|
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 confidence: Float = PodDevice.BASE_CONFIDENCE,
|
||||||
|
private val rssiAverage: Int? = null,
|
||||||
|
private val cachedBatteryPercentage: Float? = null,
|
||||||
|
) : ApplePods, DualPodDevice, HasDualMicrophone, HasCase {
|
||||||
|
|
||||||
|
override val model: PodDevice.Model = PodDevice.Model.VARUNR_AIRPODS_PRO
|
||||||
|
|
||||||
|
override val rssi: Int
|
||||||
|
get() = rssiAverage ?: super<ApplePods>.rssi
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normally values for the left pod are in the lower nibbles, if the left pod is primary (microphone)
|
||||||
|
* If the right pod is the primary, the values are flipped.
|
||||||
|
*/
|
||||||
|
val areValuesFlipped: Boolean
|
||||||
|
get() = !rawStatus.isBitSet(5)
|
||||||
|
|
||||||
|
override val batteryLeftPodPercent: Float?
|
||||||
|
get() {
|
||||||
|
val value = when (areValuesFlipped) {
|
||||||
|
true -> rawPodsBattery.upperNibble.toInt()
|
||||||
|
false -> rawPodsBattery.lowerNibble.toInt()
|
||||||
|
}
|
||||||
|
return when (value) {
|
||||||
|
15 -> null
|
||||||
|
else -> if (value > 10) {
|
||||||
|
log { "Left pod: Above 100% battery: $value" }
|
||||||
|
1.0f
|
||||||
|
} else {
|
||||||
|
(value / 10f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val batteryRightPodPercent: Float?
|
||||||
|
get() {
|
||||||
|
val value = when (areValuesFlipped) {
|
||||||
|
true -> rawPodsBattery.lowerNibble.toInt()
|
||||||
|
false -> rawPodsBattery.upperNibble.toInt()
|
||||||
|
}
|
||||||
|
return when (value) {
|
||||||
|
15 -> null
|
||||||
|
else -> if (value > 10) {
|
||||||
|
log { "Right pod: Above 100% battery: $value" }
|
||||||
|
1.0f
|
||||||
|
} else {
|
||||||
|
value / 10f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val isThisPodInThecase: Boolean
|
||||||
|
get() = rawStatus.isBitSet(6)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data flip bit is set if the left pod is primary.
|
||||||
|
* For the pod that is in the case, this is flipped again though.
|
||||||
|
*/
|
||||||
|
override val isLeftPodMicrophone: Boolean
|
||||||
|
get() = rawStatus.isBitSet(5) xor isThisPodInThecase
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data flip bit is UNset if the right pod is primary.
|
||||||
|
* For the pod that is in the case, this is flipped again though.
|
||||||
|
*/
|
||||||
|
override val isRightPodMicrophone: Boolean
|
||||||
|
get() = !rawStatus.isBitSet(5) xor isThisPodInThecase
|
||||||
|
|
||||||
|
override val batteryCasePercent: Float?
|
||||||
|
get() = when (val value = rawCaseBattery.toInt()) {
|
||||||
|
15 -> cachedBatteryPercentage
|
||||||
|
else -> if (value > 10) {
|
||||||
|
log { "Case: Above 100% battery: $value" }
|
||||||
|
1.0f
|
||||||
|
} else {
|
||||||
|
value / 10f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val isCaseCharging: Boolean
|
||||||
|
get() = rawFlags.isBitSet(2)
|
||||||
|
|
||||||
|
class Factory @Inject constructor() : ApplePodsFactory<VarunrAirPodsPro>(TAG) {
|
||||||
|
|
||||||
|
override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run {
|
||||||
|
// Official message length is 19HEX, i.e. binary 25, did they copy this wrong?
|
||||||
|
getModelInfo().full == DEVICE_CODE && length == 19
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun create(scanResult: BleScanResult, message: ProximityPairing.Message): ApplePods {
|
||||||
|
var basic = VarunrAirPodsPro(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,
|
||||||
|
seenCounter = result.seenCounter,
|
||||||
|
confidence = result.confidence,
|
||||||
|
cachedBatteryPercentage = result.getLatestCaseBattery(),
|
||||||
|
rssiAverage = result.averageRssi(basic.rssi),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val DEVICE_CODE = 0x0E20.toUShort()
|
||||||
|
private val TAG = logTag("PodDevice", "Apple", "Varunr", "AirPodsPro")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,9 +8,9 @@ import eu.darken.capod.common.debug.logging.logTag
|
|||||||
import eu.darken.capod.common.flow.setupCommonEventHandlers
|
import eu.darken.capod.common.flow.setupCommonEventHandlers
|
||||||
import eu.darken.capod.main.core.GeneralSettings
|
import eu.darken.capod.main.core.GeneralSettings
|
||||||
import eu.darken.capod.monitor.core.PodMonitor
|
import eu.darken.capod.monitor.core.PodMonitor
|
||||||
import eu.darken.capod.pods.core.HasDualEarDetection
|
|
||||||
import eu.darken.capod.pods.core.HasEarDetection
|
import eu.darken.capod.pods.core.HasEarDetection
|
||||||
import eu.darken.capod.pods.core.apple.DualApplePods
|
import eu.darken.capod.pods.core.HasEarDetectionDual
|
||||||
|
import eu.darken.capod.pods.core.apple.DualAirPods
|
||||||
import eu.darken.capod.reaction.settings.ReactionSettings
|
import eu.darken.capod.reaction.settings.ReactionSettings
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -68,12 +68,12 @@ class AutoConnect @Inject constructor(
|
|||||||
val conditionFulfilled = when (condition) {
|
val conditionFulfilled = when (condition) {
|
||||||
AutoConnectCondition.WHEN_SEEN -> true
|
AutoConnectCondition.WHEN_SEEN -> true
|
||||||
AutoConnectCondition.CASE_OPEN -> when (mainDevice) {
|
AutoConnectCondition.CASE_OPEN -> when (mainDevice) {
|
||||||
is DualApplePods -> mainDevice.caseLidState == DualApplePods.LidState.OPEN
|
is DualAirPods -> mainDevice.caseLidState == DualAirPods.LidState.OPEN
|
||||||
else -> true
|
else -> true
|
||||||
}
|
}
|
||||||
AutoConnectCondition.IN_EAR -> when (mainDevice) {
|
AutoConnectCondition.IN_EAR -> when (mainDevice) {
|
||||||
is HasEarDetection -> {
|
is HasEarDetection -> {
|
||||||
if (mainDevice is HasDualEarDetection && reactionSettings.onePodMode.value) {
|
if (mainDevice is HasEarDetectionDual && reactionSettings.onePodMode.value) {
|
||||||
mainDevice.isEitherPodInEar
|
mainDevice.isEitherPodInEar
|
||||||
} else {
|
} else {
|
||||||
mainDevice.isBeingWorn
|
mainDevice.isBeingWorn
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import eu.darken.capod.common.debug.logging.logTag
|
|||||||
import eu.darken.capod.common.flow.setupCommonEventHandlers
|
import eu.darken.capod.common.flow.setupCommonEventHandlers
|
||||||
import eu.darken.capod.common.flow.withPrevious
|
import eu.darken.capod.common.flow.withPrevious
|
||||||
import eu.darken.capod.monitor.core.PodMonitor
|
import eu.darken.capod.monitor.core.PodMonitor
|
||||||
import eu.darken.capod.pods.core.HasDualEarDetection
|
|
||||||
import eu.darken.capod.pods.core.HasEarDetection
|
import eu.darken.capod.pods.core.HasEarDetection
|
||||||
|
import eu.darken.capod.pods.core.HasEarDetectionDual
|
||||||
import eu.darken.capod.reaction.settings.ReactionSettings
|
import eu.darken.capod.reaction.settings.ReactionSettings
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -48,7 +48,7 @@ class PlayPause @Inject constructor(
|
|||||||
return@onEach
|
return@onEach
|
||||||
}
|
}
|
||||||
|
|
||||||
if (previous is HasDualEarDetection && current is HasDualEarDetection && reactionSettings.onePodMode.value) {
|
if (previous is HasEarDetectionDual && current is HasEarDetectionDual && reactionSettings.onePodMode.value) {
|
||||||
log(TAG) { "Ear status changed for dual pod device in single pod mode." }
|
log(TAG) { "Ear status changed for dual pod device in single pod mode." }
|
||||||
val previousWorn = previous.isEitherPodInEar
|
val previousWorn = previous.isEitherPodInEar
|
||||||
val currentWorn = current.isEitherPodInEar
|
val currentWorn = current.isEitherPodInEar
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import eu.darken.capod.common.flow.setupCommonEventHandlers
|
|||||||
import eu.darken.capod.common.flow.withPrevious
|
import eu.darken.capod.common.flow.withPrevious
|
||||||
import eu.darken.capod.monitor.core.PodMonitor
|
import eu.darken.capod.monitor.core.PodMonitor
|
||||||
import eu.darken.capod.pods.core.PodDevice
|
import eu.darken.capod.pods.core.PodDevice
|
||||||
import eu.darken.capod.pods.core.apple.DualApplePods
|
import eu.darken.capod.pods.core.apple.DualAirPods
|
||||||
import eu.darken.capod.reaction.popup.ui.PopUpWindow
|
import eu.darken.capod.reaction.popup.ui.PopUpWindow
|
||||||
import eu.darken.capod.reaction.settings.ReactionSettings
|
import eu.darken.capod.reaction.settings.ReactionSettings
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
@@ -39,7 +39,7 @@ class PopUpReaction @Inject constructor(
|
|||||||
.withPrevious()
|
.withPrevious()
|
||||||
.setupCommonEventHandlers(TAG) { "monitor" }
|
.setupCommonEventHandlers(TAG) { "monitor" }
|
||||||
.map { (previous, current) ->
|
.map { (previous, current) ->
|
||||||
if (previous is DualApplePods? && current is DualApplePods) {
|
if (previous is DualAirPods? && current is DualAirPods) {
|
||||||
log(TAG, VERBOSE) {
|
log(TAG, VERBOSE) {
|
||||||
val prev = previous?.rawCaseLidState?.let { String.format("%02X", it.toByte()) }
|
val prev = previous?.rawCaseLidState?.let { String.format("%02X", it.toByte()) }
|
||||||
val cur = current.rawCaseLidState.let { String.format("%02X", it.toByte()) }
|
val cur = current.rawCaseLidState.let { String.format("%02X", it.toByte()) }
|
||||||
@@ -60,8 +60,8 @@ class PopUpReaction @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun tryPopWindow(current: DualApplePods) {
|
private suspend fun tryPopWindow(current: DualAirPods) {
|
||||||
if (current.caseLidState == DualApplePods.LidState.OPEN) {
|
if (current.caseLidState == DualAirPods.LidState.OPEN) {
|
||||||
log(TAG, INFO) { "Show popup" }
|
log(TAG, INFO) { "Show popup" }
|
||||||
|
|
||||||
val now = Instant.now()
|
val now = Instant.now()
|
||||||
@@ -78,9 +78,9 @@ class PopUpReaction @Inject constructor(
|
|||||||
withContext(dispatcherProvider.Main) {
|
withContext(dispatcherProvider.Main) {
|
||||||
popupWindow.show(current)
|
popupWindow.show(current)
|
||||||
}
|
}
|
||||||
} else if (current.caseLidState != DualApplePods.LidState.OPEN) {
|
} else if (current.caseLidState != DualAirPods.LidState.OPEN) {
|
||||||
when (current.caseLidState) {
|
when (current.caseLidState) {
|
||||||
DualApplePods.LidState.CLOSED -> {
|
DualAirPods.LidState.CLOSED -> {
|
||||||
log(TAG, INFO) { "Lid was actively closed, resetting cooldown." }
|
log(TAG, INFO) { "Lid was actively closed, resetting cooldown." }
|
||||||
coolDowns.remove(current.identifier)
|
coolDowns.remove(current.identifier)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,11 +10,9 @@ import dagger.hilt.android.qualifiers.ApplicationContext
|
|||||||
import eu.darken.capod.R
|
import eu.darken.capod.R
|
||||||
import eu.darken.capod.common.debug.autoreport.DebugSettings
|
import eu.darken.capod.common.debug.autoreport.DebugSettings
|
||||||
import eu.darken.capod.databinding.PopupNotificationDualPodsBinding
|
import eu.darken.capod.databinding.PopupNotificationDualPodsBinding
|
||||||
import eu.darken.capod.databinding.PopupNotificationSinglePodsBasicBinding
|
|
||||||
import eu.darken.capod.databinding.PopupNotificationSinglePodsBinding
|
import eu.darken.capod.databinding.PopupNotificationSinglePodsBinding
|
||||||
import eu.darken.capod.pods.core.*
|
import eu.darken.capod.pods.core.*
|
||||||
import eu.darken.capod.pods.core.apple.BasicSingleApplePods
|
import eu.darken.capod.pods.core.apple.DualAirPods
|
||||||
import eu.darken.capod.pods.core.apple.DualApplePods
|
|
||||||
import eu.darken.capod.pods.core.apple.SingleApplePods
|
import eu.darken.capod.pods.core.apple.SingleApplePods
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@@ -28,16 +26,13 @@ class PopUpPodViewFactory @Inject constructor(
|
|||||||
private val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
private val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||||
|
|
||||||
fun createContentView(parent: ViewGroup, device: PodDevice): View = when (device) {
|
fun createContentView(parent: ViewGroup, device: PodDevice): View = when (device) {
|
||||||
is DualApplePods -> createDualApplePods(parent, device)
|
is DualAirPods -> createDualApplePods(parent, device)
|
||||||
is SingleApplePods -> createSingleApplePods(parent, device) // Unused, has no case to trigger reaction?
|
// Unused, has no case to trigger reaction?
|
||||||
is BasicSingleApplePods -> createSingleBasicApplePods(
|
is SingleApplePods -> createSingleApplePods(parent, device)
|
||||||
parent,
|
|
||||||
device
|
|
||||||
) // Unused, has no case to trigger reaction?
|
|
||||||
else -> throw IllegalArgumentException("Unexpected device: $device")
|
else -> throw IllegalArgumentException("Unexpected device: $device")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createDualApplePods(parent: ViewGroup, device: DualApplePods): View =
|
private fun createDualApplePods(parent: ViewGroup, device: DualAirPods): View =
|
||||||
PopupNotificationDualPodsBinding.inflate(layoutInflater, parent, false).apply {
|
PopupNotificationDualPodsBinding.inflate(layoutInflater, parent, false).apply {
|
||||||
device.apply {
|
device.apply {
|
||||||
podIcon.setImageResource(iconRes)
|
podIcon.setImageResource(iconRes)
|
||||||
@@ -72,17 +67,4 @@ class PopUpPodViewFactory @Inject constructor(
|
|||||||
}
|
}
|
||||||
}.root
|
}.root
|
||||||
|
|
||||||
private fun createSingleBasicApplePods(parent: ViewGroup, device: BasicSingleApplePods): View =
|
|
||||||
PopupNotificationSinglePodsBasicBinding.inflate(layoutInflater, parent, false).apply {
|
|
||||||
device.apply {
|
|
||||||
headphonesIcon.setImageResource(iconRes)
|
|
||||||
headphonesLabel.text = getLabel(context)
|
|
||||||
signal.text = getSignalQuality(context)
|
|
||||||
signal.isInvisible = debugSettings.isDebugModeEnabled.value
|
|
||||||
|
|
||||||
headphonesBatteryIcon.setImageResource(getBatteryDrawable(batteryHeadsetPercent))
|
|
||||||
headphonesBatteryLabel.text = getBatteryLevelHeadset(context)
|
|
||||||
}
|
|
||||||
}.root
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -12,13 +12,11 @@ import dagger.hilt.android.AndroidEntryPoint
|
|||||||
import eu.darken.capod.R
|
import eu.darken.capod.R
|
||||||
import eu.darken.capod.common.uix.PreferenceFragment2
|
import eu.darken.capod.common.uix.PreferenceFragment2
|
||||||
import eu.darken.capod.common.upgrade.UpgradeRepo
|
import eu.darken.capod.common.upgrade.UpgradeRepo
|
||||||
import eu.darken.capod.common.upgrade.isPro
|
|
||||||
import eu.darken.capod.main.core.GeneralSettings
|
import eu.darken.capod.main.core.GeneralSettings
|
||||||
import eu.darken.capod.main.core.MonitorMode
|
import eu.darken.capod.main.core.MonitorMode
|
||||||
import eu.darken.capod.main.ui.settings.general.DeviceSelectionDialogFactory
|
import eu.darken.capod.main.ui.settings.general.DeviceSelectionDialogFactory
|
||||||
import eu.darken.capod.reaction.autoconnect.AutoConnectCondition
|
import eu.darken.capod.reaction.autoconnect.AutoConnectCondition
|
||||||
import eu.darken.capod.reaction.settings.ReactionSettings
|
import eu.darken.capod.reaction.settings.ReactionSettings
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@Keep
|
@Keep
|
||||||
@@ -36,6 +34,7 @@ class ReactionSettingsFragment : PreferenceFragment2() {
|
|||||||
|
|
||||||
override val preferenceFile: Int = R.xml.preferences_reactions
|
override val preferenceFile: Int = R.xml.preferences_reactions
|
||||||
|
|
||||||
|
private var isPro: Boolean = false
|
||||||
private val autoConnectConditionPref by lazy { findPreference<ListPreference>(settings.autoConnectCondition.key)!! }
|
private val autoConnectConditionPref by lazy { findPreference<ListPreference>(settings.autoConnectCondition.key)!! }
|
||||||
|
|
||||||
override fun onPreferencesCreated() {
|
override fun onPreferencesCreated() {
|
||||||
@@ -44,12 +43,11 @@ class ReactionSettingsFragment : PreferenceFragment2() {
|
|||||||
entryValues = AutoConnectCondition.values().map { settings.autoConnectCondition.rawWriter(it) as String }
|
entryValues = AutoConnectCondition.values().map { settings.autoConnectCondition.rawWriter(it) as String }
|
||||||
.toTypedArray()
|
.toTypedArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
super.onPreferencesCreated()
|
super.onPreferencesCreated()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPreferenceTreeClick(preference: Preference): Boolean {
|
override fun onPreferenceTreeClick(preference: Preference): Boolean {
|
||||||
val isPro = runBlocking { upgradeRepo.isPro() }
|
|
||||||
|
|
||||||
if (preference.key == reactionSettings.autoPlay.key && !isPro) {
|
if (preference.key == reactionSettings.autoPlay.key && !isPro) {
|
||||||
preference as CheckBoxPreference
|
preference as CheckBoxPreference
|
||||||
upgradeRepo.launchBillingFlow(requireActivity())
|
upgradeRepo.launchBillingFlow(requireActivity())
|
||||||
@@ -95,6 +93,8 @@ class ReactionSettingsFragment : PreferenceFragment2() {
|
|||||||
autoConnectConditionPref.isEnabled = it
|
autoConnectConditionPref.isEnabled = it
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vm.isPro.observe2 { isPro = true }
|
||||||
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import eu.darken.capod.common.bluetooth.BluetoothManager2
|
|||||||
import eu.darken.capod.common.coroutine.DispatcherProvider
|
import eu.darken.capod.common.coroutine.DispatcherProvider
|
||||||
import eu.darken.capod.common.debug.logging.logTag
|
import eu.darken.capod.common.debug.logging.logTag
|
||||||
import eu.darken.capod.common.uix.ViewModel3
|
import eu.darken.capod.common.uix.ViewModel3
|
||||||
|
import eu.darken.capod.common.upgrade.UpgradeRepo
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
@@ -13,10 +15,13 @@ class ReactionSettingsFragmentVM @Inject constructor(
|
|||||||
private val handle: SavedStateHandle,
|
private val handle: SavedStateHandle,
|
||||||
private val dispatcherProvider: DispatcherProvider,
|
private val dispatcherProvider: DispatcherProvider,
|
||||||
private val bluetoothManager: BluetoothManager2,
|
private val bluetoothManager: BluetoothManager2,
|
||||||
|
private val upgradeRepo: UpgradeRepo,
|
||||||
) : ViewModel3(dispatcherProvider) {
|
) : ViewModel3(dispatcherProvider) {
|
||||||
|
|
||||||
val bondedDevices = bluetoothManager.bondedDevices().toList()
|
val bondedDevices = bluetoothManager.bondedDevices().toList()
|
||||||
|
|
||||||
|
val isPro = upgradeRepo.upgradeInfo.map { it.isPro }.asLiveData2()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val TAG = logTag("Settings", "Reaction", "VM")
|
private val TAG = logTag("Settings", "Reaction", "VM")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
tools:listitem="@layout/overview_pods_apple_dual_item"
|
tools:listitem="@layout/overview_pods_dual_item"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/toolbar" />
|
app:layout_constraintTop_toBottomOf="@id/toolbar" />
|
||||||
|
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center_horizontal">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/headphones_label"
|
|
||||||
style="@style/TextAppearance.Compat.Notification.Title"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center"
|
|
||||||
tools:text="Beats Solo 3" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="8dp"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/headphones_battery_icon"
|
|
||||||
style="@style/PodInfoItemIcon"
|
|
||||||
android:src="@drawable/ic_baseline_battery_unknown_24" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/headphones_battery_label"
|
|
||||||
style="@style/TextAppearance.Compat.Notification.Title"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:layout_marginHorizontal="8dp"
|
|
||||||
tools:text="100%" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:id="@+id/card"
|
|
||||||
style="@style/MyCardView"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginVertical="8dp"
|
|
||||||
tools:context=".main.ui.MainActivity">
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:id="@+id/card_content"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/device_icon"
|
|
||||||
android:layout_width="24dp"
|
|
||||||
android:layout_height="24dp"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/name"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/name"
|
|
||||||
app:srcCompat="@drawable/ic_device_generic_headphones" />
|
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
|
||||||
android:id="@+id/name"
|
|
||||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="16dp"
|
|
||||||
android:layout_marginStart="4dp"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/last_seen"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/reception"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/device_icon"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
tools:text="Power Beats 3" />
|
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
|
||||||
android:id="@+id/last_seen"
|
|
||||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/barrier_top"
|
|
||||||
app:layout_constraintEnd_toEndOf="@id/name"
|
|
||||||
app:layout_constraintStart_toStartOf="@id/name"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/name"
|
|
||||||
tools:text="3s ago" />
|
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
|
||||||
android:id="@+id/reception"
|
|
||||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="16dp"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:gravity="center"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/name"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/reception_icon"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/name"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/name"
|
|
||||||
tools:text="Yours (RSSI -61)" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/reception_icon"
|
|
||||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
|
||||||
android:layout_width="16dp"
|
|
||||||
android:layout_height="16dp"
|
|
||||||
android:layout_marginHorizontal="16dp"
|
|
||||||
android:layout_marginStart="4dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:gravity="center"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/reception"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/reception"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/reception"
|
|
||||||
app:srcCompat="@drawable/ic_baseline_settings_input_antenna_24"
|
|
||||||
tools:text="Yours (RSSI -61)" />
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.Barrier
|
|
||||||
android:id="@+id/barrier_top"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:barrierDirection="top"
|
|
||||||
app:constraint_referenced_ids="headphones"
|
|
||||||
tools:layout_editor_absoluteY="60dp" />
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:id="@+id/headphones"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/barrier_bottom"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/barrier_top"
|
|
||||||
app:layout_constraintVertical_bias="0.0"
|
|
||||||
app:layout_goneMarginBottom="16dp">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/battery_icon"
|
|
||||||
style="@style/PodInfoItemIcon"
|
|
||||||
android:src="@drawable/ic_baseline_battery_unknown_24"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/battery_label"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/battery_label" />
|
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
|
||||||
android:id="@+id/battery_label"
|
|
||||||
style="@style/PodInfoItemText"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginTop="2dp"
|
|
||||||
android:text="@string/general_value_not_available_label"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/battery_icon"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.Barrier
|
|
||||||
android:id="@+id/barrier_bottom"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:barrierDirection="bottom"
|
|
||||||
app:constraint_referenced_ids="headphones" />
|
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
|
||||||
android:id="@+id/status"
|
|
||||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="16dp"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/barrier_bottom"
|
|
||||||
tools:text="Music Active, Case Closed" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
|
||||||
+4
-4
@@ -12,7 +12,8 @@
|
|||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/card_content"
|
android:id="@+id/card_content"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingBottom="16dp">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/device_icon"
|
android:id="@+id/device_icon"
|
||||||
@@ -107,7 +108,6 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginEnd="4dp"
|
android:layout_marginEnd="4dp"
|
||||||
android:minHeight="108dp"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/barrier_bottom"
|
app:layout_constraintBottom_toTopOf="@id/barrier_bottom"
|
||||||
app:layout_constraintEnd_toStartOf="@id/pod_case_container"
|
app:layout_constraintEnd_toStartOf="@id/pod_case_container"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
@@ -117,6 +117,7 @@
|
|||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/pod_left_icon"
|
android:id="@+id/pod_left_icon"
|
||||||
style="@style/PodInfoItemIcon"
|
style="@style/PodInfoItemIcon"
|
||||||
|
android:contentDescription="@string/pods_dual_left_label"
|
||||||
android:src="@drawable/ic_airpod_left_24"
|
android:src="@drawable/ic_airpod_left_24"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/pod_left_label"
|
app:layout_constraintBottom_toBottomOf="@id/pod_left_label"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
@@ -322,6 +323,7 @@
|
|||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/pod_right_icon"
|
android:id="@+id/pod_right_icon"
|
||||||
style="@style/PodInfoItemIcon"
|
style="@style/PodInfoItemIcon"
|
||||||
|
android:contentDescription="@string/pods_dual_right_label"
|
||||||
android:src="@drawable/ic_airpod_right_24"
|
android:src="@drawable/ic_airpod_right_24"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/pod_right_label"
|
app:layout_constraintBottom_toBottomOf="@id/pod_right_label"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
@@ -420,7 +422,6 @@
|
|||||||
app:layout_constraintTop_toBottomOf="@id/pod_right_microphone_label" />
|
app:layout_constraintTop_toBottomOf="@id/pod_right_microphone_label" />
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.Barrier
|
<androidx.constraintlayout.widget.Barrier
|
||||||
android:id="@+id/barrier_bottom"
|
android:id="@+id/barrier_bottom"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@@ -435,7 +436,6 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="16dp"
|
android:layout_marginHorizontal="16dp"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
+3
-5
@@ -12,7 +12,8 @@
|
|||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/card_content"
|
android:id="@+id/card_content"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingBottom="16dp">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/device_icon"
|
android:id="@+id/device_icon"
|
||||||
@@ -96,13 +97,11 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:minHeight="64dp"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/barrier_bottom"
|
app:layout_constraintBottom_toTopOf="@id/barrier_bottom"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/barrier_top"
|
app:layout_constraintTop_toBottomOf="@id/barrier_top"
|
||||||
app:layout_constraintVertical_bias="0.0"
|
app:layout_constraintVertical_bias="0.0">
|
||||||
app:layout_goneMarginBottom="16dp">
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/battery_icon"
|
android:id="@+id/battery_icon"
|
||||||
@@ -180,7 +179,6 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="16dp"
|
android:layout_marginHorizontal="16dp"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/headphones_icon"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:src="@drawable/ic_device_generic_earbuds"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/headphones_label"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/headphones_label"
|
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/headphones_label" />
|
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
|
||||||
android:id="@+id/headphones_label"
|
|
||||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:layout_marginHorizontal="8dp"
|
|
||||||
android:layout_marginTop="4dp"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/signal"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/headphones_icon"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
tools:text="Beats Solo 3" />
|
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
|
||||||
android:id="@+id/signal"
|
|
||||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:drawableEnd="@drawable/ic_baseline_signal_cellular_alt_24"
|
|
||||||
android:gravity="center"
|
|
||||||
android:minWidth="44dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/headphones_label"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/headphones_label"
|
|
||||||
tools:text="-90%" />
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:id="@+id/headphones_container"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="16dp"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_chainStyle="spread"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/headphones_label">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@id/headphones_battery_icon"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:src="@drawable/ic_baseline_battery_unknown_24"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/headphones_battery_label"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/headphones_battery_label"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/headphones_battery_label" />
|
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
|
||||||
android:id="@+id/headphones_battery_label"
|
|
||||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="4dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/headphones_battery_icon"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
tools:text="100%" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
<string name="settings_general_description">Bütün tətbiqə təsir edən ümumi incə tənzimləmələr.</string>
|
<string name="settings_general_description">Bütün tətbiqə təsir edən ümumi incə tənzimləmələr.</string>
|
||||||
<string name="settings_acknowledgements_label">Təşəkkürlər</string>
|
<string name="settings_acknowledgements_label">Təşəkkürlər</string>
|
||||||
<string name="changelog_label">Dəyişiklik jurnalı</string>
|
<string name="changelog_label">Dəyişiklik jurnalı</string>
|
||||||
<string name="settings_support_email_developer_label">Tərtibatçıya e-poçt göndər</string>
|
<string name="settings_support_email_developer_label" comment="settings_support_email_developer_label Pressing this setting will open your default email app with a template for a mail to me and some device info (e.g. versions).">Tərtibatçıya e-poçt göndər</string>
|
||||||
<string name="settings_support_installid_label">Quraşdırma kimliyi</string>
|
<string name="settings_support_installid_label">Quraşdırma kimliyi</string>
|
||||||
<string name="settings_support_installid_desc">Avtomatik xəta hesabatları anonimdir. Tərtibatçının xəta hesabatlarınızı tapmasına ehtiyacı varsa quraşdırma kimliyinizi paylaşın.</string>
|
<string name="settings_support_installid_desc">Avtomatik xəta hesabatları anonimdir. Tərtibatçının xəta hesabatlarınızı tapmasına ehtiyacı varsa quraşdırma kimliyinizi paylaşın.</string>
|
||||||
<string name="settings_support_label">Dəstək</string>
|
<string name="settings_support_label">Dəstək</string>
|
||||||
|
|||||||
@@ -1,2 +1,29 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources></resources>
|
<resources>
|
||||||
|
<string name="app_name">CAPod</string>
|
||||||
|
<string name="app_name_pro">CAPod Pro</string>
|
||||||
|
<string name="app_name_foss">CAPod FOSS</string>
|
||||||
|
<string name="notification_channel_device_status_label">Статус прылады</string>
|
||||||
|
<string name="general_error_label">Памылка</string>
|
||||||
|
<string name="general_share_action">Падзяліцца</string>
|
||||||
|
<string name="general_done_action">Гатова</string>
|
||||||
|
<string name="general_copy_action">Скапіраваць</string>
|
||||||
|
<string name="general_thank_you_label">Дзякуй</string>
|
||||||
|
<string name="general_value_not_available_label">Н/д</string>
|
||||||
|
<string name="general_grant_permission_action">Даць дазвол</string>
|
||||||
|
<string name="general_upgrade_action">Палепшыць</string>
|
||||||
|
<string name="general_check_action">Праверыць</string>
|
||||||
|
<string name="general_close_action">Закрыць</string>
|
||||||
|
<string name="debug_debuglog_size_label">Памер</string>
|
||||||
|
<string name="debug_debuglog_size_compressed_label">Сціснуты памер</string>
|
||||||
|
<string name="debug_notification_channel_label">Апавяшчэнні адладкі</string>
|
||||||
|
<string name="debug_debuglog_file_label">Файл журнала</string>
|
||||||
|
<string name="debug_debuglog_record_action">Запісаць лог аладкі ў журнал</string>
|
||||||
|
<string name="permission_bluetooth_connect_label">Злучэнне па Bluetooth</string>
|
||||||
|
<string name="permission_bluetooth_connect_description">Гэтай праграме патрабуецца дазвол на выкарыстанне Bluetooth для ўзаемадзеяння са спалучанымі прыладамі і стварэння новых злучэнняў.</string>
|
||||||
|
<string name="permission_bluetooth_scan_label">Сканіраванне Bluetooth</string>
|
||||||
|
<string name="permission_bluetooth_scan_description">Дазвол на сканіраванне Bluetooth дасць магчымасць гэтай праграме выяўляць і атрымліваць даныя па Bluetooth з навакольных прылад, такіх як вашы AirPods.</string>
|
||||||
|
<string name="permission_bluetooth_label">Bluetooth</string>
|
||||||
|
<string name="permission_bluetooth_description">Гэтай праграме патрабуецца дазвол на выкарыстанне Bluetooth для злучэння са спалучанымі прыладамі.</string>
|
||||||
|
<string name="permission_access_fine_location_label">Доступ да дакладнага месцазнаходжання</string>
|
||||||
|
</resources>
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="general_done_action">সম্পন্ন</string>
|
<string name="general_done_action">সম্পন্ন</string>
|
||||||
<string name="general_thank_you_label">ধন্যবাদ</string>
|
<string name="general_thank_you_label">ধন্যবাদ</string>
|
||||||
|
<string name="general_grant_permission_action">অনুমতি প্রদান করুন</string>
|
||||||
|
<string name="general_upgrade_action">আপগ্রেড</string>
|
||||||
<string name="debug_debuglog_size_label">আকার</string>
|
<string name="debug_debuglog_size_label">আকার</string>
|
||||||
<string name="settings_general_label">সেটিংস</string>
|
<string name="settings_general_label">সেটিংস</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
<string name="settings_general_description">Configuracions generals que afecten a tota l\'aplicació.</string>
|
<string name="settings_general_description">Configuracions generals que afecten a tota l\'aplicació.</string>
|
||||||
<string name="settings_acknowledgements_label">Agraïments</string>
|
<string name="settings_acknowledgements_label">Agraïments</string>
|
||||||
<string name="changelog_label">Registre de canvis</string>
|
<string name="changelog_label">Registre de canvis</string>
|
||||||
<string name="settings_support_email_developer_label">Correu del desenvolupador</string>
|
<string name="settings_support_email_developer_label" comment="settings_support_email_developer_label Pressing this setting will open your default email app with a template for a mail to me and some device info (e.g. versions).">Correu del desenvolupador</string>
|
||||||
<string name="settings_support_installid_label">ID d\'instal·lació</string>
|
<string name="settings_support_installid_label">ID d\'instal·lació</string>
|
||||||
<string name="settings_support_installid_desc">Els informes d\'error automàtics són anònims. Compartiu el vostre ID d\'instal·lació si el desenvolupador necessita trobar els vostres informes d\'error.</string>
|
<string name="settings_support_installid_desc">Els informes d\'error automàtics són anònims. Compartiu el vostre ID d\'instal·lació si el desenvolupador necessita trobar els vostres informes d\'error.</string>
|
||||||
<string name="settings_support_label">Suport</string>
|
<string name="settings_support_label">Suport</string>
|
||||||
@@ -134,4 +134,6 @@
|
|||||||
<string name="permission_required_title">Cal el permís següent:</string>
|
<string name="permission_required_title">Cal el permís següent:</string>
|
||||||
<string name="settings_compatibility_mode_label">Mode de compatibilitat</string>
|
<string name="settings_compatibility_mode_label">Mode de compatibilitat</string>
|
||||||
<string name="settings_compatibility_mode_description">Desactiva les optimitzacions per millorar la compatibilitat. Proveu això si no veieu cap dada.</string>
|
<string name="settings_compatibility_mode_description">Desactiva les optimitzacions per millorar la compatibilitat. Proveu això si no veieu cap dada.</string>
|
||||||
|
<string name="translators_thanks_title">Traductors</string>
|
||||||
|
<string name="translators_thanks_description" comment="translators_thanks_description You can voluntarily add your name here to have it displayed in the app. It will be shown in the Settings>Acknowledgements>Thank you section. Separate names by semicolons and an optional email may be included in brackets, example: darken(darken@darken.eu);John Doe(john@example.com) "darken" is just a placeholder and does not have to be kept if/when you add yours. Be nice to each other!">Jaime Muñoz(jmmartin_5@outlook.com)</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
<string name="settings_general_description">Obecná vylepšení, která ovlivňují celou aplikaci.</string>
|
<string name="settings_general_description">Obecná vylepšení, která ovlivňují celou aplikaci.</string>
|
||||||
<string name="settings_acknowledgements_label">Poděkování</string>
|
<string name="settings_acknowledgements_label">Poděkování</string>
|
||||||
<string name="changelog_label">Seznam změn</string>
|
<string name="changelog_label">Seznam změn</string>
|
||||||
<string name="settings_support_email_developer_label">E-mail vývojáři</string>
|
<string name="settings_support_email_developer_label" comment="settings_support_email_developer_label Pressing this setting will open your default email app with a template for a mail to me and some device info (e.g. versions).">E-mail vývojáři</string>
|
||||||
<string name="settings_support_installid_label">ID instalace</string>
|
<string name="settings_support_installid_label">ID instalace</string>
|
||||||
<string name="settings_support_installid_desc">Automatická hlášení chyb jsou anonymní. Sdílíte pouze své ID instalace, pokud vývojář potřebuje najít vaše chybová hlášení.</string>
|
<string name="settings_support_installid_desc">Automatická hlášení chyb jsou anonymní. Sdílíte pouze své ID instalace, pokud vývojář potřebuje najít vaše chybová hlášení.</string>
|
||||||
<string name="settings_support_label">Podpora</string>
|
<string name="settings_support_label">Podpora</string>
|
||||||
@@ -134,4 +134,6 @@
|
|||||||
<string name="permission_required_title">Je vyžadováno následující oprávnění:</string>
|
<string name="permission_required_title">Je vyžadováno následující oprávnění:</string>
|
||||||
<string name="settings_compatibility_mode_label">Režim kompatibility</string>
|
<string name="settings_compatibility_mode_label">Režim kompatibility</string>
|
||||||
<string name="settings_compatibility_mode_description">Vypnutí optimalizace pro zlepšení kompatibility. Zkuste to, pokud se vám nezobrazují žádná data.</string>
|
<string name="settings_compatibility_mode_description">Vypnutí optimalizace pro zlepšení kompatibility. Zkuste to, pokud se vám nezobrazují žádná data.</string>
|
||||||
|
<string name="translators_thanks_title">Překladatelé</string>
|
||||||
|
<string name="translators_thanks_description" comment="translators_thanks_description You can voluntarily add your name here to have it displayed in the app. It will be shown in the Settings>Acknowledgements>Thank you section. Separate names by semicolons and an optional email may be included in brackets, example: darken(darken@darken.eu);John Doe(john@example.com) "darken" is just a placeholder and does not have to be kept if/when you add yours. Be nice to each other!">novas78@xda; woytazzer</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
<string name="settings_general_description">Allgemeine Optimierungen, die die gesamte App betreffen.</string>
|
<string name="settings_general_description">Allgemeine Optimierungen, die die gesamte App betreffen.</string>
|
||||||
<string name="settings_acknowledgements_label">Danksagungen</string>
|
<string name="settings_acknowledgements_label">Danksagungen</string>
|
||||||
<string name="changelog_label">Änderungsprotokoll</string>
|
<string name="changelog_label">Änderungsprotokoll</string>
|
||||||
<string name="settings_support_email_developer_label">E-Mail-Entwickler</string>
|
<string name="settings_support_email_developer_label" comment="settings_support_email_developer_label Pressing this setting will open your default email app with a template for a mail to me and some device info (e.g. versions).">E-Mail-Entwickler</string>
|
||||||
<string name="settings_support_installid_label">ID installieren</string>
|
<string name="settings_support_installid_label">ID installieren</string>
|
||||||
<string name="settings_support_installid_desc">Automatische Fehlermeldungen sind anonym. Teilen Sie Ihre Installations- ID mit, wenn der Entwickler Ihre Fehlerberichte finden muss.</string>
|
<string name="settings_support_installid_desc">Automatische Fehlermeldungen sind anonym. Teilen Sie Ihre Installations- ID mit, wenn der Entwickler Ihre Fehlerberichte finden muss.</string>
|
||||||
<string name="settings_support_label">Unterstützung</string>
|
<string name="settings_support_label">Unterstützung</string>
|
||||||
@@ -134,4 +134,6 @@
|
|||||||
<string name="permission_required_title">Die folgende Genehmigung ist erforderlich:</string>
|
<string name="permission_required_title">Die folgende Genehmigung ist erforderlich:</string>
|
||||||
<string name="settings_compatibility_mode_label">Kompatibilitätsmodus</string>
|
<string name="settings_compatibility_mode_label">Kompatibilitätsmodus</string>
|
||||||
<string name="settings_compatibility_mode_description">Deaktivieren Sie Optimierungen, um die Kompatibilität zu verbessern. Versuchen Sie dies, wenn Sie keine Daten sehen.</string>
|
<string name="settings_compatibility_mode_description">Deaktivieren Sie Optimierungen, um die Kompatibilität zu verbessern. Versuchen Sie dies, wenn Sie keine Daten sehen.</string>
|
||||||
|
<string name="translators_thanks_title">Übersetzer</string>
|
||||||
|
<string name="translators_thanks_description" comment="translators_thanks_description You can voluntarily add your name here to have it displayed in the app. It will be shown in the Settings>Acknowledgements>Thank you section. Separate names by semicolons and an optional email may be included in brackets, example: darken(darken@darken.eu);John Doe(john@example.com) "darken" is just a placeholder and does not have to be kept if/when you add yours. Be nice to each other!">darken</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
<string name="settings_general_description">Γενικές ρυθμίσεις που επηρεάζουν όλη την εφαρμογή.</string>
|
<string name="settings_general_description">Γενικές ρυθμίσεις που επηρεάζουν όλη την εφαρμογή.</string>
|
||||||
<string name="settings_acknowledgements_label">Ευχαριστίες</string>
|
<string name="settings_acknowledgements_label">Ευχαριστίες</string>
|
||||||
<string name="changelog_label">Αρχείο αλλαγών</string>
|
<string name="changelog_label">Αρχείο αλλαγών</string>
|
||||||
<string name="settings_support_email_developer_label">Email στον προγραμματιστή</string>
|
<string name="settings_support_email_developer_label" comment="settings_support_email_developer_label Pressing this setting will open your default email app with a template for a mail to me and some device info (e.g. versions).">Email στον προγραμματιστή</string>
|
||||||
<string name="settings_support_installid_label">Αναγνωριστικό εγκατάστασης</string>
|
<string name="settings_support_installid_label">Αναγνωριστικό εγκατάστασης</string>
|
||||||
<string name="settings_support_installid_desc">Οι αυτόματες αναφορές σφαλμάτων είναι ανώνυμες. Κοινοποιήστε το αναγνωριστικό εγκατάστασης εάν ο προγραμματιστής πρέπει να βρει τις αναφορές σας σφαλμάτων.</string>
|
<string name="settings_support_installid_desc">Οι αυτόματες αναφορές σφαλμάτων είναι ανώνυμες. Κοινοποιήστε το αναγνωριστικό εγκατάστασης εάν ο προγραμματιστής πρέπει να βρει τις αναφορές σας σφαλμάτων.</string>
|
||||||
<string name="settings_support_label">Υποστήριξη</string>
|
<string name="settings_support_label">Υποστήριξη</string>
|
||||||
@@ -134,4 +134,6 @@
|
|||||||
<string name="permission_required_title">Η ακόλουθη άδεια είναι απαραίτητη:</string>
|
<string name="permission_required_title">Η ακόλουθη άδεια είναι απαραίτητη:</string>
|
||||||
<string name="settings_compatibility_mode_label">Λειτουργία συμβατότητας</string>
|
<string name="settings_compatibility_mode_label">Λειτουργία συμβατότητας</string>
|
||||||
<string name="settings_compatibility_mode_description">Απενεργοποίηση βελτιστοποιήσεων για βελτίωση συμβατότητας. Δοκιμάστε αυτό εάν δε βλέπετε δεδομένα.</string>
|
<string name="settings_compatibility_mode_description">Απενεργοποίηση βελτιστοποιήσεων για βελτίωση συμβατότητας. Δοκιμάστε αυτό εάν δε βλέπετε δεδομένα.</string>
|
||||||
|
<string name="translators_thanks_title">Μεταφραστές</string>
|
||||||
|
<string name="translators_thanks_description" comment="translators_thanks_description You can voluntarily add your name here to have it displayed in the app. It will be shown in the Settings>Acknowledgements>Thank you section. Separate names by semicolons and an optional email may be included in brackets, example: darken(darken@darken.eu);John Doe(john@example.com) "darken" is just a placeholder and does not have to be kept if/when you add yours. Be nice to each other!">Vagelis1608</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -25,4 +25,31 @@
|
|||||||
<string name="permission_bluetooth_scan_description">El permiso \"Escaneo Bluetooth\" permite que esta aplicación descubra y reciba datos de Bluetooth de dispositivos cercanos como tus AirPods.</string>
|
<string name="permission_bluetooth_scan_description">El permiso \"Escaneo Bluetooth\" permite que esta aplicación descubra y reciba datos de Bluetooth de dispositivos cercanos como tus AirPods.</string>
|
||||||
<string name="permission_bluetooth_label">Bluetooth</string>
|
<string name="permission_bluetooth_label">Bluetooth</string>
|
||||||
<string name="permission_bluetooth_description">Esta aplicacion requiere el permiso \"Bluetooth\" para conectarse a los dispositivos vinculados.</string>
|
<string name="permission_bluetooth_description">Esta aplicacion requiere el permiso \"Bluetooth\" para conectarse a los dispositivos vinculados.</string>
|
||||||
|
<string name="permission_access_fine_location_label">Acceso a la ubicación precisa</string>
|
||||||
|
<string name="permission_access_fine_location_description">CAPod utiliza el permiso de \"ubicación precisa\" para recibir Datos de Bluetooth de bajo consumo. Sus auriculares utilizan la tecnología Datos de Bluetooth de bajo consumo para transmitir su estado. Esta aplicación NO utilizará datos de Bluetooth para determinar su ubicación.</string>
|
||||||
|
<string name="permission_background_location_label">Acceso a la ubicación en segundo plano</string>
|
||||||
|
<string name="permission_background_location_description">CAPod usa el \"acceso a la ubicación en segundo plano\" para habilitar funciones como \"Mostrar ventana emergente\" y \"Conexión automática\" mientras la aplicación está cerrada. El acceso a la ubicación en segundo plano permite que la aplicación reciba datos de Bluetooth de bajo consumo mientras está en segundo plano. Esta aplicación NO utilizará datos de Bluetooth para determinar su ubicación.</string>
|
||||||
|
<string name="permission_ignore_battery_optimizations_label">Deshabilitar optimizaciones de batería</string>
|
||||||
|
<string name="permission_ignore_battery_optimizations_description">Las optimizaciones de la batería evitan que esta aplicación reciba datos de Bluetooth de manera confiable mientras la aplicación está en segundo plano.</string>
|
||||||
|
<string name="pods_dual_left_label">Audífono izquierdo</string>
|
||||||
|
<string name="pods_dual_right_label">Audífono derecho</string>
|
||||||
|
<string name="pods_case_label">Estuche</string>
|
||||||
|
<string name="pods_case_status_open_label">Estuche abierto</string>
|
||||||
|
<string name="pods_case_status_closed_label">Estuche cerrado</string>
|
||||||
|
<string name="pods_connection_state_disconnected_label">No está conectado a un dispositivo</string>
|
||||||
|
<string name="pods_connection_state_idle_label">Conectado a un dispositivo, pero inactivo</string>
|
||||||
|
<string name="pods_connection_state_music_label">En modo música</string>
|
||||||
|
<string name="pods_connection_state_call_label">En modo llamada</string>
|
||||||
|
<string name="pods_connection_state_ringing_label">Sonando</string>
|
||||||
|
<string name="pods_connection_state_hanging_up_label">Colgar</string>
|
||||||
|
<string name="pods_connection_state_unknown_label">Estado de conexión desconocido</string>
|
||||||
|
<string name="pods_unknown_raw_data_label">Datos sin procesar</string>
|
||||||
|
<string name="pods_unknown_label">Dispositivo desconocido</string>
|
||||||
|
<string name="pods_unknown_contact_dev">Este es un dispositivo desconocido, pero está usando un formato de mensaje similar. Agreguemos soporte para ello, contáctame :)</string>
|
||||||
|
<string name="pods_none_label_short">Sin dispositivo</string>
|
||||||
|
<string name="pods_charging_label">Cargando</string>
|
||||||
|
<string name="pods_inear_label">En el oído</string>
|
||||||
|
<string name="pods_microphone_label">Micrófono</string>
|
||||||
|
<string name="pods_yours">Tuyos</string>
|
||||||
|
<string name="headset_being_worn_label">En uso</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
<string name="settings_general_description">Ajustes generales que afectan a toda la aplicación.</string>
|
<string name="settings_general_description">Ajustes generales que afectan a toda la aplicación.</string>
|
||||||
<string name="settings_acknowledgements_label">Agradecimientos</string>
|
<string name="settings_acknowledgements_label">Agradecimientos</string>
|
||||||
<string name="changelog_label">Registro de cambios</string>
|
<string name="changelog_label">Registro de cambios</string>
|
||||||
<string name="settings_support_email_developer_label">Correo del desarrollador</string>
|
<string name="settings_support_email_developer_label" comment="settings_support_email_developer_label Pressing this setting will open your default email app with a template for a mail to me and some device info (e.g. versions).">Correo del desarrollador</string>
|
||||||
<string name="settings_support_installid_label">ID de instalación</string>
|
<string name="settings_support_installid_label">ID de instalación</string>
|
||||||
<string name="settings_support_installid_desc">Los informes automáticos de errores son anónimos. Comparta su ID de instalación si el desarrollador necesita encontrar sus informes de error.</string>
|
<string name="settings_support_installid_desc">Los informes automáticos de errores son anónimos. Comparta su ID de instalación si el desarrollador necesita encontrar sus informes de error.</string>
|
||||||
<string name="settings_support_label">Ayuda</string>
|
<string name="settings_support_label">Ayuda</string>
|
||||||
@@ -134,4 +134,6 @@
|
|||||||
<string name="permission_required_title">Se requiere el siguiente permiso:</string>
|
<string name="permission_required_title">Se requiere el siguiente permiso:</string>
|
||||||
<string name="settings_compatibility_mode_label">Modo de compatibilidad</string>
|
<string name="settings_compatibility_mode_label">Modo de compatibilidad</string>
|
||||||
<string name="settings_compatibility_mode_description">Deshabilita las optimizaciones para mejorar la compatibilidad. Prueba esto si no ves ningún dato.</string>
|
<string name="settings_compatibility_mode_description">Deshabilita las optimizaciones para mejorar la compatibilidad. Prueba esto si no ves ningún dato.</string>
|
||||||
|
<string name="translators_thanks_title">Traductores</string>
|
||||||
|
<string name="translators_thanks_description" comment="translators_thanks_description You can voluntarily add your name here to have it displayed in the app. It will be shown in the Settings>Acknowledgements>Thank you section. Separate names by semicolons and an optional email may be included in brackets, example: darken(darken@darken.eu);John Doe(john@example.com) "darken" is just a placeholder and does not have to be kept if/when you add yours. Be nice to each other!">Jaime Muñoz(jmmartin_5@outlook.com)</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1,2 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources></resources>
|
<resources>
|
||||||
|
<string name="pods_dual_left_label">Vasak klapp</string>
|
||||||
|
<string name="pods_dual_right_label">Parem klapp</string>
|
||||||
|
</resources>
|
||||||
|
|||||||
@@ -13,5 +13,19 @@
|
|||||||
<string name="debug_debuglog_size_label">Sukat</string>
|
<string name="debug_debuglog_size_label">Sukat</string>
|
||||||
<string name="permission_bluetooth_connect_description">Ang app na ito ay kailangan ng \"Bluetooth connect\" permission para makipag interact sa mga na-paired na devices at maka gawa ng connection.</string>
|
<string name="permission_bluetooth_connect_description">Ang app na ito ay kailangan ng \"Bluetooth connect\" permission para makipag interact sa mga na-paired na devices at maka gawa ng connection.</string>
|
||||||
<string name="permission_bluetooth_scan_description">Ang \"Bluetooth scanning\" permission ay pag na ibigay, itong app na ito ay puwedeng mag diskubre o maka receive ng data galing sa isang malapit na Bluetooth devices tulad ng iyong AirPods.</string>
|
<string name="permission_bluetooth_scan_description">Ang \"Bluetooth scanning\" permission ay pag na ibigay, itong app na ito ay puwedeng mag diskubre o maka receive ng data galing sa isang malapit na Bluetooth devices tulad ng iyong AirPods.</string>
|
||||||
|
<string name="permission_bluetooth_label">Bluetooth</string>
|
||||||
|
<string name="permission_bluetooth_description">Ang app na ito ay kailangan ng \"Bluetooth\" permission upang maka connect sa naka-paired na bluetooth device.</string>
|
||||||
<string name="permission_access_fine_location_description">Ang CAPod app ay gumagamit ng \"Fine location\" permission para maka receiveng Bluetooth Low Energy Data. Iyong headphones ay gumagamit ng Bluetooth Low Energy technology pa ma-broadcaast ang kanilang Status. Itong app na ito ay HINDI gagamitin ang Bluetooth data para malaman ang iyong lokasyon.</string>
|
<string name="permission_access_fine_location_description">Ang CAPod app ay gumagamit ng \"Fine location\" permission para maka receiveng Bluetooth Low Energy Data. Iyong headphones ay gumagamit ng Bluetooth Low Energy technology pa ma-broadcaast ang kanilang Status. Itong app na ito ay HINDI gagamitin ang Bluetooth data para malaman ang iyong lokasyon.</string>
|
||||||
|
<string name="pods_dual_left_label">Kaliwang pod</string>
|
||||||
|
<string name="pods_dual_right_label">Kanan na pod</string>
|
||||||
|
<string name="pods_case_status_open_label">Buksan</string>
|
||||||
|
<string name="pods_case_status_closed_label">Sarado</string>
|
||||||
|
<string name="pods_connection_state_disconnected_label">Hindi Konektado sa device</string>
|
||||||
|
<string name="pods_unknown_contact_dev">Ito ay hindi kilalang Device, pero ginagamit ang kilalang message format. lagyan nating ng support para diyan, contact mo ko :)</string>
|
||||||
|
<string name="pods_yours">Sayo</string>
|
||||||
|
<string name="headset_being_worn_label">Ginagamit</string>
|
||||||
|
<string name="pods_case_unknown_state">Hindi alam ang stado</string>
|
||||||
|
<string name="overview_nomaindevice_description">Lahat ng mga device ay malabong saiyo. I-power on at i-connect ang device mo o i-adjust ang settings.</string>
|
||||||
|
<string name="settings_licenses_label">Lisensiya</string>
|
||||||
|
<string name="settings_category_other_label">Iba</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
<string name="settings_general_description">Réglage généraux qui affectent l\'appli entière.</string>
|
<string name="settings_general_description">Réglage généraux qui affectent l\'appli entière.</string>
|
||||||
<string name="settings_acknowledgements_label">Remerciements</string>
|
<string name="settings_acknowledgements_label">Remerciements</string>
|
||||||
<string name="changelog_label">Journal des changements</string>
|
<string name="changelog_label">Journal des changements</string>
|
||||||
<string name="settings_support_email_developer_label">Envoyer un courriel au développeur</string>
|
<string name="settings_support_email_developer_label" comment="settings_support_email_developer_label Pressing this setting will open your default email app with a template for a mail to me and some device info (e.g. versions).">Envoyer un courriel au développeur</string>
|
||||||
<string name="settings_support_installid_label">ID d’installation</string>
|
<string name="settings_support_installid_label">ID d’installation</string>
|
||||||
<string name="settings_support_installid_desc">Les relevés automatiques d’erreur sont anonymes. Partagez votre ID d’installation au cas où le développeur aurait besoin de trouver votre relevé d’erreur.</string>
|
<string name="settings_support_installid_desc">Les relevés automatiques d’erreur sont anonymes. Partagez votre ID d’installation au cas où le développeur aurait besoin de trouver votre relevé d’erreur.</string>
|
||||||
<string name="settings_support_label">Assistance</string>
|
<string name="settings_support_label">Assistance</string>
|
||||||
@@ -81,6 +81,7 @@
|
|||||||
<string name="settings_monitor_mode_label">Mode surveillance</string>
|
<string name="settings_monitor_mode_label">Mode surveillance</string>
|
||||||
<string name="settings_monitor_mode_description">Les circonstances de surveillance des données Bluetooth par l’appli.</string>
|
<string name="settings_monitor_mode_description">Les circonstances de surveillance des données Bluetooth par l’appli.</string>
|
||||||
<string name="settings_scanner_mode_label">Mode analyse</string>
|
<string name="settings_scanner_mode_label">Mode analyse</string>
|
||||||
|
<string name="settings_scanner_mode_description">L’analyseur des données « basse énergie » de Bluetooth devrait-il prioriser les performances ou préserver l’énergie ?</string>
|
||||||
<string name="settings_monitor_mode_manual_label">Si l’appli est en fonction</string>
|
<string name="settings_monitor_mode_manual_label">Si l’appli est en fonction</string>
|
||||||
<string name="settings_monitor_mode_automatic_label">Si l’appareil est connecté</string>
|
<string name="settings_monitor_mode_automatic_label">Si l’appareil est connecté</string>
|
||||||
<string name="settings_monitor_mode_always_label">Toujours</string>
|
<string name="settings_monitor_mode_always_label">Toujours</string>
|
||||||
@@ -88,10 +89,13 @@
|
|||||||
<string name="settings_scanner_mode_balanced_label">Équilibré</string>
|
<string name="settings_scanner_mode_balanced_label">Équilibré</string>
|
||||||
<string name="settings_scanner_mode_lowlatency_label">Faible latence</string>
|
<string name="settings_scanner_mode_lowlatency_label">Faible latence</string>
|
||||||
<string name="settings_autopause_label">Pause automatique</string>
|
<string name="settings_autopause_label">Pause automatique</string>
|
||||||
|
<string name="settings_autopause_description">Mettre le son en pause si vous ôtez l’appareil de votre oreille.</string>
|
||||||
<string name="settings_showall_label">Afficher tous les appareils</string>
|
<string name="settings_showall_label">Afficher tous les appareils</string>
|
||||||
<string name="settings_showall_description">Afficher les appareils d’autres personnes à proximité.</string>
|
<string name="settings_showall_description">Afficher les appareils d’autres personnes à proximité.</string>
|
||||||
<string name="settings_autopplay_label">Lecture automatique</string>
|
<string name="settings_autopplay_label">Lecture automatique</string>
|
||||||
|
<string name="settings_autoplay_description">Démarrer la lecture du son quand l’appareil est porté.</string>
|
||||||
<string name="settings_fake_data_label">Fausses données</string>
|
<string name="settings_fake_data_label">Fausses données</string>
|
||||||
|
<string name="settings_fake_data_description">Afficher les fausses données, c.-à-d. simuler les appareils qui n’existent pas.</string>
|
||||||
<string name="settings_debug_label">Paramètres de débogage</string>
|
<string name="settings_debug_label">Paramètres de débogage</string>
|
||||||
<string name="settings_debug_description">Autres paramètres pour aider à diagnostiquer les problèmes de l’appli.</string>
|
<string name="settings_debug_description">Autres paramètres pour aider à diagnostiquer les problèmes de l’appli.</string>
|
||||||
<string name="settings_signal_minimum_label">Qualité minimale du signal</string>
|
<string name="settings_signal_minimum_label">Qualité minimale du signal</string>
|
||||||
@@ -118,6 +122,7 @@
|
|||||||
<string name="overview_bluetooth_disabled_label">Le Bluetooth est désactivé</string>
|
<string name="overview_bluetooth_disabled_label">Le Bluetooth est désactivé</string>
|
||||||
<string name="overview_bluetooth_disabled_description">Le Bluetooth est désactivé, activez-le ;)</string>
|
<string name="overview_bluetooth_disabled_description">Le Bluetooth est désactivé, activez-le ;)</string>
|
||||||
<string name="help_translate_label">Traduction</string>
|
<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="settings_onepod_mode_label">Mode à un seul AirPod</string>
|
<string name="settings_onepod_mode_label">Mode à un seul AirPod</string>
|
||||||
<string name="settings_onepod_mode_description">Il n’est pas nécessaire de porter deux AirPods, en porter un seul suffit à déclencher les réactions.</string>
|
<string name="settings_onepod_mode_description">Il n’est pas nécessaire de porter deux AirPods, en porter un seul suffit à déclencher les réactions.</string>
|
||||||
<string name="permission_system_alert_window_label">Fenêtre d’alerte système</string>
|
<string name="permission_system_alert_window_label">Fenêtre d’alerte système</string>
|
||||||
@@ -127,4 +132,8 @@
|
|||||||
<string name="settings_blescanner_unfiltered_label">Données BÉB non filtrées</string>
|
<string name="settings_blescanner_unfiltered_label">Données BÉB non filtrées</string>
|
||||||
<string name="settings_blescanner_unfiltered_description">Supprimer tous les filtres de l’analyseur BÉB pour afficher toutes les données BÉB diffusées. Utile pour prendre en charge les nouveaux types de casques-micros.</string>
|
<string name="settings_blescanner_unfiltered_description">Supprimer tous les filtres de l’analyseur BÉB pour afficher toutes les données BÉB diffusées. Utile pour prendre en charge les nouveaux types de casques-micros.</string>
|
||||||
<string name="permission_required_title">L’autorisation suivante est nécessaire :</string>
|
<string name="permission_required_title">L’autorisation suivante est nécessaire :</string>
|
||||||
|
<string name="settings_compatibility_mode_label">Mode de compatibilité</string>
|
||||||
|
<string name="settings_compatibility_mode_description">Désactiver les optimisations pour améliorer la compatibilité. À essayer si vous ne voyez aucune donnée.</string>
|
||||||
|
<string name="translators_thanks_title">Traducteurs</string>
|
||||||
|
<string name="translators_thanks_description" comment="translators_thanks_description You can voluntarily add your name here to have it displayed in the app. It will be shown in the Settings>Acknowledgements>Thank you section. Separate names by semicolons and an optional email may be included in brackets, example: darken(darken@darken.eu);John Doe(john@example.com) "darken" is just a placeholder and does not have to be kept if/when you add yours. Be nice to each other!">AO</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1,2 +1,13 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources></resources>
|
<resources>
|
||||||
|
<string name="app_name">CAPod</string>
|
||||||
|
<string name="app_name_pro">CAPod Pro</string>
|
||||||
|
<string name="app_name_foss">CAPod FOSS</string>
|
||||||
|
<string name="notification_channel_device_status_label">उपकरण की स्थिति</string>
|
||||||
|
<string name="general_error_label">त्रुटि</string>
|
||||||
|
<string name="general_share_action">साझा करना</string>
|
||||||
|
<string name="general_done_action">पूर्ण</string>
|
||||||
|
<string name="general_copy_action">प्रतिलिपि</string>
|
||||||
|
<string name="general_thank_you_label">शुक्रिया</string>
|
||||||
|
<string name="general_value_not_available_label">N/A</string>
|
||||||
|
</resources>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
<string name="settings_general_description">Általános módosítások, amelyek az egész alkalmazást érintik.</string>
|
<string name="settings_general_description">Általános módosítások, amelyek az egész alkalmazást érintik.</string>
|
||||||
<string name="settings_acknowledgements_label">Köszönetnyilvánítások</string>
|
<string name="settings_acknowledgements_label">Köszönetnyilvánítások</string>
|
||||||
<string name="changelog_label">Napló</string>
|
<string name="changelog_label">Napló</string>
|
||||||
<string name="settings_support_email_developer_label">Fejlesztő Email címe</string>
|
<string name="settings_support_email_developer_label" comment="settings_support_email_developer_label Pressing this setting will open your default email app with a template for a mail to me and some device info (e.g. versions).">Fejlesztő Email címe</string>
|
||||||
<string name="settings_support_installid_label">Azonosító</string>
|
<string name="settings_support_installid_label">Azonosító</string>
|
||||||
<string name="settings_support_installid_desc">Az automatikus hibajelentések névtelenek. Ossza meg azonosítóját, hogy a fejlesztő megtalálja a hibajelentéseket.</string>
|
<string name="settings_support_installid_desc">Az automatikus hibajelentések névtelenek. Ossza meg azonosítóját, hogy a fejlesztő megtalálja a hibajelentéseket.</string>
|
||||||
<string name="settings_support_label">Támogatás</string>
|
<string name="settings_support_label">Támogatás</string>
|
||||||
@@ -127,4 +127,5 @@
|
|||||||
<string name="settings_blescanner_unfiltered_label">Szűretlen BLE adatok</string>
|
<string name="settings_blescanner_unfiltered_label">Szűretlen BLE adatok</string>
|
||||||
<string name="settings_blescanner_unfiltered_description">Távolítson el minden szűrőt a BLE szkennerből, hogy megjelenjen az összes adat. Hasznos új fejhallgató típusok támogatásához.</string>
|
<string name="settings_blescanner_unfiltered_description">Távolítson el minden szűrőt a BLE szkennerből, hogy megjelenjen az összes adat. Hasznos új fejhallgató típusok támogatásához.</string>
|
||||||
<string name="permission_required_title">A következő engedély szükséges:</string>
|
<string name="permission_required_title">A következő engedély szükséges:</string>
|
||||||
|
<string name="translators_thanks_title">Fordító</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
<string name="settings_general_description">Penyesuaian umum yang memengaruhi seluruh aplikasi.</string>
|
<string name="settings_general_description">Penyesuaian umum yang memengaruhi seluruh aplikasi.</string>
|
||||||
<string name="settings_acknowledgements_label">Ucapan terima kasih</string>
|
<string name="settings_acknowledgements_label">Ucapan terima kasih</string>
|
||||||
<string name="changelog_label">Catatan perubahan</string>
|
<string name="changelog_label">Catatan perubahan</string>
|
||||||
<string name="settings_support_email_developer_label">Email pengembang</string>
|
<string name="settings_support_email_developer_label" comment="settings_support_email_developer_label Pressing this setting will open your default email app with a template for a mail to me and some device info (e.g. versions).">Email pengembang</string>
|
||||||
<string name="settings_support_installid_label">ID pemasangan</string>
|
<string name="settings_support_installid_label">ID pemasangan</string>
|
||||||
<string name="settings_support_installid_desc">Laporan kesalahan otomatis bersifat anonim. Bagikan ID pemasangan anda jika pengembang perlu menemukan laporan kesalahan anda.</string>
|
<string name="settings_support_installid_desc">Laporan kesalahan otomatis bersifat anonim. Bagikan ID pemasangan anda jika pengembang perlu menemukan laporan kesalahan anda.</string>
|
||||||
<string name="settings_support_label">Dukungan</string>
|
<string name="settings_support_label">Dukungan</string>
|
||||||
@@ -81,6 +81,7 @@
|
|||||||
<string name="settings_monitor_mode_label">Mode monitor</string>
|
<string name="settings_monitor_mode_label">Mode monitor</string>
|
||||||
<string name="settings_monitor_mode_description">Dalam keadaan apa aplikasi ini memonitor data Bluetooth.</string>
|
<string name="settings_monitor_mode_description">Dalam keadaan apa aplikasi ini memonitor data Bluetooth.</string>
|
||||||
<string name="settings_scanner_mode_label">Modus memindai</string>
|
<string name="settings_scanner_mode_label">Modus memindai</string>
|
||||||
|
<string name="settings_scanner_mode_description">Haruskah pemindai data Bluetooth Hemat Energi memprioritaskan kinerja atau menghemat energi?</string>
|
||||||
<string name="settings_monitor_mode_manual_label">Saat aplikasi terbuka</string>
|
<string name="settings_monitor_mode_manual_label">Saat aplikasi terbuka</string>
|
||||||
<string name="settings_monitor_mode_automatic_label">Saat perangkat terhubung</string>
|
<string name="settings_monitor_mode_automatic_label">Saat perangkat terhubung</string>
|
||||||
<string name="settings_monitor_mode_always_label">Selalu</string>
|
<string name="settings_monitor_mode_always_label">Selalu</string>
|
||||||
@@ -88,10 +89,13 @@
|
|||||||
<string name="settings_scanner_mode_balanced_label">Seimbang</string>
|
<string name="settings_scanner_mode_balanced_label">Seimbang</string>
|
||||||
<string name="settings_scanner_mode_lowlatency_label">Latemsi rendah</string>
|
<string name="settings_scanner_mode_lowlatency_label">Latemsi rendah</string>
|
||||||
<string name="settings_autopause_label">Jeda otomatis</string>
|
<string name="settings_autopause_label">Jeda otomatis</string>
|
||||||
|
<string name="settings_autopause_description">Jeda audio saat melepaskan perangkat dari telinga anda.</string>
|
||||||
<string name="settings_showall_label">Tampilkan semua perangkat</string>
|
<string name="settings_showall_label">Tampilkan semua perangkat</string>
|
||||||
<string name="settings_showall_description">Tampilkan perangkat orang lain yang ada di dekat anda.</string>
|
<string name="settings_showall_description">Tampilkan perangkat orang lain yang ada di dekat anda.</string>
|
||||||
<string name="settings_autopplay_label">Putar otomatis</string>
|
<string name="settings_autopplay_label">Putar otomatis</string>
|
||||||
|
<string name="settings_autoplay_description">Mulai pemutaran audio saat perangkat dipakai.</string>
|
||||||
<string name="settings_fake_data_label">Data palsu</string>
|
<string name="settings_fake_data_label">Data palsu</string>
|
||||||
|
<string name="settings_fake_data_description">Tampilkan data palsu, yaitu, mensimulasikan perangkat yang tidak ada.</string>
|
||||||
<string name="settings_debug_label">Pengaturan debug</string>
|
<string name="settings_debug_label">Pengaturan debug</string>
|
||||||
<string name="settings_debug_description">Pengaturan tambahan untuk membantu memecahkan masalah dengan aplikasi.</string>
|
<string name="settings_debug_description">Pengaturan tambahan untuk membantu memecahkan masalah dengan aplikasi.</string>
|
||||||
<string name="settings_signal_minimum_label">Kualitas sinyal minimum</string>
|
<string name="settings_signal_minimum_label">Kualitas sinyal minimum</string>
|
||||||
@@ -118,6 +122,7 @@
|
|||||||
<string name="overview_bluetooth_disabled_label">Bluetooth dinonaktifkan</string>
|
<string name="overview_bluetooth_disabled_label">Bluetooth dinonaktifkan</string>
|
||||||
<string name="overview_bluetooth_disabled_description">Bluetooth dinonaktifkan, aktifkan terlebih dahulu ;)</string>
|
<string name="overview_bluetooth_disabled_description">Bluetooth dinonaktifkan, aktifkan terlebih dahulu ;)</string>
|
||||||
<string name="help_translate_label">Terjemahan</string>
|
<string name="help_translate_label">Terjemahan</string>
|
||||||
|
<string name="help_translate_description">Bantu terjemahkan applikasi ini ke bahasa favorit anda.</string>
|
||||||
<string name="settings_onepod_mode_label">Mode satu pod</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_onepod_mode_description">Menggunakan kedua pod tidak diperlukan, memakai satu pod sudah cukup untuk memicu reaksi.</string>
|
||||||
<string name="permission_system_alert_window_label">Jendela Peringatan Sistem</string>
|
<string name="permission_system_alert_window_label">Jendela Peringatan Sistem</string>
|
||||||
@@ -127,4 +132,6 @@
|
|||||||
<string name="settings_blescanner_unfiltered_label">Data BLE yang tidak difilter</string>
|
<string name="settings_blescanner_unfiltered_label">Data BLE yang tidak difilter</string>
|
||||||
<string name="settings_blescanner_unfiltered_description">Hapus semua filter dari pemindai BLE untuk menampilkan semua data BLE yang disiarkan. Berguna untuk menambahkan dukungan pada jenis headphone baru.</string>
|
<string name="settings_blescanner_unfiltered_description">Hapus semua filter dari pemindai BLE untuk menampilkan semua data BLE yang disiarkan. Berguna untuk menambahkan dukungan pada jenis headphone baru.</string>
|
||||||
<string name="permission_required_title">Izin berikut diperlukan:</string>
|
<string name="permission_required_title">Izin berikut diperlukan:</string>
|
||||||
|
<string name="settings_compatibility_mode_label">Mode kompatibilitas</string>
|
||||||
|
<string name="settings_compatibility_mode_description">Nonaktifkan pengoptimalan untuk meningkatkan kompatibilitas. Coba ini jika anda tidak melihat data apa pun.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
<string name="settings_general_description">Modifiche generali che riguardano l\'intera applicazione.</string>
|
<string name="settings_general_description">Modifiche generali che riguardano l\'intera applicazione.</string>
|
||||||
<string name="settings_acknowledgements_label">Riconoscimenti</string>
|
<string name="settings_acknowledgements_label">Riconoscimenti</string>
|
||||||
<string name="changelog_label">Changelog</string>
|
<string name="changelog_label">Changelog</string>
|
||||||
<string name="settings_support_email_developer_label">Email sviluppatore</string>
|
<string name="settings_support_email_developer_label" comment="settings_support_email_developer_label Pressing this setting will open your default email app with a template for a mail to me and some device info (e.g. versions).">Email sviluppatore</string>
|
||||||
<string name="settings_support_installid_label">ID installazione</string>
|
<string name="settings_support_installid_label">ID installazione</string>
|
||||||
<string name="settings_support_installid_desc">Le segnalazioni automatiche degli errori sono anonime. Condividi il tuo ID di installazione con lo sviluppatore se necessità di trovare la tua segnalazione all\'interno del registro segnalazioni.</string>
|
<string name="settings_support_installid_desc">Le segnalazioni automatiche degli errori sono anonime. Condividi il tuo ID di installazione con lo sviluppatore se necessità di trovare la tua segnalazione all\'interno del registro segnalazioni.</string>
|
||||||
<string name="settings_support_label">Supporto</string>
|
<string name="settings_support_label">Supporto</string>
|
||||||
@@ -93,7 +93,9 @@
|
|||||||
<string name="settings_showall_label">Mostra tutti i dispositivi</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_showall_description">Mostra i dispositivi delle altre persone vicine a te.</string>
|
||||||
<string name="settings_autopplay_label">Riproduzione automatica</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 immaginari</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_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_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_label">Qualità del segnale minima</string>
|
||||||
@@ -128,6 +130,9 @@
|
|||||||
<string name="last_seen_x">Ultimo accesso: %s</string>
|
<string name="last_seen_x">Ultimo accesso: %s</string>
|
||||||
<string name="first_seen_x">Primo accesso: %s</string>
|
<string name="first_seen_x">Primo accesso: %s</string>
|
||||||
<string name="settings_blescanner_unfiltered_label">Dati BLE non filtrati</string>
|
<string name="settings_blescanner_unfiltered_label">Dati BLE non filtrati</string>
|
||||||
|
<string name="settings_blescanner_unfiltered_description">Rimuovi eventuali filtri dallo scanner BLE per mostrate tutti i dati BLE trasmetti. Utile per aggiungere supporto per nuovi tipi di cuffie.</string>
|
||||||
<string name="permission_required_title">È richiesta la seguente autorizzazione:</string>
|
<string name="permission_required_title">È richiesta la seguente autorizzazione:</string>
|
||||||
<string name="settings_compatibility_mode_label">Modalità di compatibilità</string>
|
<string name="settings_compatibility_mode_label">Modalità di compatibilità</string>
|
||||||
|
<string name="settings_compatibility_mode_description">Disattiva le ottimizzazioni per migliorare la compatibilità. Prova questa opzione se non vedi alcun dato.</string>
|
||||||
|
<string name="translators_thanks_title">Traduttori</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<string name="general_done_action">בוצע</string>
|
<string name="general_done_action">בוצע</string>
|
||||||
<string name="general_copy_action">העתק</string>
|
<string name="general_copy_action">העתק</string>
|
||||||
<string name="general_thank_you_label">תודה רבה</string>
|
<string name="general_thank_you_label">תודה רבה</string>
|
||||||
<string name="general_value_not_available_label">לא ישים</string>
|
<string name="general_value_not_available_label">לא זמין</string>
|
||||||
<string name="general_grant_permission_action">מתן רשות</string>
|
<string name="general_grant_permission_action">מתן רשות</string>
|
||||||
<string name="general_upgrade_action">שידרוג</string>
|
<string name="general_upgrade_action">שידרוג</string>
|
||||||
<string name="general_check_action">בדיקה</string>
|
<string name="general_check_action">בדיקה</string>
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
<string name="settings_general_description">שינויים כלליים שמשפיעים על האפליקציה כולה.</string>
|
<string name="settings_general_description">שינויים כלליים שמשפיעים על האפליקציה כולה.</string>
|
||||||
<string name="settings_acknowledgements_label">תודות</string>
|
<string name="settings_acknowledgements_label">תודות</string>
|
||||||
<string name="changelog_label">יומן שינויים</string>
|
<string name="changelog_label">יומן שינויים</string>
|
||||||
<string name="settings_support_email_developer_label">אימייל של המפתח</string>
|
<string name="settings_support_email_developer_label" comment="settings_support_email_developer_label Pressing this setting will open your default email app with a template for a mail to me and some device info (e.g. versions).">אימייל של המפתח</string>
|
||||||
<string name="settings_support_installid_label">מזהה התקנה</string>
|
<string name="settings_support_installid_label">מזהה התקנה</string>
|
||||||
<string name="settings_support_installid_desc">דוחות שגיאה אוטומטיים הם אנונימיים. שתף את מזהה ההתקנה שלך אם המפתח צריך למצוא את דוחות השגיאות שלך.</string>
|
<string name="settings_support_installid_desc">דוחות שגיאה אוטומטיים הם אנונימיים. שתף את מזהה ההתקנה שלך אם המפתח צריך למצוא את דוחות השגיאות שלך.</string>
|
||||||
<string name="settings_support_label">תמיכה</string>
|
<string name="settings_support_label">תמיכה</string>
|
||||||
@@ -134,4 +134,6 @@
|
|||||||
<string name="permission_required_title">ההרשאה הבאה נדרשת:</string>
|
<string name="permission_required_title">ההרשאה הבאה נדרשת:</string>
|
||||||
<string name="settings_compatibility_mode_label">מצב תאימות</string>
|
<string name="settings_compatibility_mode_label">מצב תאימות</string>
|
||||||
<string name="settings_compatibility_mode_description">נטרול אופטימיזציה לשיפור התאימות. נסו את זה אם לא מוצגים נתונים כלל.</string>
|
<string name="settings_compatibility_mode_description">נטרול אופטימיזציה לשיפור התאימות. נסו את זה אם לא מוצגים נתונים כלל.</string>
|
||||||
|
<string name="translators_thanks_title">מתרגמים</string>
|
||||||
|
<string name="translators_thanks_description" comment="translators_thanks_description You can voluntarily add your name here to have it displayed in the app. It will be shown in the Settings>Acknowledgements>Thank you section. Separate names by semicolons and an optional email may be included in brackets, example: darken(darken@darken.eu);John Doe(john@example.com) "darken" is just a placeholder and does not have to be kept if/when you add yours. Be nice to each other!">AL_Cool_T</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
<string name="settings_general_description">앱 전체에 영향을 주는 일반적인 설정들입니다.</string>
|
<string name="settings_general_description">앱 전체에 영향을 주는 일반적인 설정들입니다.</string>
|
||||||
<string name="settings_acknowledgements_label">감사의 말</string>
|
<string name="settings_acknowledgements_label">감사의 말</string>
|
||||||
<string name="changelog_label">체인지로그</string>
|
<string name="changelog_label">체인지로그</string>
|
||||||
<string name="settings_support_email_developer_label">개발자에게 메일 보내기</string>
|
<string name="settings_support_email_developer_label" comment="settings_support_email_developer_label Pressing this setting will open your default email app with a template for a mail to me and some device info (e.g. versions).">개발자에게 메일 보내기</string>
|
||||||
<string name="settings_support_installid_label">설치 ID</string>
|
<string name="settings_support_installid_label">설치 ID</string>
|
||||||
<string name="settings_support_installid_desc">자동 오류 보고는 익명성이 보장됩니다. 개발자가 오류 보고서를 필요로 할 때 설치 ID를 알려주세요.</string>
|
<string name="settings_support_installid_desc">자동 오류 보고는 익명성이 보장됩니다. 개발자가 오류 보고서를 필요로 할 때 설치 ID를 알려주세요.</string>
|
||||||
<string name="settings_support_label">지원</string>
|
<string name="settings_support_label">지원</string>
|
||||||
@@ -134,4 +134,6 @@
|
|||||||
<string name="permission_required_title">다음 권한을 부여해야 합니다:</string>
|
<string name="permission_required_title">다음 권한을 부여해야 합니다:</string>
|
||||||
<string name="settings_compatibility_mode_label">호환성 모드</string>
|
<string name="settings_compatibility_mode_label">호환성 모드</string>
|
||||||
<string name="settings_compatibility_mode_description">최적화 설정들 몇 개를 비활성화해 호환성을 높입니다. 데이터가 보이지 않을 때 사용하세요.</string>
|
<string name="settings_compatibility_mode_description">최적화 설정들 몇 개를 비활성화해 호환성을 높입니다. 데이터가 보이지 않을 때 사용하세요.</string>
|
||||||
|
<string name="translators_thanks_title">번역가</string>
|
||||||
|
<string name="translators_thanks_description" comment="translators_thanks_description You can voluntarily add your name here to have it displayed in the app. It will be shown in the Settings>Acknowledgements>Thank you section. Separate names by semicolons and an optional email may be included in brackets, example: darken(darken@darken.eu);John Doe(john@example.com) "darken" is just a placeholder and does not have to be kept if/when you add yours. Be nice to each other!">윤지호(annyeong1alt@gmail.com)</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
<string name="settings_general_description">Tweak umum yang mempengaruhi keseluruhan apl.</string>
|
<string name="settings_general_description">Tweak umum yang mempengaruhi keseluruhan apl.</string>
|
||||||
<string name="settings_acknowledgements_label">Ucapan terima kasih</string>
|
<string name="settings_acknowledgements_label">Ucapan terima kasih</string>
|
||||||
<string name="changelog_label">Changelog</string>
|
<string name="changelog_label">Changelog</string>
|
||||||
<string name="settings_support_email_developer_label">Pembangun e-mel</string>
|
<string name="settings_support_email_developer_label" comment="settings_support_email_developer_label Pressing this setting will open your default email app with a template for a mail to me and some device info (e.g. versions).">Pembangun e-mel</string>
|
||||||
<string name="settings_support_installid_label">Pasang ID</string>
|
<string name="settings_support_installid_label">Pasang ID</string>
|
||||||
<string name="settings_support_installid_desc">Laporan ralat automatik adalah tanpa nama. Kongsi ID pemasangan anda jika pembangun perlu mencari laporan ralat anda.</string>
|
<string name="settings_support_installid_desc">Laporan ralat automatik adalah tanpa nama. Kongsi ID pemasangan anda jika pembangun perlu mencari laporan ralat anda.</string>
|
||||||
<string name="settings_support_label">Sokongan</string>
|
<string name="settings_support_label">Sokongan</string>
|
||||||
@@ -134,4 +134,6 @@
|
|||||||
<string name="permission_required_title">Kebenaran berikut diperlukan:</string>
|
<string name="permission_required_title">Kebenaran berikut diperlukan:</string>
|
||||||
<string name="settings_compatibility_mode_label">Mod keserasian</string>
|
<string name="settings_compatibility_mode_label">Mod keserasian</string>
|
||||||
<string name="settings_compatibility_mode_description">Nyahdayakan pengoptimuman untuk tingkatkan keserasian. Cuba ini jika anda tidak melihat sebarang data.</string>
|
<string name="settings_compatibility_mode_description">Nyahdayakan pengoptimuman untuk tingkatkan keserasian. Cuba ini jika anda tidak melihat sebarang data.</string>
|
||||||
|
<string name="translators_thanks_title">Penterjemah</string>
|
||||||
|
<string name="translators_thanks_description" comment="translators_thanks_description You can voluntarily add your name here to have it displayed in the app. It will be shown in the Settings>Acknowledgements>Thank you section. Separate names by semicolons and an optional email may be included in brackets, example: darken(darken@darken.eu);John Doe(john@example.com) "darken" is just a placeholder and does not have to be kept if/when you add yours. Be nice to each other!">bob hasnul(bobhasnul@gmail. com)</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
<string name="settings_general_description">Algemene aanpassingen die de hele app beïnvloeden.</string>
|
<string name="settings_general_description">Algemene aanpassingen die de hele app beïnvloeden.</string>
|
||||||
<string name="settings_acknowledgements_label">Dankbetuigingen</string>
|
<string name="settings_acknowledgements_label">Dankbetuigingen</string>
|
||||||
<string name="changelog_label">Wijzigingslog</string>
|
<string name="changelog_label">Wijzigingslog</string>
|
||||||
<string name="settings_support_email_developer_label">E-mailontwikkelaar</string>
|
<string name="settings_support_email_developer_label" comment="settings_support_email_developer_label Pressing this setting will open your default email app with a template for a mail to me and some device info (e.g. versions).">E-mailontwikkelaar</string>
|
||||||
<string name="settings_support_installid_label">Installatie-ID</string>
|
<string name="settings_support_installid_label">Installatie-ID</string>
|
||||||
<string name="settings_support_installid_desc">Automatische foutmeldingen zijn anoniem. Deel uw installatie-ID als de ontwikkelaar uw foutrapporten moet vinden.</string>
|
<string name="settings_support_installid_desc">Automatische foutmeldingen zijn anoniem. Deel uw installatie-ID als de ontwikkelaar uw foutrapporten moet vinden.</string>
|
||||||
<string name="settings_support_label">Ondersteuning</string>
|
<string name="settings_support_label">Ondersteuning</string>
|
||||||
@@ -81,6 +81,7 @@
|
|||||||
<string name="settings_monitor_mode_label">Monitor modus</string>
|
<string name="settings_monitor_mode_label">Monitor modus</string>
|
||||||
<string name="settings_monitor_mode_description">Onder welke omstandigheden houdt deze app Bluetooth-gegevens bij.</string>
|
<string name="settings_monitor_mode_description">Onder welke omstandigheden houdt deze app Bluetooth-gegevens bij.</string>
|
||||||
<string name="settings_scanner_mode_label">Scannermodus</string>
|
<string name="settings_scanner_mode_label">Scannermodus</string>
|
||||||
|
<string name="settings_scanner_mode_description">Moet de Bluetooth Low Energy-gegevensscanner prioriteit geven aan prestaties of energie besparen?</string>
|
||||||
<string name="settings_monitor_mode_manual_label">Wanneer app is geopend</string>
|
<string name="settings_monitor_mode_manual_label">Wanneer app is geopend</string>
|
||||||
<string name="settings_monitor_mode_automatic_label">Wanneer het apparaat is aangesloten</string>
|
<string name="settings_monitor_mode_automatic_label">Wanneer het apparaat is aangesloten</string>
|
||||||
<string name="settings_monitor_mode_always_label">Altijd</string>
|
<string name="settings_monitor_mode_always_label">Altijd</string>
|
||||||
@@ -88,10 +89,13 @@
|
|||||||
<string name="settings_scanner_mode_balanced_label">Gebalanceerd</string>
|
<string name="settings_scanner_mode_balanced_label">Gebalanceerd</string>
|
||||||
<string name="settings_scanner_mode_lowlatency_label">Lage latentie</string>
|
<string name="settings_scanner_mode_lowlatency_label">Lage latentie</string>
|
||||||
<string name="settings_autopause_label">Auto pauze</string>
|
<string name="settings_autopause_label">Auto pauze</string>
|
||||||
|
<string name="settings_autopause_description">Pauzeer de muziek wanneer u het apparaat van uw oor haalt.</string>
|
||||||
<string name="settings_showall_label">Alle apparaten weergeven</string>
|
<string name="settings_showall_label">Alle apparaten weergeven</string>
|
||||||
<string name="settings_showall_description">Toon apparaten van andere mensen die bij u in de buurt zijn.</string>
|
<string name="settings_showall_description">Toon apparaten van andere mensen die bij u in de buurt zijn.</string>
|
||||||
<string name="settings_autopplay_label">Automatisch afspelen</string>
|
<string name="settings_autopplay_label">Automatisch afspelen</string>
|
||||||
|
<string name="settings_autoplay_description">Start audioweergave wanneer het apparaat wordt gedragen.</string>
|
||||||
<string name="settings_fake_data_label">Nep gegevens</string>
|
<string name="settings_fake_data_label">Nep gegevens</string>
|
||||||
|
<string name="settings_fake_data_description">Toon nepgegevens, d.w.z. simuleer apparaten die niet bestaan.</string>
|
||||||
<string name="settings_debug_label">Foutopsporingsinstellingen</string>
|
<string name="settings_debug_label">Foutopsporingsinstellingen</string>
|
||||||
<string name="settings_debug_description">Aanvullende instellingen voor het oplossen van problemen met de app.</string>
|
<string name="settings_debug_description">Aanvullende instellingen voor het oplossen van problemen met de app.</string>
|
||||||
<string name="settings_signal_minimum_label">Minimale signaalkwaliteit</string>
|
<string name="settings_signal_minimum_label">Minimale signaalkwaliteit</string>
|
||||||
@@ -118,6 +122,7 @@
|
|||||||
<string name="overview_bluetooth_disabled_label">Bluetooth is uitgeschakeld</string>
|
<string name="overview_bluetooth_disabled_label">Bluetooth is uitgeschakeld</string>
|
||||||
<string name="overview_bluetooth_disabled_description">Bluetooth is uitgeschakeld, activeer het ;)</string>
|
<string name="overview_bluetooth_disabled_description">Bluetooth is uitgeschakeld, activeer het ;)</string>
|
||||||
<string name="help_translate_label">Vertaling</string>
|
<string name="help_translate_label">Vertaling</string>
|
||||||
|
<string name="help_translate_description">Help deze app te vertalen in uw favoriete taal.</string>
|
||||||
<string name="settings_onepod_mode_label">Eén pod-modus</string>
|
<string name="settings_onepod_mode_label">Eén pod-modus</string>
|
||||||
<string name="settings_onepod_mode_description">Het dragen van beide pods is niet vereist, het dragen van een enkele pod is voldoende om reacties uit te lokken.</string>
|
<string name="settings_onepod_mode_description">Het dragen van beide pods is niet vereist, het dragen van een enkele pod is voldoende om reacties uit te lokken.</string>
|
||||||
<string name="permission_system_alert_window_label">Systeemwaarschuwingsvenster</string>
|
<string name="permission_system_alert_window_label">Systeemwaarschuwingsvenster</string>
|
||||||
@@ -127,4 +132,8 @@
|
|||||||
<string name="settings_blescanner_unfiltered_label">Ongefilterde BLE-gegevens</string>
|
<string name="settings_blescanner_unfiltered_label">Ongefilterde BLE-gegevens</string>
|
||||||
<string name="settings_blescanner_unfiltered_description">Verwijder eventuele filters van de BLE-scanner om alle uitgezonden BLE-gegevens weer te geven. Handig om ondersteuning toe te voegen voor nieuwe typen hoofdtelefoons.</string>
|
<string name="settings_blescanner_unfiltered_description">Verwijder eventuele filters van de BLE-scanner om alle uitgezonden BLE-gegevens weer te geven. Handig om ondersteuning toe te voegen voor nieuwe typen hoofdtelefoons.</string>
|
||||||
<string name="permission_required_title">De volgende toestemming is vereist:</string>
|
<string name="permission_required_title">De volgende toestemming is vereist:</string>
|
||||||
|
<string name="settings_compatibility_mode_label">Compatibiliteitsmodus</string>
|
||||||
|
<string name="settings_compatibility_mode_description">Schakel optimalisaties uit om de compatibiliteit te verbeteren. Probeer dit als u geen gegevens ziet.</string>
|
||||||
|
<string name="translators_thanks_title">Vertalers</string>
|
||||||
|
<string name="translators_thanks_description" comment="translators_thanks_description You can voluntarily add your name here to have it displayed in the app. It will be shown in the Settings>Acknowledgements>Thank you section. Separate names by semicolons and an optional email may be included in brackets, example: darken(darken@darken.eu);John Doe(john@example.com) "darken" is just a placeholder and does not have to be kept if/when you add yours. Be nice to each other!">darken</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
<string name="settings_general_description">Generelle justeringer som påvirker hele appen.</string>
|
<string name="settings_general_description">Generelle justeringer som påvirker hele appen.</string>
|
||||||
<string name="settings_acknowledgements_label">Anerkjennelser</string>
|
<string name="settings_acknowledgements_label">Anerkjennelser</string>
|
||||||
<string name="changelog_label">Endringslogg</string>
|
<string name="changelog_label">Endringslogg</string>
|
||||||
<string name="settings_support_email_developer_label">Send e-post til utvikler</string>
|
<string name="settings_support_email_developer_label" comment="settings_support_email_developer_label Pressing this setting will open your default email app with a template for a mail to me and some device info (e.g. versions).">Send e-post til utvikler</string>
|
||||||
<string name="settings_support_installid_label">Installasjons-ID</string>
|
<string name="settings_support_installid_label">Installasjons-ID</string>
|
||||||
<string name="settings_support_installid_desc">Automatiske feilrapporter er anonyme. Del installasjons-ID-en din hvis utvikleren skal finne feilrapportene dine.</string>
|
<string name="settings_support_installid_desc">Automatiske feilrapporter er anonyme. Del installasjons-ID-en din hvis utvikleren skal finne feilrapportene dine.</string>
|
||||||
<string name="settings_support_label">Brukerstøtte</string>
|
<string name="settings_support_label">Brukerstøtte</string>
|
||||||
@@ -134,4 +134,6 @@
|
|||||||
<string name="permission_required_title">Følgende tillatelse kreves:</string>
|
<string name="permission_required_title">Følgende tillatelse kreves:</string>
|
||||||
<string name="settings_compatibility_mode_label">Kompatibilitetsmodus</string>
|
<string name="settings_compatibility_mode_label">Kompatibilitetsmodus</string>
|
||||||
<string name="settings_compatibility_mode_description">Deaktiver optimaliseringer for å forbedre kompatibiliteten. Prøv dette hvis du ikke ser noen data.</string>
|
<string name="settings_compatibility_mode_description">Deaktiver optimaliseringer for å forbedre kompatibiliteten. Prøv dette hvis du ikke ser noen data.</string>
|
||||||
|
<string name="translators_thanks_title">Oversettere</string>
|
||||||
|
<string name="translators_thanks_description" comment="translators_thanks_description You can voluntarily add your name here to have it displayed in the app. It will be shown in the Settings>Acknowledgements>Thank you section. Separate names by semicolons and an optional email may be included in brackets, example: darken(darken@darken.eu);John Doe(john@example.com) "darken" is just a placeholder and does not have to be kept if/when you add yours. Be nice to each other!">Kristoffer Vassbø(kristoffervassbo@gmail.com)</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
<string name="settings_general_description">Ogólne opcje, które mają wpływ na całą aplikację.</string>
|
<string name="settings_general_description">Ogólne opcje, które mają wpływ na całą aplikację.</string>
|
||||||
<string name="settings_acknowledgements_label">Podziękowania</string>
|
<string name="settings_acknowledgements_label">Podziękowania</string>
|
||||||
<string name="changelog_label">Lista zmian</string>
|
<string name="changelog_label">Lista zmian</string>
|
||||||
<string name="settings_support_email_developer_label">E-mail autora</string>
|
<string name="settings_support_email_developer_label" comment="settings_support_email_developer_label Pressing this setting will open your default email app with a template for a mail to me and some device info (e.g. versions).">E-mail autora</string>
|
||||||
<string name="settings_support_installid_label">ID instalacji</string>
|
<string name="settings_support_installid_label">ID instalacji</string>
|
||||||
<string name="settings_support_installid_desc">Automatyczne raporty błędów są anonimowe. Udostępni swoje ID instalacji, aby autor mógł znaleźć twój raport błędu.</string>
|
<string name="settings_support_installid_desc">Automatyczne raporty błędów są anonimowe. Udostępni swoje ID instalacji, aby autor mógł znaleźć twój raport błędu.</string>
|
||||||
<string name="settings_support_label">Wsparcie</string>
|
<string name="settings_support_label">Wsparcie</string>
|
||||||
@@ -134,4 +134,6 @@
|
|||||||
<string name="permission_required_title">Następujące uprawnienie jest wymagane:</string>
|
<string name="permission_required_title">Następujące uprawnienie jest wymagane:</string>
|
||||||
<string name="settings_compatibility_mode_label">Tryb kompatybilność</string>
|
<string name="settings_compatibility_mode_label">Tryb kompatybilność</string>
|
||||||
<string name="settings_compatibility_mode_description">Wyłącza optymalizacje, aby poprawić kompatybilność. Wypróbuj, jeśli nie widzisz żadnych danych.</string>
|
<string name="settings_compatibility_mode_description">Wyłącza optymalizacje, aby poprawić kompatybilność. Wypróbuj, jeśli nie widzisz żadnych danych.</string>
|
||||||
|
<string name="translators_thanks_title">Tłumacze</string>
|
||||||
|
<string name="translators_thanks_description" comment="translators_thanks_description You can voluntarily add your name here to have it displayed in the app. It will be shown in the Settings>Acknowledgements>Thank you section. Separate names by semicolons and an optional email may be included in brackets, example: darken(darken@darken.eu);John Doe(john@example.com) "darken" is just a placeholder and does not have to be kept if/when you add yours. Be nice to each other!">darken; K4r0lSz;</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -62,9 +62,9 @@
|
|||||||
<string name="settings_category_other_label">Outros</string>
|
<string name="settings_category_other_label">Outros</string>
|
||||||
<string name="settings_general_label">Configurações</string>
|
<string name="settings_general_label">Configurações</string>
|
||||||
<string name="settings_general_description">Ajustes gerais que afetam todo o aplicativo.</string>
|
<string name="settings_general_description">Ajustes gerais que afetam todo o aplicativo.</string>
|
||||||
<string name="settings_acknowledgements_label">Reconhecimentos</string>
|
<string name="settings_acknowledgements_label">Agradecimentos</string>
|
||||||
<string name="changelog_label">Registro de alterações</string>
|
<string name="changelog_label">Registro de alterações</string>
|
||||||
<string name="settings_support_email_developer_label">Email do desenvolvedor</string>
|
<string name="settings_support_email_developer_label" comment="settings_support_email_developer_label Pressing this setting will open your default email app with a template for a mail to me and some device info (e.g. versions).">Email do desenvolvedor</string>
|
||||||
<string name="settings_support_installid_label">ID de instalação</string>
|
<string name="settings_support_installid_label">ID de instalação</string>
|
||||||
<string name="settings_support_installid_desc">Os relatórios automáticos de erros são anônimos. Compartilhe seu ID de instalação se o desenvolvedor precisar encontrar seus relatórios de erros.</string>
|
<string name="settings_support_installid_desc">Os relatórios automáticos de erros são anônimos. Compartilhe seu ID de instalação se o desenvolvedor precisar encontrar seus relatórios de erros.</string>
|
||||||
<string name="settings_support_label">Suporte</string>
|
<string name="settings_support_label">Suporte</string>
|
||||||
@@ -134,4 +134,6 @@
|
|||||||
<string name="permission_required_title">A seguinte permissão é necessária:</string>
|
<string name="permission_required_title">A seguinte permissão é necessária:</string>
|
||||||
<string name="settings_compatibility_mode_label">Modo de compatibilidade</string>
|
<string name="settings_compatibility_mode_label">Modo de compatibilidade</string>
|
||||||
<string name="settings_compatibility_mode_description">Desative as otimizações para melhorar a compatibilidade. Tente isso se você não estiver vendo nenhum dado.</string>
|
<string name="settings_compatibility_mode_description">Desative as otimizações para melhorar a compatibilidade. Tente isso se você não estiver vendo nenhum dado.</string>
|
||||||
|
<string name="translators_thanks_title">Tradutores</string>
|
||||||
|
<string name="translators_thanks_description" comment="translators_thanks_description You can voluntarily add your name here to have it displayed in the app. It will be shown in the Settings>Acknowledgements>Thank you section. Separate names by semicolons and an optional email may be included in brackets, example: darken(darken@darken.eu);John Doe(john@example.com) "darken" is just a placeholder and does not have to be kept if/when you add yours. Be nice to each other!">Igor Silva(ferrare42@gmail.com)</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
<string name="settings_general_description">Общие настройки, влияющие на всё приложение.</string>
|
<string name="settings_general_description">Общие настройки, влияющие на всё приложение.</string>
|
||||||
<string name="settings_acknowledgements_label">Благодарности</string>
|
<string name="settings_acknowledgements_label">Благодарности</string>
|
||||||
<string name="changelog_label">История изменений</string>
|
<string name="changelog_label">История изменений</string>
|
||||||
<string name="settings_support_email_developer_label">Написать разработчику</string>
|
<string name="settings_support_email_developer_label" comment="settings_support_email_developer_label Pressing this setting will open your default email app with a template for a mail to me and some device info (e.g. versions).">Написать разработчику</string>
|
||||||
<string name="settings_support_installid_label">ID установки</string>
|
<string name="settings_support_installid_label">ID установки</string>
|
||||||
<string name="settings_support_installid_desc">Автоматические отчёты об ошибках анонимны. Поделитесь Вашим ID установки, если разработчику нужен доступ к Вашим отчётам об ошибках.</string>
|
<string name="settings_support_installid_desc">Автоматические отчёты об ошибках анонимны. Поделитесь Вашим ID установки, если разработчику нужен доступ к Вашим отчётам об ошибках.</string>
|
||||||
<string name="settings_support_label">Поддержка</string>
|
<string name="settings_support_label">Поддержка</string>
|
||||||
@@ -134,4 +134,6 @@
|
|||||||
<string name="permission_required_title">Требуется следующее разрешение:</string>
|
<string name="permission_required_title">Требуется следующее разрешение:</string>
|
||||||
<string name="settings_compatibility_mode_label">Режим совместимости</string>
|
<string name="settings_compatibility_mode_label">Режим совместимости</string>
|
||||||
<string name="settings_compatibility_mode_description">Отключите оптимизацию для улучшения совместимости. Попробуйте это, если не видите данных.</string>
|
<string name="settings_compatibility_mode_description">Отключите оптимизацию для улучшения совместимости. Попробуйте это, если не видите данных.</string>
|
||||||
|
<string name="translators_thanks_title">Переводчики</string>
|
||||||
|
<string name="translators_thanks_description" comment="translators_thanks_description You can voluntarily add your name here to have it displayed in the app. It will be shown in the Settings>Acknowledgements>Thank you section. Separate names by semicolons and an optional email may be included in brackets, example: darken(darken@darken.eu);John Doe(john@example.com) "darken" is just a placeholder and does not have to be kept if/when you add yours. Be nice to each other!">AL_Cool_T</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
<string name="settings_general_description">Všeobecné vylepšenia, ktoré ovplyvňujú celú aplikáciu.</string>
|
<string name="settings_general_description">Všeobecné vylepšenia, ktoré ovplyvňujú celú aplikáciu.</string>
|
||||||
<string name="settings_acknowledgements_label">Poďakovania</string>
|
<string name="settings_acknowledgements_label">Poďakovania</string>
|
||||||
<string name="changelog_label">Zoznam zmien</string>
|
<string name="changelog_label">Zoznam zmien</string>
|
||||||
<string name="settings_support_email_developer_label">E-mail vývojárovi</string>
|
<string name="settings_support_email_developer_label" comment="settings_support_email_developer_label Pressing this setting will open your default email app with a template for a mail to me and some device info (e.g. versions).">E-mail vývojárovi</string>
|
||||||
<string name="settings_support_installid_label">ID inštalácie</string>
|
<string name="settings_support_installid_label">ID inštalácie</string>
|
||||||
<string name="settings_support_installid_desc">Automatické chybové hlásenia sú anonymné. Zdieľajte svoje ID inštalácie, ak vývojár potrebuje nájsť vaše chybové hlásenia.</string>
|
<string name="settings_support_installid_desc">Automatické chybové hlásenia sú anonymné. Zdieľajte svoje ID inštalácie, ak vývojár potrebuje nájsť vaše chybové hlásenia.</string>
|
||||||
<string name="settings_support_label">Podpora</string>
|
<string name="settings_support_label">Podpora</string>
|
||||||
@@ -134,4 +134,6 @@
|
|||||||
<string name="permission_required_title">Vyžaduje sa nasledujúce povolenie:</string>
|
<string name="permission_required_title">Vyžaduje sa nasledujúce povolenie:</string>
|
||||||
<string name="settings_compatibility_mode_label">Režim kompatibility</string>
|
<string name="settings_compatibility_mode_label">Režim kompatibility</string>
|
||||||
<string name="settings_compatibility_mode_description">Zakázať optimalizáciu na zlepšenie kompatibility. Skúste to, ak nevidíte žiadne údaje.</string>
|
<string name="settings_compatibility_mode_description">Zakázať optimalizáciu na zlepšenie kompatibility. Skúste to, ak nevidíte žiadne údaje.</string>
|
||||||
|
<string name="translators_thanks_title">Prekladatelia</string>
|
||||||
|
<string name="translators_thanks_description" comment="translators_thanks_description You can voluntarily add your name here to have it displayed in the app. It will be shown in the Settings>Acknowledgements>Thank you section. Separate names by semicolons and an optional email may be included in brackets, example: darken(darken@darken.eu);John Doe(john@example.com) "darken" is just a placeholder and does not have to be kept if/when you add yours. Be nice to each other!">dukelc</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
<string name="settings_general_description">Tüm uygulamayı etkileyen genel düzenlemeler.</string>
|
<string name="settings_general_description">Tüm uygulamayı etkileyen genel düzenlemeler.</string>
|
||||||
<string name="settings_acknowledgements_label">Teşekkür</string>
|
<string name="settings_acknowledgements_label">Teşekkür</string>
|
||||||
<string name="changelog_label">Değişiklik Günlüğü</string>
|
<string name="changelog_label">Değişiklik Günlüğü</string>
|
||||||
<string name="settings_support_email_developer_label">E-posta geliştiricisi</string>
|
<string name="settings_support_email_developer_label" comment="settings_support_email_developer_label Pressing this setting will open your default email app with a template for a mail to me and some device info (e.g. versions).">E-posta geliştiricisi</string>
|
||||||
<string name="settings_support_installid_label">Yükleme Kimliği</string>
|
<string name="settings_support_installid_label">Yükleme Kimliği</string>
|
||||||
<string name="settings_support_installid_desc">Otomatik hata raporları anonimdir. Geliştiricinin hata raporlarınızı bulması gerekiyorsa yükleme kimliğinizi paylaşın.</string>
|
<string name="settings_support_installid_desc">Otomatik hata raporları anonimdir. Geliştiricinin hata raporlarınızı bulması gerekiyorsa yükleme kimliğinizi paylaşın.</string>
|
||||||
<string name="settings_support_label">Destek</string>
|
<string name="settings_support_label">Destek</string>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">CAPod</string>
|
<string name="app_name">CAPod</string>
|
||||||
<string name="app_name_pro">CAPod Професійна</string>
|
<string name="app_name_pro">CAPod Професійна</string>
|
||||||
|
<string name="app_name_foss">CAPod FOSS</string>
|
||||||
<string name="notification_channel_device_status_label">Статус пристрою</string>
|
<string name="notification_channel_device_status_label">Статус пристрою</string>
|
||||||
<string name="general_error_label">Помилка</string>
|
<string name="general_error_label">Помилка</string>
|
||||||
<string name="general_share_action">Поділитися</string>
|
<string name="general_share_action">Поділитися</string>
|
||||||
@@ -14,6 +15,7 @@
|
|||||||
<string name="general_check_action">Перевірити</string>
|
<string name="general_check_action">Перевірити</string>
|
||||||
<string name="general_close_action">Зачинити</string>
|
<string name="general_close_action">Зачинити</string>
|
||||||
<string name="debug_debuglog_size_label">Розмір</string>
|
<string name="debug_debuglog_size_label">Розмір</string>
|
||||||
|
<string name="debug_debuglog_size_compressed_label">Стиснутий розмір</string>
|
||||||
<string name="permission_bluetooth_label">Bluetooth</string>
|
<string name="permission_bluetooth_label">Bluetooth</string>
|
||||||
<string name="permission_access_fine_location_label">Доступ до точного місцезнаходження</string>
|
<string name="permission_access_fine_location_label">Доступ до точного місцезнаходження</string>
|
||||||
<string name="permission_background_location_label">Доступ до місцезнаходження у тлі</string>
|
<string name="permission_background_location_label">Доступ до місцезнаходження у тлі</string>
|
||||||
@@ -29,6 +31,7 @@
|
|||||||
<string name="pods_connection_state_call_label">У режимі виклику</string>
|
<string name="pods_connection_state_call_label">У режимі виклику</string>
|
||||||
<string name="pods_connection_state_unknown_label">Невідомий стан з\'єднання</string>
|
<string name="pods_connection_state_unknown_label">Невідомий стан з\'єднання</string>
|
||||||
<string name="pods_unknown_label">Невідомий пристрій</string>
|
<string name="pods_unknown_label">Невідомий пристрій</string>
|
||||||
|
<string name="pods_unknown_contact_dev">Це невідомий пристрій, проте він використовує подібний формат повідомлень. Додаймо його підтримку, надішліть мені лист :)</string>
|
||||||
<string name="pods_none_label_short">Немає пристрою</string>
|
<string name="pods_none_label_short">Немає пристрою</string>
|
||||||
<string name="pods_charging_label">Заряджання</string>
|
<string name="pods_charging_label">Заряджання</string>
|
||||||
<string name="pods_inear_label">У вусі</string>
|
<string name="pods_inear_label">У вусі</string>
|
||||||
@@ -44,16 +47,26 @@
|
|||||||
<string name="settings_general_description">Загальні функції, що впливають на всю програму.</string>
|
<string name="settings_general_description">Загальні функції, що впливають на всю програму.</string>
|
||||||
<string name="settings_acknowledgements_label">Подяки</string>
|
<string name="settings_acknowledgements_label">Подяки</string>
|
||||||
<string name="changelog_label">Список змін</string>
|
<string name="changelog_label">Список змін</string>
|
||||||
<string name="settings_support_email_developer_label">Лист розробнику</string>
|
<string name="settings_support_email_developer_label" comment="settings_support_email_developer_label Pressing this setting will open your default email app with a template for a mail to me and some device info (e.g. versions).">Лист розробнику</string>
|
||||||
<string name="settings_support_label">Підтримка</string>
|
<string name="settings_support_label">Підтримка</string>
|
||||||
<string name="settings_support_description">Якщо необхідна допомога.</string>
|
<string name="settings_support_description">Якщо необхідна допомога.</string>
|
||||||
|
<string name="discord_label">Discord</string>
|
||||||
|
<string name="discord_description">Місце для зависання та задавання питань.</string>
|
||||||
|
<string name="settings_support_email_developer_description">Зауважте, що я можу відповідати лише німецькою або англійською.</string>
|
||||||
<string name="settings_debug_autoreports_label">Автоматичні звіти про помилки</string>
|
<string name="settings_debug_autoreports_label">Автоматичні звіти про помилки</string>
|
||||||
|
<string name="settings_debug_mode_label">Режим налагодження</string>
|
||||||
|
<string name="settings_debug_mode_description">Відображення додаткової інформації щодо помилок.</string>
|
||||||
|
<string name="settings_monitor_mode_label">Режим відстеження</string>
|
||||||
|
<string name="settings_monitor_mode_description">За яких умов ця програма відстежує дані Bluetooth.</string>
|
||||||
|
<string name="settings_scanner_mode_label">Режим сканера</string>
|
||||||
|
<string name="settings_scanner_mode_description">Сканер даних Bluetooth Low Energy має зосередитися на продуктивності чи збереженні заряду батареї?</string>
|
||||||
<string name="settings_monitor_mode_manual_label">Коли програму відкрито</string>
|
<string name="settings_monitor_mode_manual_label">Коли програму відкрито</string>
|
||||||
<string name="settings_monitor_mode_automatic_label">При під\'єднаному пристрої</string>
|
<string name="settings_monitor_mode_automatic_label">При під\'єднаному пристрої</string>
|
||||||
<string name="settings_monitor_mode_always_label">Завжди</string>
|
<string name="settings_monitor_mode_always_label">Завжди</string>
|
||||||
<string name="settings_scanner_mode_lowpower_label">Низький заряд</string>
|
<string name="settings_scanner_mode_lowpower_label">Низький заряд</string>
|
||||||
<string name="settings_scanner_mode_balanced_label">Збалансовано</string>
|
<string name="settings_scanner_mode_balanced_label">Збалансовано</string>
|
||||||
<string name="settings_autopause_label">Автопауза</string>
|
<string name="settings_autopause_label">Автопауза</string>
|
||||||
|
<string name="settings_autopause_description">Зупинка відтворення аудіо, коли навушник прибрано з Вашого вуха.</string>
|
||||||
<string name="settings_showall_label">Показувати усі пристрої</string>
|
<string name="settings_showall_label">Показувати усі пристрої</string>
|
||||||
<string name="settings_showall_description">Відображення пристроїв інших людей побизу Вас.</string>
|
<string name="settings_showall_description">Відображення пристроїв інших людей побизу Вас.</string>
|
||||||
<string name="settings_autopplay_label">Автовідтворення</string>
|
<string name="settings_autopplay_label">Автовідтворення</string>
|
||||||
@@ -82,4 +95,6 @@
|
|||||||
<string name="last_seen_x">Востаннє був: %s</string>
|
<string name="last_seen_x">Востаннє був: %s</string>
|
||||||
<string name="first_seen_x">Уперше був: %s</string>
|
<string name="first_seen_x">Уперше був: %s</string>
|
||||||
<string name="permission_required_title">Необхідні наступні дозволи:</string>
|
<string name="permission_required_title">Необхідні наступні дозволи:</string>
|
||||||
|
<string name="translators_thanks_title">Перекладачі</string>
|
||||||
|
<string name="translators_thanks_description" comment="translators_thanks_description You can voluntarily add your name here to have it displayed in the app. It will be shown in the Settings>Acknowledgements>Thank you section. Separate names by semicolons and an optional email may be included in brackets, example: darken(darken@darken.eu);John Doe(john@example.com) "darken" is just a placeholder and does not have to be kept if/when you add yours. Be nice to each other!">Ievgen Gil</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<string name="notification_channel_device_status_label">Trạng thái thiết bị</string>
|
<string name="notification_channel_device_status_label">Trạng thái thiết bị</string>
|
||||||
<string name="general_error_label">Lỗi</string>
|
<string name="general_error_label">Lỗi</string>
|
||||||
<string name="general_share_action">Chia sẻ</string>
|
<string name="general_share_action">Chia sẻ</string>
|
||||||
<string name="general_done_action">Xong</string>
|
<string name="general_done_action">Hoàn tất</string>
|
||||||
<string name="general_copy_action">Sao chép</string>
|
<string name="general_copy_action">Sao chép</string>
|
||||||
<string name="general_thank_you_label">Cảm ơn</string>
|
<string name="general_thank_you_label">Cảm ơn</string>
|
||||||
<string name="general_value_not_available_label">Không rõ</string>
|
<string name="general_value_not_available_label">Không rõ</string>
|
||||||
@@ -21,21 +21,21 @@
|
|||||||
<string name="debug_debuglog_record_action">Ghi nhật ký gỡ lỗi</string>
|
<string name="debug_debuglog_record_action">Ghi nhật ký gỡ lỗi</string>
|
||||||
<string name="permission_bluetooth_connect_label">Kết nối Bluetooth</string>
|
<string name="permission_bluetooth_connect_label">Kết nối Bluetooth</string>
|
||||||
<string name="permission_bluetooth_connect_description">Ứng dụng này yêu cầu quyền \"Kết nối Bluetooth\" để tương tác với các thiết bị được ghép nối và bắt đầu kết nối.</string>
|
<string name="permission_bluetooth_connect_description">Ứng dụng này yêu cầu quyền \"Kết nối Bluetooth\" để tương tác với các thiết bị được ghép nối và bắt đầu kết nối.</string>
|
||||||
<string name="permission_bluetooth_scan_label">Quét qua Bluetooth</string>
|
<string name="permission_bluetooth_scan_label">Quét Bluetooth</string>
|
||||||
<string name="permission_bluetooth_scan_description">Quyền \"quét Bluetooth\" cho phép ứng dụng này khám phá và nhận dữ liệu Bluetooth từ các thiết bị lân cận, chẳng hạn như AirPods của bạn.</string>
|
<string name="permission_bluetooth_scan_description">Quyền \"quét Bluetooth\" cho phép ứng dụng này khám phá và nhận dữ liệu Bluetooth từ các thiết bị lân cận, chẳng hạn như AirPods của bạn.</string>
|
||||||
<string name="permission_bluetooth_label">Bluetooth</string>
|
<string name="permission_bluetooth_label">Bluetooth</string>
|
||||||
<string name="permission_bluetooth_description">Ứng dụng này yêu cầu quyền \"Bluetooth\" để kết nối với các thiết bị bluetooth được ghép nối.</string>
|
<string name="permission_bluetooth_description">Ứng dụng này yêu cầu quyền \"Bluetooth\" để kết nối với các thiết bị Bluetooth được ghép nối.</string>
|
||||||
<string name="permission_access_fine_location_label">Truy cập vị trí tốt</string>
|
<string name="permission_access_fine_location_label">Truy cập vị trí chính xác</string>
|
||||||
<string name="permission_access_fine_location_description">CAPod sử dụng quyền \"vị trí tốt\" để nhận dữ liệu Bluetooth Low Energy. Tai nghe của bạn sử dụng công nghệ Bluetooth Low Energy để phát trạng thái của chúng. Ứng dụng này sẽ KHÔNG sử dụng dữ liệu Bluetooth để xác định vị trí của bạn.</string>
|
<string name="permission_access_fine_location_description">CAPod sử dụng quyền \"vị trí chính xác\" để nhận dữ liệu Bluetooth Năng Lượng Thấp. Tai nghe của bạn sử dụng công nghệ Bluetooth Năng Lượng Thấp để phát trạng thái của chúng. Ứng dụng này sẽ KHÔNG sử dụng dữ liệu Bluetooth để xác định vị trí của bạn.</string>
|
||||||
<string name="permission_background_location_label">Quyền truy cập vị trí nền</string>
|
<string name="permission_background_location_label">Quyền truy cập vị trí trong nền</string>
|
||||||
<string name="permission_background_location_description">CAPod sử dụng \"quyền truy cập vị trí nền\" để bật các tính năng như \"Hiển thị cửa sổ bật lên\" và \"Tự động kết nối\" trong khi ứng dụng đóng. Quyền truy cập vị trí trong nền cho phép ứng dụng nhận dữ liệu Bluetooth Low Energy khi đang ở chế độ nền. Ứng dụng này sẽ KHÔNG sử dụng dữ liệu Bluetooth để xác định vị trí của bạn.</string>
|
<string name="permission_background_location_description">CAPod sử dụng \"quyền truy cập vị trí trong nền\" để bật các tính năng như \"Hiển thị cửa sổ bật lên\" và \"Tự động kết nối\" trong khi ứng dụng đóng. Quyền truy cập vị trí trong nền cho phép ứng dụng nhận dữ liệu Bluetooth Năng Lượng Thấp khi đang ở chế độ nền. Ứng dụng này sẽ KHÔNG sử dụng dữ liệu Bluetooth để xác định vị trí của bạn.</string>
|
||||||
<string name="permission_ignore_battery_optimizations_label">Tắt tối ưu hóa pin</string>
|
<string name="permission_ignore_battery_optimizations_label">Tắt tối ưu hóa pin</string>
|
||||||
<string name="permission_ignore_battery_optimizations_description">Tối ưu hóa pin ngăn ứng dụng này nhận dữ liệu Bluetooth một cách đáng tin cậy khi ứng dụng ở chế độ nền.</string>
|
<string name="permission_ignore_battery_optimizations_description">Tối ưu hóa pin ngăn ứng dụng này nhận dữ liệu Bluetooth một cách chính xác khi ứng dụng ở chế độ nền.</string>
|
||||||
<string name="pods_dual_left_label">Tai bên trái</string>
|
<string name="pods_dual_left_label">Tai bên trái</string>
|
||||||
<string name="pods_dual_right_label">Tai bên phải</string>
|
<string name="pods_dual_right_label">Tai bên phải</string>
|
||||||
<string name="pods_case_label">Hộp đựng</string>
|
<string name="pods_case_label">Hộp đựng</string>
|
||||||
<string name="pods_case_status_open_label">Mở</string>
|
<string name="pods_case_status_open_label">Mở</string>
|
||||||
<string name="pods_case_status_closed_label">Đã đóng</string>
|
<string name="pods_case_status_closed_label">Đóng</string>
|
||||||
<string name="pods_connection_state_disconnected_label">Không được kết nối với thiết bị</string>
|
<string name="pods_connection_state_disconnected_label">Không được kết nối với thiết bị</string>
|
||||||
<string name="pods_connection_state_idle_label">Đã kết nối với một thiết bị nhưng không hoạt động</string>
|
<string name="pods_connection_state_idle_label">Đã kết nối với một thiết bị nhưng không hoạt động</string>
|
||||||
<string name="pods_connection_state_music_label">Ở chế độ âm nhạc</string>
|
<string name="pods_connection_state_music_label">Ở chế độ âm nhạc</string>
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
<string name="pods_connection_state_hanging_up_label">Cúp máy</string>
|
<string name="pods_connection_state_hanging_up_label">Cúp máy</string>
|
||||||
<string name="pods_connection_state_unknown_label">Trạng thái kết nối không xác định</string>
|
<string name="pods_connection_state_unknown_label">Trạng thái kết nối không xác định</string>
|
||||||
<string name="pods_unknown_raw_data_label">Dữ liệu thô</string>
|
<string name="pods_unknown_raw_data_label">Dữ liệu thô</string>
|
||||||
<string name="pods_unknown_label">Thiết bị chưa biết</string>
|
<string name="pods_unknown_label">Thiết bị không xác định</string>
|
||||||
<string name="pods_unknown_contact_dev">Đây là một thiết bị không xác định, nhưng nó đang sử dụng định dạng tin nhắn tương tự. Cần thêm hỗ trợ cho nó, liên hệ với tôi :)</string>
|
<string name="pods_unknown_contact_dev">Đây là một thiết bị không xác định, nhưng nó đang sử dụng định dạng tin nhắn tương tự. Cần thêm hỗ trợ cho nó, liên hệ với tôi :)</string>
|
||||||
<string name="pods_none_label_short">Không có thiết bị</string>
|
<string name="pods_none_label_short">Không có thiết bị</string>
|
||||||
<string name="pods_charging_label">Đang sạc</string>
|
<string name="pods_charging_label">Đang sạc</string>
|
||||||
@@ -62,9 +62,9 @@
|
|||||||
<string name="settings_category_other_label">Khác</string>
|
<string name="settings_category_other_label">Khác</string>
|
||||||
<string name="settings_general_label">Cài đặt</string>
|
<string name="settings_general_label">Cài đặt</string>
|
||||||
<string name="settings_general_description">Các chỉnh sửa chung ảnh hưởng đến toàn bộ ứng dụng.</string>
|
<string name="settings_general_description">Các chỉnh sửa chung ảnh hưởng đến toàn bộ ứng dụng.</string>
|
||||||
<string name="settings_acknowledgements_label">Nhìn nhận</string>
|
<string name="settings_acknowledgements_label">Đóng góp và cảm ơn</string>
|
||||||
<string name="changelog_label">Các thay đổi</string>
|
<string name="changelog_label">Các thay đổi</string>
|
||||||
<string name="settings_support_email_developer_label">Gửi email cho nhà phát triển</string>
|
<string name="settings_support_email_developer_label" comment="settings_support_email_developer_label Pressing this setting will open your default email app with a template for a mail to me and some device info (e.g. versions).">Gửi email cho nhà phát triển</string>
|
||||||
<string name="settings_support_installid_label">ID Cài đặt</string>
|
<string name="settings_support_installid_label">ID Cài đặt</string>
|
||||||
<string name="settings_support_installid_desc">Các báo cáo lỗi tự động được ẩn danh. Chia sẻ ID cài đặt của bạn nếu nhà phát triển cần tìm các báo cáo lỗi của bạn.</string>
|
<string name="settings_support_installid_desc">Các báo cáo lỗi tự động được ẩn danh. Chia sẻ ID cài đặt của bạn nếu nhà phát triển cần tìm các báo cáo lỗi của bạn.</string>
|
||||||
<string name="settings_support_label">Hỗ trợ</string>
|
<string name="settings_support_label">Hỗ trợ</string>
|
||||||
@@ -134,4 +134,6 @@
|
|||||||
<string name="permission_required_title">Quyền sau đây là bắt buộc:</string>
|
<string name="permission_required_title">Quyền sau đây là bắt buộc:</string>
|
||||||
<string name="settings_compatibility_mode_label">Chế độ tương thích</string>
|
<string name="settings_compatibility_mode_label">Chế độ tương thích</string>
|
||||||
<string name="settings_compatibility_mode_description">Tắt tối ưu hóa để cải thiện khả năng tương thích. Hãy thử điều này nếu bạn không thấy bất kỳ dữ liệu nào.</string>
|
<string name="settings_compatibility_mode_description">Tắt tối ưu hóa để cải thiện khả năng tương thích. Hãy thử điều này nếu bạn không thấy bất kỳ dữ liệu nào.</string>
|
||||||
|
<string name="translators_thanks_title">Dịch thuật</string>
|
||||||
|
<string name="translators_thanks_description" comment="translators_thanks_description You can voluntarily add your name here to have it displayed in the app. It will be shown in the Settings>Acknowledgements>Thank you section. Separate names by semicolons and an optional email may be included in brackets, example: darken(darken@darken.eu);John Doe(john@example.com) "darken" is just a placeholder and does not have to be kept if/when you add yours. Be nice to each other!">dovanchuc7521</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
<string name="permission_bluetooth_label">蓝牙</string>
|
<string name="permission_bluetooth_label">蓝牙</string>
|
||||||
<string name="permission_bluetooth_description">本应用需要“蓝牙”权限才能连接已配对的蓝牙设备</string>
|
<string name="permission_bluetooth_description">本应用需要“蓝牙”权限才能连接已配对的蓝牙设备</string>
|
||||||
<string name="permission_access_fine_location_label">访问精准位置</string>
|
<string name="permission_access_fine_location_label">访问精准位置</string>
|
||||||
<string name="permission_access_fine_location_description">CAPod 使用“精准定位”权限来接收低功耗蓝牙数据。您的耳机使用低功耗蓝牙技术来传播其状态,本应用「不会」通过蓝牙数据来给您定位。</string>
|
<string name="permission_access_fine_location_description">CAPod 使用“精准定位”权限来接收低功耗蓝牙数据。您的耳机使用低功耗蓝牙技术来广播其状态,本应用「不会」通过蓝牙数据测定您的位置。</string>
|
||||||
<string name="permission_background_location_label">在后台访问位置</string>
|
<string name="permission_background_location_label">在后台访问位置</string>
|
||||||
<string name="permission_background_location_description">CAPod 使用“在后台访问位置”权限以在本应用被关闭时继续提供如“显示弹窗”、“自动连接”等功能。此权限允许本应用在后台运行时继续接收蓝牙低功耗数据。本应用并不使用蓝牙数据来窥探您的位置。</string>
|
<string name="permission_background_location_description">CAPod 使用“在后台访问位置”权限以在本应用被关闭时继续提供如“显示弹窗”、“自动连接”等功能。此权限允许本应用在后台运行时继续接收蓝牙低功耗数据。本应用并不使用蓝牙数据来窥探您的位置。</string>
|
||||||
<string name="permission_ignore_battery_optimizations_label">禁用电池优化</string>
|
<string name="permission_ignore_battery_optimizations_label">禁用电池优化</string>
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
<string name="settings_general_description">影响整个应用的一般性设置。</string>
|
<string name="settings_general_description">影响整个应用的一般性设置。</string>
|
||||||
<string name="settings_acknowledgements_label">鸣谢</string>
|
<string name="settings_acknowledgements_label">鸣谢</string>
|
||||||
<string name="changelog_label">更新日志</string>
|
<string name="changelog_label">更新日志</string>
|
||||||
<string name="settings_support_email_developer_label">给开发者发电子邮件</string>
|
<string name="settings_support_email_developer_label" comment="settings_support_email_developer_label Pressing this setting will open your default email app with a template for a mail to me and some device info (e.g. versions).">给开发者发电子邮件</string>
|
||||||
<string name="settings_support_installid_label">安装 ID</string>
|
<string name="settings_support_installid_label">安装 ID</string>
|
||||||
<string name="settings_support_installid_desc">自动发送的错误报告是匿名的。如果需要,给开发者发送您的安装 ID 以便找出您的错误报告。</string>
|
<string name="settings_support_installid_desc">自动发送的错误报告是匿名的。如果需要,给开发者发送您的安装 ID 以便找出您的错误报告。</string>
|
||||||
<string name="settings_support_label">用户支持</string>
|
<string name="settings_support_label">用户支持</string>
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
<string name="settings_debug_mode_label">调试模式</string>
|
<string name="settings_debug_mode_label">调试模式</string>
|
||||||
<string name="settings_debug_mode_description">显示额外信息以帮助调试故障。</string>
|
<string name="settings_debug_mode_description">显示额外信息以帮助调试故障。</string>
|
||||||
<string name="settings_monitor_mode_label">监控模式</string>
|
<string name="settings_monitor_mode_label">监控模式</string>
|
||||||
<string name="settings_monitor_mode_description">此模式下本应用将监视蓝牙数据。</string>
|
<string name="settings_monitor_mode_description">决定本应用在何时收听蓝牙数据。</string>
|
||||||
<string name="settings_scanner_mode_label">扫描模式</string>
|
<string name="settings_scanner_mode_label">扫描模式</string>
|
||||||
<string name="settings_scanner_mode_description">低功耗蓝牙数据扫描器应着重性能还是省电?</string>
|
<string name="settings_scanner_mode_description">低功耗蓝牙数据扫描器应着重性能还是省电?</string>
|
||||||
<string name="settings_monitor_mode_manual_label">应用打开时</string>
|
<string name="settings_monitor_mode_manual_label">应用打开时</string>
|
||||||
@@ -120,7 +120,7 @@
|
|||||||
<string name="settings_popup_caseopen_label">显示弹窗</string>
|
<string name="settings_popup_caseopen_label">显示弹窗</string>
|
||||||
<string name="settings_popup_caseopen_description">设备充电仓打开时显示弹窗(实验性)</string>
|
<string name="settings_popup_caseopen_description">设备充电仓打开时显示弹窗(实验性)</string>
|
||||||
<string name="overview_bluetooth_disabled_label">蓝牙已禁用</string>
|
<string name="overview_bluetooth_disabled_label">蓝牙已禁用</string>
|
||||||
<string name="overview_bluetooth_disabled_description">蓝牙已关闭,请启用之 ;)</string>
|
<string name="overview_bluetooth_disabled_description">蓝牙已关闭,请开启 ;)</string>
|
||||||
<string name="help_translate_label">翻译</string>
|
<string name="help_translate_label">翻译</string>
|
||||||
<string name="help_translate_description">帮助翻译本应用</string>
|
<string name="help_translate_description">帮助翻译本应用</string>
|
||||||
<string name="settings_onepod_mode_label">单耳模式</string>
|
<string name="settings_onepod_mode_label">单耳模式</string>
|
||||||
@@ -134,4 +134,6 @@
|
|||||||
<string name="permission_required_title">需要下列权限:</string>
|
<string name="permission_required_title">需要下列权限:</string>
|
||||||
<string name="settings_compatibility_mode_label">兼容模式</string>
|
<string name="settings_compatibility_mode_label">兼容模式</string>
|
||||||
<string name="settings_compatibility_mode_description">禁用优化以提高兼容性,请在未看到任何数据时尝试此操作</string>
|
<string name="settings_compatibility_mode_description">禁用优化以提高兼容性,请在未看到任何数据时尝试此操作</string>
|
||||||
|
<string name="translators_thanks_title">翻译人员</string>
|
||||||
|
<string name="translators_thanks_description" comment="translators_thanks_description You can voluntarily add your name here to have it displayed in the app. It will be shown in the Settings>Acknowledgements>Thank you section. Separate names by semicolons and an optional email may be included in brackets, example: darken(darken@darken.eu);John Doe(john@example.com) "darken" is just a placeholder and does not have to be kept if/when you add yours. Be nice to each other!">木仔</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<string name="general_share_action">分享</string>
|
<string name="general_share_action">分享</string>
|
||||||
<string name="general_done_action">完成</string>
|
<string name="general_done_action">完成</string>
|
||||||
<string name="general_copy_action">複製</string>
|
<string name="general_copy_action">複製</string>
|
||||||
<string name="general_thank_you_label">謝謝你們</string>
|
<string name="general_thank_you_label">感謝你們</string>
|
||||||
<string name="general_value_not_available_label">不可用</string>
|
<string name="general_value_not_available_label">不可用</string>
|
||||||
<string name="general_grant_permission_action">授予權限</string>
|
<string name="general_grant_permission_action">授予權限</string>
|
||||||
<string name="general_upgrade_action">升級</string>
|
<string name="general_upgrade_action">升級</string>
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
<string name="permission_bluetooth_connect_label">藍牙連線</string>
|
<string name="permission_bluetooth_connect_label">藍牙連線</string>
|
||||||
<string name="permission_bluetooth_connect_description">本應用程式需要「藍牙連線」權限以與已配對的裝置交互或配對新裝置。</string>
|
<string name="permission_bluetooth_connect_description">本應用程式需要「藍牙連線」權限以與已配對的裝置交互或配對新裝置。</string>
|
||||||
<string name="permission_bluetooth_scan_label">藍牙掃描</string>
|
<string name="permission_bluetooth_scan_label">藍牙掃描</string>
|
||||||
<string name="permission_bluetooth_scan_description">「藍牙掃描」權限允許該應用程式從發現附近的裝置並接收藍牙資料,你的 AirPods 需要如此。</string>
|
<string name="permission_bluetooth_scan_description">「藍牙掃描」權限允許該應用程式發現附近的裝置並接收藍牙資料,你的 AirPods 需要如此。</string>
|
||||||
<string name="permission_bluetooth_label">藍牙</string>
|
<string name="permission_bluetooth_label">藍牙</string>
|
||||||
<string name="permission_bluetooth_description">該應用程式需要「藍牙」權限與已配對裝置連線。</string>
|
<string name="permission_bluetooth_description">該應用程式需要「藍牙」權限與已配對裝置連線。</string>
|
||||||
<string name="permission_access_fine_location_label">存取精確位置</string>
|
<string name="permission_access_fine_location_label">存取精確位置</string>
|
||||||
@@ -61,14 +61,14 @@
|
|||||||
<string name="settings_licenses_label">授權條款</string>
|
<string name="settings_licenses_label">授權條款</string>
|
||||||
<string name="settings_category_other_label">其它</string>
|
<string name="settings_category_other_label">其它</string>
|
||||||
<string name="settings_general_label">設定</string>
|
<string name="settings_general_label">設定</string>
|
||||||
<string name="settings_general_description">影響整個應用程式的一般微調。</string>
|
<string name="settings_general_description">影響整個應用程式的一般調校。</string>
|
||||||
<string name="settings_acknowledgements_label">致謝</string>
|
<string name="settings_acknowledgements_label">致謝</string>
|
||||||
<string name="changelog_label">變更記錄</string>
|
<string name="changelog_label">變更記錄</string>
|
||||||
<string name="settings_support_email_developer_label">向開發人員寄出電子郵件</string>
|
<string name="settings_support_email_developer_label" comment="settings_support_email_developer_label Pressing this setting will open your default email app with a template for a mail to me and some device info (e.g. versions).">向開發人員寄出電子郵件</string>
|
||||||
<string name="settings_support_installid_label">安裝 ID</string>
|
<string name="settings_support_installid_label">安裝 ID</string>
|
||||||
<string name="settings_support_installid_desc">自動傳送的錯誤報告是匿名的。如果開發人員需要找出你的錯誤報告將分享你的安裝 ID。</string>
|
<string name="settings_support_installid_desc">自動傳送的錯誤報告是匿名的。如果開發人員需要找出你的錯誤報告將分享你的安裝 ID。</string>
|
||||||
<string name="settings_support_label">支援</string>
|
<string name="settings_support_label">支援</string>
|
||||||
<string name="settings_support_description">如果你需要幫助。</string>
|
<string name="settings_support_description">如果你需要協助。</string>
|
||||||
<string name="issue_tracker_label">問題追蹤器</string>
|
<string name="issue_tracker_label">問題追蹤器</string>
|
||||||
<string name="issue_tracker_description">一個用於錯誤回報和功能需求的公用問題追蹤器 (僅英文)。</string>
|
<string name="issue_tracker_description">一個用於錯誤回報和功能需求的公用問題追蹤器 (僅英文)。</string>
|
||||||
<string name="discord_label">Discord</string>
|
<string name="discord_label">Discord</string>
|
||||||
@@ -97,7 +97,7 @@
|
|||||||
<string name="settings_fake_data_label">假資料</string>
|
<string name="settings_fake_data_label">假資料</string>
|
||||||
<string name="settings_fake_data_description">顯示假資料,模擬不存在的裝置。</string>
|
<string name="settings_fake_data_description">顯示假資料,模擬不存在的裝置。</string>
|
||||||
<string name="settings_debug_label">偵錯設定</string>
|
<string name="settings_debug_label">偵錯設定</string>
|
||||||
<string name="settings_debug_description">一個能幫助這個應用程式故障檢修的附加設定。</string>
|
<string name="settings_debug_description">一個能協助這個應用程式故障檢修的附加設定。</string>
|
||||||
<string name="settings_signal_minimum_label">最低訊號質量</string>
|
<string name="settings_signal_minimum_label">最低訊號質量</string>
|
||||||
<string name="settings_signal_minimum_description">可以被認為是你的裝置的最低訊號質量。</string>
|
<string name="settings_signal_minimum_description">可以被認為是你的裝置的最低訊號質量。</string>
|
||||||
<string name="settings_autoconnect_label">自動連線</string>
|
<string name="settings_autoconnect_label">自動連線</string>
|
||||||
@@ -111,7 +111,7 @@
|
|||||||
<string name="settings_maindevice_address_description">你的已配對裝置的位址。這個應用程式用該位址來確定何時連線到你的手機。</string>
|
<string name="settings_maindevice_address_description">你的已配對裝置的位址。這個應用程式用該位址來確定何時連線到你的手機。</string>
|
||||||
<string name="settings_maindevice_address_none">無</string>
|
<string name="settings_maindevice_address_none">無</string>
|
||||||
<string name="settings_maindevice_model_label">你的裝置型號</string>
|
<string name="settings_maindevice_model_label">你的裝置型號</string>
|
||||||
<string name="settings_maindevice_model_description">你的主要裝置型號。這能幫助這個應用程式在未連線到你的手機時辨識你的裝置。</string>
|
<string name="settings_maindevice_model_description">你的主要裝置型號。這能協助這個應用程式在未連線到你的手機時辨識你的裝置。</string>
|
||||||
<string name="settings_reaction_autoconnect_whenseen_label">看到時</string>
|
<string name="settings_reaction_autoconnect_whenseen_label">看到時</string>
|
||||||
<string name="settings_reaction_autoconnect_caseopen_label">充電盒開啟</string>
|
<string name="settings_reaction_autoconnect_caseopen_label">充電盒開啟</string>
|
||||||
<string name="settings_reaction_autoconnect_inear_label">在耳中</string>
|
<string name="settings_reaction_autoconnect_inear_label">在耳中</string>
|
||||||
@@ -134,4 +134,6 @@
|
|||||||
<string name="permission_required_title">可能要求下列權限:</string>
|
<string name="permission_required_title">可能要求下列權限:</string>
|
||||||
<string name="settings_compatibility_mode_label">相容模式</string>
|
<string name="settings_compatibility_mode_label">相容模式</string>
|
||||||
<string name="settings_compatibility_mode_description">停用最佳化以提高相容性。請在未看到任何資料時開啟。</string>
|
<string name="settings_compatibility_mode_description">停用最佳化以提高相容性。請在未看到任何資料時開啟。</string>
|
||||||
|
<string name="translators_thanks_title">翻譯人員</string>
|
||||||
|
<string name="translators_thanks_description" comment="translators_thanks_description You can voluntarily add your name here to have it displayed in the app. It will be shown in the Settings>Acknowledgements>Thank you section. Separate names by semicolons and an optional email may be included in brackets, example: darken(darken@darken.eu);John Doe(john@example.com) "darken" is just a placeholder and does not have to be kept if/when you add yours. Be nice to each other!">人工知能</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -144,4 +144,6 @@
|
|||||||
<string name="permission_required_title">The following permission is required:</string>
|
<string name="permission_required_title">The following permission is required:</string>
|
||||||
<string name="settings_compatibility_mode_label">Compatibility mode</string>
|
<string name="settings_compatibility_mode_label">Compatibility mode</string>
|
||||||
<string name="settings_compatibility_mode_description">Disable optimizations to improve compatibility. Try this if you are not seeing any data.</string>
|
<string name="settings_compatibility_mode_description">Disable optimizations to improve compatibility. Try this if you are not seeing any data.</string>
|
||||||
|
<string name="translators_thanks_title">Translators</string>
|
||||||
|
<string name="translators_thanks_description">darken</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -4,6 +4,15 @@
|
|||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:title="@string/general_thank_you_label"
|
android:title="@string/general_thank_you_label"
|
||||||
app:iconSpaceReserved="false">
|
app:iconSpaceReserved="false">
|
||||||
|
<Preference
|
||||||
|
android:key="thanks.translators"
|
||||||
|
android:summary="@string/translators_thanks_description"
|
||||||
|
android:title="@string/translators_thanks_title"
|
||||||
|
app:iconSpaceReserved="false">
|
||||||
|
<intent
|
||||||
|
android:action="android.intent.action.VIEW"
|
||||||
|
android:data="https://crowdin.com/project/capod/activity-stream" />
|
||||||
|
</Preference>
|
||||||
<Preference
|
<Preference
|
||||||
android:key="thanks.maxpatchs"
|
android:key="thanks.maxpatchs"
|
||||||
android:summary="Thanks for the lovely icons."
|
android:summary="Thanks for the lovely icons."
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package eu.darken.capod.pods.core.apple
|
|||||||
import eu.darken.capod.pods.core.PodDevice
|
import eu.darken.capod.pods.core.PodDevice
|
||||||
import eu.darken.capod.pods.core.apple.airpods.AirPodsGen1
|
import eu.darken.capod.pods.core.apple.airpods.AirPodsGen1
|
||||||
import eu.darken.capod.pods.core.apple.airpods.AirPodsPro
|
import eu.darken.capod.pods.core.apple.airpods.AirPodsPro
|
||||||
|
import eu.darken.capod.pods.core.apple.misc.UnknownAppleDevice
|
||||||
import io.kotest.matchers.shouldBe
|
import io.kotest.matchers.shouldBe
|
||||||
import io.kotest.matchers.types.instanceOf
|
import io.kotest.matchers.types.instanceOf
|
||||||
import kotlinx.coroutines.test.runBlockingTest
|
import kotlinx.coroutines.test.runBlockingTest
|
||||||
@@ -12,14 +13,14 @@ class AirPodsFactoryTest : BaseAirPodsTest() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `create AirPodsGen1`() = runBlockingTest {
|
fun `create AirPodsGen1`() = runBlockingTest {
|
||||||
create<DualApplePods>("07 19 01 02 20 55 AA 56 31 00 00 6F E4 DF 10 AF 10 60 81 03 3B 76 D9 C7 11 22 88") {
|
create<DualAirPods>("07 19 01 02 20 55 AA 56 31 00 00 6F E4 DF 10 AF 10 60 81 03 3B 76 D9 C7 11 22 88") {
|
||||||
this shouldBe instanceOf<AirPodsGen1>()
|
this shouldBe instanceOf<AirPodsGen1>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `create AirPodsPro`() = runBlockingTest {
|
fun `create AirPodsPro`() = runBlockingTest {
|
||||||
create<DualApplePods>("07 19 01 0E 20 2B 99 8F 01 00 >09< 10 30 EE F3 41 B5 D8 9F A3 B0 B4 17 9F 85 97 5F") {
|
create<DualAirPods>("07 19 01 0E 20 2B 99 8F 01 00 >09< 10 30 EE F3 41 B5 D8 9F A3 B0 B4 17 9F 85 97 5F") {
|
||||||
this shouldBe instanceOf<AirPodsPro>()
|
this shouldBe instanceOf<AirPodsPro>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ class BasicSingleApplePodsTest : BaseAirPodsTest() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test mapping`() = runBlockingTest {
|
fun `test mapping`() = runBlockingTest {
|
||||||
create<BasicSingleApplePods>("07 19 01 05 20 00 F5 0F 01 01 00 6D CE C0 04 22 0A 85 31 2D 82 6B 42 80 01 20 1A") {
|
create<SingleApplePods>("07 19 01 05 20 00 F5 0F 01 01 00 6D CE C0 04 22 0A 85 31 2D 82 6B 42 80 01 20 1A") {
|
||||||
rawPrefix shouldBe 0x01.toUByte()
|
rawPrefix shouldBe 0x01.toUByte()
|
||||||
rawDeviceModel shouldBe 0x0520.toUShort()
|
rawDeviceModel shouldBe 0x0520.toUShort()
|
||||||
rawStatus shouldBe 0x00.toUByte()
|
rawStatus shouldBe 0x00.toUByte()
|
||||||
@@ -23,7 +23,7 @@ class BasicSingleApplePodsTest : BaseAirPodsTest() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test battery headset percent`() = runBlockingTest {
|
fun `test battery headset percent`() = runBlockingTest {
|
||||||
create<BasicSingleApplePods>("07 19 01 05 20 00 F5 0F 01 01 00 6D CE C0 04 22 0A 85 31 2D 82 6B 42 80 01 20 1A") {
|
create<SingleApplePods>("07 19 01 05 20 00 F5 0F 01 01 00 6D CE C0 04 22 0A 85 31 2D 82 6B 42 80 01 20 1A") {
|
||||||
batteryHeadsetPercent shouldBe 0.5f
|
batteryHeadsetPercent shouldBe 0.5f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ class DualApplePodsTest : BaseAirPodsTest() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test bit mapping`() = runBlockingTest {
|
fun `test bit mapping`() = runBlockingTest {
|
||||||
create<DualApplePods>("07 19 01 0E 20 54 AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") {
|
create<DualAirPods>("07 19 01 0E 20 54 AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") {
|
||||||
|
|
||||||
rawPrefix shouldBe 0x01.toUByte()
|
rawPrefix shouldBe 0x01.toUByte()
|
||||||
rawDeviceModel shouldBe 0x0e20.toUShort()
|
rawDeviceModel shouldBe 0x0e20.toUShort()
|
||||||
@@ -24,13 +24,13 @@ class DualApplePodsTest : BaseAirPodsTest() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test AirPodDevice - active microphone`() = runBlockingTest {
|
fun `test AirPodDevice - active microphone`() = runBlockingTest {
|
||||||
create<DualApplePods>("07 19 01 0E 20 >2B< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") {
|
create<DualAirPods>("07 19 01 0E 20 >2B< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") {
|
||||||
// 00101011
|
// 00101011
|
||||||
// --^-----
|
// --^-----
|
||||||
isLeftPodMicrophone shouldBe true
|
isLeftPodMicrophone shouldBe true
|
||||||
isRightPodMicrophone shouldBe false
|
isRightPodMicrophone shouldBe false
|
||||||
}
|
}
|
||||||
create<DualApplePods>("07 19 01 0E 20 >0B< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") {
|
create<DualAirPods>("07 19 01 0E 20 >0B< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") {
|
||||||
// 00001011
|
// 00001011
|
||||||
// --^-----
|
// --^-----
|
||||||
isLeftPodMicrophone shouldBe false
|
isLeftPodMicrophone shouldBe false
|
||||||
@@ -41,24 +41,24 @@ class DualApplePodsTest : BaseAirPodsTest() {
|
|||||||
@Test
|
@Test
|
||||||
fun `test AirPodDevice - left pod ear status`() = runBlockingTest {
|
fun `test AirPodDevice - left pod ear status`() = runBlockingTest {
|
||||||
// Left Pod primary
|
// Left Pod primary
|
||||||
create<DualApplePods>("07 19 01 0E 20 >22< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") {
|
create<DualAirPods>("07 19 01 0E 20 >22< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") {
|
||||||
// 00100010
|
// 00100010
|
||||||
// 765432¹0
|
// 765432¹0
|
||||||
isLeftPodInEar shouldBe true
|
isLeftPodInEar shouldBe true
|
||||||
}
|
}
|
||||||
create<DualApplePods>("07 19 01 0E 20 >20< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") {
|
create<DualAirPods>("07 19 01 0E 20 >20< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") {
|
||||||
// 00100000
|
// 00100000
|
||||||
// 765432¹0
|
// 765432¹0
|
||||||
isLeftPodInEar shouldBe false
|
isLeftPodInEar shouldBe false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Right Pod is primary
|
// Right Pod is primary
|
||||||
create<DualApplePods>("07 19 01 0E 20 >09< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") {
|
create<DualAirPods>("07 19 01 0E 20 >09< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") {
|
||||||
// 00001001
|
// 00001001
|
||||||
// 7654³210
|
// 7654³210
|
||||||
isLeftPodInEar shouldBe true
|
isLeftPodInEar shouldBe true
|
||||||
}
|
}
|
||||||
create<DualApplePods>("07 19 01 0E 20 >20< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") {
|
create<DualAirPods>("07 19 01 0E 20 >20< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") {
|
||||||
// 00000001
|
// 00000001
|
||||||
// 7654³210
|
// 7654³210
|
||||||
isLeftPodInEar shouldBe false
|
isLeftPodInEar shouldBe false
|
||||||
@@ -68,24 +68,24 @@ class DualApplePodsTest : BaseAirPodsTest() {
|
|||||||
@Test
|
@Test
|
||||||
fun `test AirPodDevice - right pod ear status`() = runBlockingTest {
|
fun `test AirPodDevice - right pod ear status`() = runBlockingTest {
|
||||||
// Left Pod primary
|
// Left Pod primary
|
||||||
create<DualApplePods>("07 19 01 0E 20 >29< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") {
|
create<DualAirPods>("07 19 01 0E 20 >29< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") {
|
||||||
// 00101001
|
// 00101001
|
||||||
// 7654³210
|
// 7654³210
|
||||||
isRightPodInEar shouldBe true
|
isRightPodInEar shouldBe true
|
||||||
}
|
}
|
||||||
create<DualApplePods>("07 19 01 0E 20 >21< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") {
|
create<DualAirPods>("07 19 01 0E 20 >21< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") {
|
||||||
// 00100001
|
// 00100001
|
||||||
// 7654³210
|
// 7654³210
|
||||||
isRightPodInEar shouldBe false
|
isRightPodInEar shouldBe false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Right Pod is primary
|
// Right Pod is primary
|
||||||
create<DualApplePods>("07 19 01 0E 20 >03< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") {
|
create<DualAirPods>("07 19 01 0E 20 >03< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") {
|
||||||
// 00000011
|
// 00000011
|
||||||
// 765432¹0
|
// 765432¹0
|
||||||
isRightPodInEar shouldBe true
|
isRightPodInEar shouldBe true
|
||||||
}
|
}
|
||||||
create<DualApplePods>("07 19 01 0E 20 >01< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") {
|
create<DualAirPods>("07 19 01 0E 20 >01< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") {
|
||||||
// 00000001
|
// 00000001
|
||||||
// 765432¹0
|
// 765432¹0
|
||||||
isRightPodInEar shouldBe false
|
isRightPodInEar shouldBe false
|
||||||
@@ -95,13 +95,13 @@ class DualApplePodsTest : BaseAirPodsTest() {
|
|||||||
@Test
|
@Test
|
||||||
fun `test AirPodDevice - battery status`() = runBlockingTest {
|
fun `test AirPodDevice - battery status`() = runBlockingTest {
|
||||||
// Right Pod is primary
|
// Right Pod is primary
|
||||||
create<DualApplePods>("07 19 01 0E 20 0B >98< 94 52 00 05 09 73 3C 3D F9 2C 3E B3 DD 76 02 DD 4E 16 FD FB") {
|
create<DualAirPods>("07 19 01 0E 20 0B >98< 94 52 00 05 09 73 3C 3D F9 2C 3E B3 DD 76 02 DD 4E 16 FD FB") {
|
||||||
// 88 10001000
|
// 88 10001000
|
||||||
batteryLeftPodPercent shouldBe 0.9f
|
batteryLeftPodPercent shouldBe 0.9f
|
||||||
batteryRightPodPercent shouldBe 0.8f
|
batteryRightPodPercent shouldBe 0.8f
|
||||||
}
|
}
|
||||||
// Left Pod primary
|
// Left Pod primary
|
||||||
create<DualApplePods>("07 19 01 0E 20 2B >89< 94 52 00 05 09 73 3C 3D F9 2C 3E B3 DD 76 02 DD 4E 16 FD FB") {
|
create<DualAirPods>("07 19 01 0E 20 2B >89< 94 52 00 05 09 73 3C 3D F9 2C 3E B3 DD 76 02 DD 4E 16 FD FB") {
|
||||||
// F8 11111000
|
// F8 11111000
|
||||||
batteryLeftPodPercent shouldBe 0.9f
|
batteryLeftPodPercent shouldBe 0.9f
|
||||||
batteryRightPodPercent shouldBe 0.8f
|
batteryRightPodPercent shouldBe 0.8f
|
||||||
@@ -114,13 +114,13 @@ class DualApplePodsTest : BaseAirPodsTest() {
|
|||||||
* Right pod is charging
|
* Right pod is charging
|
||||||
*/
|
*/
|
||||||
// This is the left
|
// This is the left
|
||||||
create<DualApplePods>("07 19 01 0E 20 51 89 >94< 52 00 00 F4 89 82 6D 3E 27 7F 26 62 57 D0 E2 A6 49 E9 35") {
|
create<DualAirPods>("07 19 01 0E 20 51 89 >94< 52 00 00 F4 89 82 6D 3E 27 7F 26 62 57 D0 E2 A6 49 E9 35") {
|
||||||
// 1001 0100
|
// 1001 0100
|
||||||
isLeftPodCharging shouldBe false
|
isLeftPodCharging shouldBe false
|
||||||
isRightPodCharging shouldBe true
|
isRightPodCharging shouldBe true
|
||||||
}
|
}
|
||||||
// This is the right
|
// This is the right
|
||||||
create<DualApplePods>("07 19 01 0E 20 31 98 >A4< 01 00 00 31 B9 A0 C4 80 CD D1 CF B9 3A 9A 6D 48 31 08 EB") {
|
create<DualAirPods>("07 19 01 0E 20 31 98 >A4< 01 00 00 31 B9 A0 C4 80 CD D1 CF B9 3A 9A 6D 48 31 08 EB") {
|
||||||
// 1010 0100
|
// 1010 0100
|
||||||
isLeftPodCharging shouldBe false
|
isLeftPodCharging shouldBe false
|
||||||
isRightPodCharging shouldBe true
|
isRightPodCharging shouldBe true
|
||||||
@@ -130,26 +130,26 @@ class DualApplePodsTest : BaseAirPodsTest() {
|
|||||||
* Left pod is charging
|
* Left pod is charging
|
||||||
*/
|
*/
|
||||||
// This is the left
|
// This is the left
|
||||||
create<DualApplePods>("07 19 01 0E 20 71 98 >94< 52 00 05 A5 37 31 B2 BD 42 68 0C 64 FD 00 99 4A E5 3E F4") {
|
create<DualAirPods>("07 19 01 0E 20 71 98 >94< 52 00 05 A5 37 31 B2 BD 42 68 0C 64 FD 00 99 4A E5 3E F4") {
|
||||||
// 1001 0100
|
// 1001 0100
|
||||||
isLeftPodCharging shouldBe true
|
isLeftPodCharging shouldBe true
|
||||||
isRightPodCharging shouldBe false
|
isRightPodCharging shouldBe false
|
||||||
}
|
}
|
||||||
// This is the right
|
// This is the right
|
||||||
create<DualApplePods>("07 19 01 0E 20 11 89 >A4< 04 00 04 BA 79 1B C0 65 69 C6 9F 19 6E 37 7D 6D 86 8D D9") {
|
create<DualAirPods>("07 19 01 0E 20 11 89 >A4< 04 00 04 BA 79 1B C0 65 69 C6 9F 19 6E 37 7D 6D 86 8D D9") {
|
||||||
// 1010 0100
|
// 1010 0100
|
||||||
isLeftPodCharging shouldBe true
|
isLeftPodCharging shouldBe true
|
||||||
isRightPodCharging shouldBe false
|
isRightPodCharging shouldBe false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Both charging
|
// Both charging
|
||||||
create<DualApplePods>("07 19 01 0E 20 55 88 >B4< 59 00 05 4B FC DF 68 28 A5 45 52 65 9C FE 51 86 3A B5 DB") {
|
create<DualAirPods>("07 19 01 0E 20 55 88 >B4< 59 00 05 4B FC DF 68 28 A5 45 52 65 9C FE 51 86 3A B5 DB") {
|
||||||
// 1011 0100
|
// 1011 0100
|
||||||
isLeftPodCharging shouldBe true
|
isLeftPodCharging shouldBe true
|
||||||
isRightPodCharging shouldBe true
|
isRightPodCharging shouldBe true
|
||||||
}
|
}
|
||||||
// Both not charging
|
// Both not charging
|
||||||
create<DualApplePods>("07 19 01 0E 20 00 F8 >8F< 03 00 05 4C 0F A0 C4 05 24 DD EB AF 92 99 FD 54 B1 06 48") {
|
create<DualAirPods>("07 19 01 0E 20 00 F8 >8F< 03 00 05 4C 0F A0 C4 05 24 DD EB AF 92 99 FD 54 B1 06 48") {
|
||||||
// 1000 1111
|
// 1000 1111
|
||||||
isLeftPodCharging shouldBe false
|
isLeftPodCharging shouldBe false
|
||||||
isRightPodCharging shouldBe false
|
isRightPodCharging shouldBe false
|
||||||
@@ -158,11 +158,11 @@ class DualApplePodsTest : BaseAirPodsTest() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test AirPodDevice - case charging`() = runBlockingTest {
|
fun `test AirPodDevice - case charging`() = runBlockingTest {
|
||||||
create<DualApplePods>("07 19 01 0E 20 75 99 >B4< 31 00 05 77 C8 BA 0C 4E 1F BE AD 70 C5 40 71 D2 E9 17 A2") {
|
create<DualAirPods>("07 19 01 0E 20 75 99 >B4< 31 00 05 77 C8 BA 0C 4E 1F BE AD 70 C5 40 71 D2 E9 17 A2") {
|
||||||
// 0011 0011
|
// 0011 0011
|
||||||
isCaseCharging shouldBe false
|
isCaseCharging shouldBe false
|
||||||
}
|
}
|
||||||
create<DualApplePods>("07 19 01 0E 20 75 A9 >F4< 51 00 05 A0 37 92 35 49 79 CC DC 27 94 8E FB 72 12 94 52") {
|
create<DualAirPods>("07 19 01 0E 20 75 A9 >F4< 51 00 05 A0 37 92 35 49 79 CC DC 27 94 8E FB 72 12 94 52") {
|
||||||
// 0101 0011
|
// 0101 0011
|
||||||
isCaseCharging shouldBe true
|
isCaseCharging shouldBe true
|
||||||
}
|
}
|
||||||
@@ -171,75 +171,75 @@ class DualApplePodsTest : BaseAirPodsTest() {
|
|||||||
@Test
|
@Test
|
||||||
fun `test AirPodDevice - case lid test`() = runBlockingTest {
|
fun `test AirPodDevice - case lid test`() = runBlockingTest {
|
||||||
// Lid open
|
// Lid open
|
||||||
create<DualApplePods>("07 19 01 0E 20 55 AA B4 >31< 00 00 A1 D0 BD 82 D3 52 86 CA FC 11 62 DC 42 C6 92 8E") {
|
create<DualAirPods>("07 19 01 0E 20 55 AA B4 >31< 00 00 A1 D0 BD 82 D3 52 86 CA FC 11 62 DC 42 C6 92 8E") {
|
||||||
// 31 0011 0001
|
// 31 0011 0001
|
||||||
caseLidState shouldBe DualApplePods.LidState.OPEN
|
caseLidState shouldBe DualAirPods.LidState.OPEN
|
||||||
}
|
}
|
||||||
// Lid open, left pod in case
|
// Lid open, left pod in case
|
||||||
create<DualApplePods>("07 19 01 0E 20 51 9A 93 >31< 00 00 95 D0 A5 D7 E3 F4 F1 38 38 99 61 3B 57 95 37 B7") {
|
create<DualAirPods>("07 19 01 0E 20 51 9A 93 >31< 00 00 95 D0 A5 D7 E3 F4 F1 38 38 99 61 3B 57 95 37 B7") {
|
||||||
// 31 0011 0001
|
// 31 0011 0001
|
||||||
caseLidState shouldBe DualApplePods.LidState.OPEN
|
caseLidState shouldBe DualAirPods.LidState.OPEN
|
||||||
}
|
}
|
||||||
// Lid open, left pod in case
|
// Lid open, left pod in case
|
||||||
create<DualApplePods>("07 19 01 0E 20 71 A9 92 31 00 00 DB 48 7F 32 8C CE 80 6F D9 27 98 D6 76 45 9D 62") {
|
create<DualAirPods>("07 19 01 0E 20 71 A9 92 31 00 00 DB 48 7F 32 8C CE 80 6F D9 27 98 D6 76 45 9D 62") {
|
||||||
// 31 0011 0001
|
// 31 0011 0001
|
||||||
caseLidState shouldBe DualApplePods.LidState.OPEN
|
caseLidState shouldBe DualAirPods.LidState.OPEN
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Lid just closed
|
// Lid just closed
|
||||||
create<DualApplePods>("07 19 01 0E 20 55 AA B4 >39< 00 00 08 A6 DB 99 E0 5E 14 85 E5 C2 0B 68 D7 FF C3 A1") {
|
create<DualAirPods>("07 19 01 0E 20 55 AA B4 >39< 00 00 08 A6 DB 99 E0 5E 14 85 E5 C2 0B 68 D7 FF C3 A1") {
|
||||||
// 39 0011 1001
|
// 39 0011 1001
|
||||||
caseLidState shouldBe DualApplePods.LidState.CLOSED
|
caseLidState shouldBe DualAirPods.LidState.CLOSED
|
||||||
}
|
}
|
||||||
// Lid closed
|
// Lid closed
|
||||||
create<DualApplePods>("07 19 01 0E 20 55 AA B4 38 00 00 F3 F7 08 3B 98 09 C0 DD E4 BD BD 84 55 56 8B 81") {
|
create<DualAirPods>("07 19 01 0E 20 55 AA B4 38 00 00 F3 F7 08 3B 98 09 C0 DD E4 BD BD 84 55 56 8B 81") {
|
||||||
// 38 0011 1000
|
// 38 0011 1000
|
||||||
caseLidState shouldBe DualApplePods.LidState.CLOSED
|
caseLidState shouldBe DualAirPods.LidState.CLOSED
|
||||||
}
|
}
|
||||||
// Lid closed, right pod in case
|
// Lid closed, right pod in case
|
||||||
create<DualApplePods>("07 19 01 0E 20 51 9A 93 >38< 00 00 3A D8 85 76 B0 91 48 31 DA FF 6C 4A 2B C2 67 F4") {
|
create<DualAirPods>("07 19 01 0E 20 51 9A 93 >38< 00 00 3A D8 85 76 B0 91 48 31 DA FF 6C 4A 2B C2 67 F4") {
|
||||||
// 38 0011 1000
|
// 38 0011 1000
|
||||||
caseLidState shouldBe DualApplePods.LidState.CLOSED
|
caseLidState shouldBe DualAirPods.LidState.CLOSED
|
||||||
}
|
}
|
||||||
// Lid closed, left pod in case
|
// Lid closed, left pod in case
|
||||||
create<DualApplePods>("07 19 01 0E 20 71 A9 92 38 00 00 44 91 C4 8B 85 98 DD 55 4E 6A CA BC B5 CA 8D 37") {
|
create<DualAirPods>("07 19 01 0E 20 71 A9 92 38 00 00 44 91 C4 8B 85 98 DD 55 4E 6A CA BC B5 CA 8D 37") {
|
||||||
// 38 0011 1000
|
// 38 0011 1000
|
||||||
caseLidState shouldBe DualApplePods.LidState.CLOSED
|
caseLidState shouldBe DualAirPods.LidState.CLOSED
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test AirPodDevice - connection state`() = runBlockingTest {
|
fun `test AirPodDevice - connection state`() = runBlockingTest {
|
||||||
// Disconnected
|
// Disconnected
|
||||||
create<DualApplePods>("07 19 01 0E 20 2B AA 8F 01 00 >00< 62 D4 BB F1 A7 F8 64 98 D2 C8 BD 7B 3A EF 2E 15") {
|
create<DualAirPods>("07 19 01 0E 20 2B AA 8F 01 00 >00< 62 D4 BB F1 A7 F8 64 98 D2 C8 BD 7B 3A EF 2E 15") {
|
||||||
// 31 0011 0001
|
// 31 0011 0001
|
||||||
connectionState shouldBe DualApplePods.ConnectionState.DISCONNECTED
|
state shouldBe DualAirPods.ConnectionState.DISCONNECTED
|
||||||
}
|
}
|
||||||
// Connected idle
|
// Connected idle
|
||||||
create<DualApplePods>("07 19 01 0E 20 2B AA 8F 01 00 >04< 1D 69 69 9C C2 51 F3 1F BF 6E 45 DA 90 4A A3 E3") {
|
create<DualAirPods>("07 19 01 0E 20 2B AA 8F 01 00 >04< 1D 69 69 9C C2 51 F3 1F BF 6E 45 DA 90 4A A3 E3") {
|
||||||
// 39 0011 1001
|
// 39 0011 1001
|
||||||
connectionState shouldBe DualApplePods.ConnectionState.IDLE
|
state shouldBe DualAirPods.ConnectionState.IDLE
|
||||||
}
|
}
|
||||||
// Connected and playing music
|
// Connected and playing music
|
||||||
create<DualApplePods>("07 19 01 0E 20 2B A9 8F 01 00 >05< 14 F7 CB 49 9F D3 B3 22 77 D2 22 F1 74 8C AC A6") {
|
create<DualAirPods>("07 19 01 0E 20 2B A9 8F 01 00 >05< 14 F7 CB 49 9F D3 B3 22 77 D2 22 F1 74 8C AC A6") {
|
||||||
// 38 0011 1000
|
// 38 0011 1000
|
||||||
connectionState shouldBe DualApplePods.ConnectionState.MUSIC
|
state shouldBe DualAirPods.ConnectionState.MUSIC
|
||||||
}
|
}
|
||||||
// Connected and call active
|
// Connected and call active
|
||||||
create<DualApplePods>("07 19 01 0E 20 2B 99 8F 01 00 >06< 0F 4B 43 25 E0 4A 73 63 14 22 C2 3C 89 13 BD 97") {
|
create<DualAirPods>("07 19 01 0E 20 2B 99 8F 01 00 >06< 0F 4B 43 25 E0 4A 73 63 14 22 C2 3C 89 13 BD 97") {
|
||||||
// 38 0011 1000
|
// 38 0011 1000
|
||||||
connectionState shouldBe DualApplePods.ConnectionState.CALL
|
state shouldBe DualAirPods.ConnectionState.CALL
|
||||||
}
|
}
|
||||||
// Connected and call active
|
// Connected and call active
|
||||||
create<DualApplePods>("07 19 01 0E 20 2B 99 8F 01 00 >07< E7 DF 76 44 85 B5 30 F4 95 14 02 DC A1 A4 8A 09") {
|
create<DualAirPods>("07 19 01 0E 20 2B 99 8F 01 00 >07< E7 DF 76 44 85 B5 30 F4 95 14 02 DC A1 A4 8A 09") {
|
||||||
// 38 0011 1000
|
// 38 0011 1000
|
||||||
connectionState shouldBe DualApplePods.ConnectionState.RINGING
|
state shouldBe DualAirPods.ConnectionState.RINGING
|
||||||
}
|
}
|
||||||
// Switching?
|
// Switching?
|
||||||
create<DualApplePods>("07 19 01 0E 20 2B 99 8F 01 00 >09< 10 30 EE F3 41 B5 D8 9F A3 B0 B4 17 9F 85 97 5F") {
|
create<DualAirPods>("07 19 01 0E 20 2B 99 8F 01 00 >09< 10 30 EE F3 41 B5 D8 9F A3 B0 B4 17 9F 85 97 5F") {
|
||||||
// 38 0011 1000
|
// 38 0011 1000
|
||||||
connectionState shouldBe DualApplePods.ConnectionState.HANGING_UP
|
state shouldBe DualAirPods.ConnectionState.HANGING_UP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user