mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-12-02 06:52:55 +01:00
Merge branch 'master' of codeberg.org:Freeyourgadget/Gadgetbridge
This commit is contained in:
commit
f43316fcd7
5
.github/ISSUE_TEMPLATE.md
vendored
5
.github/ISSUE_TEMPLATE.md
vendored
@ -15,8 +15,7 @@ If you just have a question, please ask first in the user chatroom in Matrix: `#
|
|||||||
### I got Gadgetbridge from:
|
### I got Gadgetbridge from:
|
||||||
* [ ] F-Droid
|
* [ ] F-Droid
|
||||||
* [ ] I built it myself from source code (specify tag / commit)
|
* [ ] I built it myself from source code (specify tag / commit)
|
||||||
|
* [ ] I previously used Gadgetbridge from other sources and then updated to F-Droid version
|
||||||
If you got it from Google Play, please note [that version](https://github.com/TaaviE/Gadgetbridge) is unofficial and not supported here; it's also often quite outdated. Please switch to one of the above versions if you can.
|
|
||||||
|
|
||||||
#### Your issue is:
|
#### Your issue is:
|
||||||
*If possible, please attach [logs](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Log-Files)! that might help identifying the problem.*
|
*If possible, please attach [logs](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Log-Files)! that might help identifying the problem.*
|
||||||
@ -35,7 +34,7 @@ Here go lines of your log.
|
|||||||
|
|
||||||
*Please specify model and firmware version if possible*
|
*Please specify model and firmware version if possible*
|
||||||
|
|
||||||
#### Your android version is:
|
#### Your Android version/manufacturer flavor is:
|
||||||
|
|
||||||
#### Your Gadgetbridge version is:
|
#### Your Gadgetbridge version is:
|
||||||
|
|
||||||
|
5
.github/ISSUE_TEMPLATE/bug_report.md
vendored
5
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -15,8 +15,7 @@ If you just have a question, please ask first in the user chatroom in Matrix: `#
|
|||||||
### I got Gadgetbridge from:
|
### I got Gadgetbridge from:
|
||||||
* [ ] F-Droid
|
* [ ] F-Droid
|
||||||
* [ ] I built it myself from source code (specify tag / commit)
|
* [ ] I built it myself from source code (specify tag / commit)
|
||||||
|
* [ ] I previously used Gadgetbridge from other sources and then updated to F-Droid version
|
||||||
If you got it from Google Play, please note [that version](https://github.com/TaaviE/Gadgetbridge) is unofficial and not supported here; it's also often quite outdated. Please switch to one of the above versions if you can.
|
|
||||||
|
|
||||||
#### Your issue is:
|
#### Your issue is:
|
||||||
*If possible, please attach [logs](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Log-Files)! that might help identifying the problem.*
|
*If possible, please attach [logs](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Log-Files)! that might help identifying the problem.*
|
||||||
@ -35,7 +34,7 @@ Here go lines of your log.
|
|||||||
|
|
||||||
*Please specify model and firmware version if possible*
|
*Please specify model and firmware version if possible*
|
||||||
|
|
||||||
#### Your android version is:
|
#### Your Android version/manufacturer flavor is:
|
||||||
|
|
||||||
#### Your Gadgetbridge version is:
|
#### Your Gadgetbridge version is:
|
||||||
|
|
||||||
|
6
.github/ISSUE_TEMPLATE/device_request.md
vendored
6
.github/ISSUE_TEMPLATE/device_request.md
vendored
@ -14,9 +14,15 @@ You can use the `Preview` tab ^ above to see final rendering of your report. Use
|
|||||||
|
|
||||||
#### Device information
|
#### Device information
|
||||||
|
|
||||||
|
- Adding an implementation for a new device requires a "willing to learn" developer, ideally with the device at hand. Without that, you may try to submit a device request and see if anyone steps up and implements it.
|
||||||
|
|
||||||
|
|
||||||
- Provide device name, manufacturer and similarity to other devices:
|
- Provide device name, manufacturer and similarity to other devices:
|
||||||
|
|
||||||
|
|
||||||
|
- Ideally, use an Android Bluetooth scanner app like nRF Connect or BLExplorer and provide screenshots of the scanned device from that app. This provides a name and some available UUIDs, which are needed for implementation. You may want to blur a MAC address for privacy reasons.
|
||||||
|
|
||||||
|
|
||||||
- Specify model and firmware version if possible:
|
- Specify model and firmware version if possible:
|
||||||
|
|
||||||
|
|
||||||
|
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -28,7 +28,7 @@ Here go lines of your log.
|
|||||||
|
|
||||||
*Please specify model and firmware version if possible*
|
*Please specify model and firmware version if possible*
|
||||||
|
|
||||||
#### Your android version is:
|
#### Your Android version/manufacturer flavor is:
|
||||||
|
|
||||||
#### Your Gadgetbridge version is:
|
#### Your Gadgetbridge version is:
|
||||||
|
|
||||||
|
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -1,6 +1,6 @@
|
|||||||
[submodule "fossil-hr-watchface"]
|
[submodule "fossil-hr-watchface"]
|
||||||
path = external/fossil-hr-watchface
|
path = external/fossil-hr-watchface
|
||||||
url = https://github.com/arjan-s/fossil-hr-watchface
|
url = https://codeberg.org/Freeyourgadget/fossil-hr-watchface
|
||||||
[submodule "jerryscript"]
|
[submodule "jerryscript"]
|
||||||
path = external/jerryscript
|
path = external/jerryscript
|
||||||
url = https://github.com/jerryscript-project/jerryscript
|
url = https://github.com/jerryscript-project/jerryscript
|
||||||
|
21
CHANGELOG.md
21
CHANGELOG.md
@ -1,5 +1,26 @@
|
|||||||
### Changelog
|
### Changelog
|
||||||
|
|
||||||
|
### 0.66.0
|
||||||
|
* Add basic support for Casio GBD-H1000
|
||||||
|
* Add support for Hama Fit Track 1900 - via FitPro device support
|
||||||
|
* Add OpenTracksController for interactions with OpenTracks
|
||||||
|
* Fossil Hybrid HR: Start/stop track in OpenTracks from GPS workout on watch
|
||||||
|
* Fossil Hybrid HR: Try guessing new widget position
|
||||||
|
* Fossil Hybrid HR: Allow assigning no function to a button
|
||||||
|
* Add Huami button/device action to control fitness tracking via OpenTracksController
|
||||||
|
* Mi Band 6: Sync alarms set on the watch like on Amazfit Bip U and others
|
||||||
|
* Bangle.js: Handle battery charging status and fix battery chart.
|
||||||
|
* Bangle.js: Prevent exception in case UART RX line is empty
|
||||||
|
* Bangle.js: Add repetitions in alarm JSON
|
||||||
|
* WaspOS: Fix battery chart.
|
||||||
|
* WaspOS: Add condition code to weather JSON
|
||||||
|
* XWatch: Add notifications and calls support
|
||||||
|
* UM-25: Make cumulative values resettable
|
||||||
|
* VESC: Fixed crash when loading a saved value
|
||||||
|
* Allow to open Android notification settings from Notification settings
|
||||||
|
* AutoExporter changes for better operation and troubleshooting
|
||||||
|
* Change Nightly icons background color
|
||||||
|
|
||||||
### 0.65.0
|
### 0.65.0
|
||||||
* Amazfit Pop/Pro: Initial Support (probably the same as Bip U but has a different firmware)
|
* Amazfit Pop/Pro: Initial Support (probably the same as Bip U but has a different firmware)
|
||||||
* Sony WH-1000XM4: Initial Support
|
* Sony WH-1000XM4: Initial Support
|
||||||
|
@ -56,8 +56,8 @@ android {
|
|||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
|
|
||||||
// Note: always bump BOTH versionCode and versionName!
|
// Note: always bump BOTH versionCode and versionName!
|
||||||
versionName "0.65.0"
|
versionName "0.66.0"
|
||||||
versionCode 209
|
versionCode 210
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
buildConfigField "String", "GIT_HASH_SHORT", "\"${getGitHashShort()}\""
|
buildConfigField "String", "GIT_HASH_SHORT", "\"${getGitHashShort()}\""
|
||||||
|
4
app/proguard-rules.pro
vendored
4
app/proguard-rules.pro
vendored
@ -18,6 +18,10 @@
|
|||||||
-keepclassmembers class nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.webview.JSInterface {
|
-keepclassmembers class nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.webview.JSInterface {
|
||||||
public *;
|
public *;
|
||||||
}
|
}
|
||||||
|
# Required for refection in BangleJSDeviceSupport
|
||||||
|
-keepclassmembers class nodomain.freeyourgadget.gadgetbridge.model.CallSpec {
|
||||||
|
public static *;
|
||||||
|
}
|
||||||
-keepattributes JavascriptInterface
|
-keepattributes JavascriptInterface
|
||||||
|
|
||||||
# https://github.com/tony19/logback-android/issues/29
|
# https://github.com/tony19/logback-android/issues/29
|
||||||
|
@ -668,5 +668,10 @@
|
|||||||
<data android:mimeType="*/*" />
|
<data android:mimeType="*/*" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".externalevents.OpenTracksController"
|
||||||
|
android:label="OpenTracks controller and intent receiver"
|
||||||
|
android:exported="true"/>
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
1
app/src/main/assets/fossil_hr/battery_layout.json
Normal file
1
app/src/main/assets/fossil_hr/battery_layout.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[{"id":0,"type":"complication_background","background":"#background","goal_ring":{"is_enable":"#goal_ring","end_angle":"#fi","is_invert":"#$e"},"dimension":{"type":"rigid","width":"#size.w","height":"#size.h"},"placement":{"type":"absolute","left":"#pos.Ue","top":"#pos.Qe"},"visible":true,"inversion":false},{"id":1,"parent_id":0,"type":"complication_content","icon":"icBattery","text_low":"#ci","dimension":{"type":"rigid","width":76,"height":76},"placement":{"type":"relative"},"visible":true,"inversion":"#$e"},{"id":2,"parent_id":1,"type":"solid","placement":{"type":"absolute","left":29,"top":23},"color":"#nt","dimension":{"type":"rigid","height":6,"width":"#it"},"visible":true,"inversion":false},{"id":3,"parent_id":1,"type":"image","image_name":"icBattCharging","draw_mode":1,"placement":{"type":"absolute","left":34,"top":21},"dimension":{"width":6,"height":9},"visible":"#et","inversion":false}]
|
1
app/src/main/assets/fossil_hr/complication_layout.json
Normal file
1
app/src/main/assets/fossil_hr/complication_layout.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[{"id":0,"type":"complication_background","background":"#background","goal_ring":{"is_enable":"#goal_ring","end_angle":"#fi","is_invert":"#$e"},"dimension":{"type":"rigid","width":"#size.w","height":"#size.h"},"placement":{"type":"absolute","left":"#pos.Ue","top":"#pos.Qe"},"visible":true,"inversion":false},{"id":1,"parent_id":0,"type":"complication_content","icon":"#icon","text_high":"#dt","text_low":"#ci","dimension":{"type":"rigid","width":76,"height":76},"placement":{"type":"relative"},"visible":true,"inversion":"#$e"}]
|
1
app/src/main/assets/fossil_hr/image_layout.json
Normal file
1
app/src/main/assets/fossil_hr/image_layout.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[{"id":0,"type":"container","direction":1,"main_alignment":1,"cross_alignment":1,"dimension":{"type":"rigid","width":240,"height":240},"placement":{"type":"absolute","left":0,"top":0},"visible":true,"inversion":false},{"id":1,"parent_id":0,"type":"image","image_name":"#name","draw_mode":1,"placement":{"type":"absolute","left":"#pos.Ue","top":"#pos.Qe"},"dimension":{"width":"#size.w","height":"#size.h"},"visible":true,"inversion":false}]
|
207
app/src/main/assets/fossil_hr/menu_layout.json
Normal file
207
app/src/main/assets/fossil_hr/menu_layout.json
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"type": "container",
|
||||||
|
"direction": 1,
|
||||||
|
"main_alignment": 0,
|
||||||
|
"cross_alignment": 1,
|
||||||
|
"dimension": {
|
||||||
|
"type": "rigid",
|
||||||
|
"width": 240,
|
||||||
|
"height": 240
|
||||||
|
},
|
||||||
|
"placement": {
|
||||||
|
"type": "absolute",
|
||||||
|
"left": 0,
|
||||||
|
"top": 0
|
||||||
|
},
|
||||||
|
"visible": true,
|
||||||
|
"inversion": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"parent_id": 0,
|
||||||
|
"type": "container",
|
||||||
|
"direction": 1,
|
||||||
|
"main_alignment": 1,
|
||||||
|
"cross_alignment": 2,
|
||||||
|
"dimension": {
|
||||||
|
"type": "rigid",
|
||||||
|
"width": 130,
|
||||||
|
"height": 34
|
||||||
|
},
|
||||||
|
"placement": {
|
||||||
|
"type": "absolute",
|
||||||
|
"left": 75,
|
||||||
|
"top": 45
|
||||||
|
},
|
||||||
|
"visible": true,
|
||||||
|
"inversion": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"parent_id": 1,
|
||||||
|
"type": "text",
|
||||||
|
"text": "#top_short_press_label",
|
||||||
|
"ppem": 17,
|
||||||
|
"color": 3,
|
||||||
|
"placement": {
|
||||||
|
"type": "relative"
|
||||||
|
},
|
||||||
|
"visible": true,
|
||||||
|
"inversion": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"parent_id": 1,
|
||||||
|
"type": "text",
|
||||||
|
"text": "#top_long_press_label",
|
||||||
|
"ppem": 17,
|
||||||
|
"color": 3,
|
||||||
|
"ascent": 17,
|
||||||
|
"placement": {
|
||||||
|
"type": "relative"
|
||||||
|
},
|
||||||
|
"visible": true,
|
||||||
|
"inversion": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"parent_id": 0,
|
||||||
|
"type": "container",
|
||||||
|
"direction": 1,
|
||||||
|
"main_alignment": 1,
|
||||||
|
"cross_alignment": 2,
|
||||||
|
"dimension": {
|
||||||
|
"type": "rigid",
|
||||||
|
"width": 80,
|
||||||
|
"height": 34
|
||||||
|
},
|
||||||
|
"placement": {
|
||||||
|
"type": "absolute",
|
||||||
|
"left": 135,
|
||||||
|
"top": 103
|
||||||
|
},
|
||||||
|
"visible": true,
|
||||||
|
"inversion": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"parent_id": 4,
|
||||||
|
"type": "text",
|
||||||
|
"text": "#middle_short_press_label",
|
||||||
|
"ppem": 17,
|
||||||
|
"color": 3,
|
||||||
|
"placement": {
|
||||||
|
"type": "relative"
|
||||||
|
},
|
||||||
|
"visible": true,
|
||||||
|
"inversion": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"parent_id": 4,
|
||||||
|
"type": "text",
|
||||||
|
"text": "#middle_long_press_label",
|
||||||
|
"ppem": 17,
|
||||||
|
"color": 3,
|
||||||
|
"ascent": 17,
|
||||||
|
"placement": {
|
||||||
|
"type": "relative"
|
||||||
|
},
|
||||||
|
"visible": true,
|
||||||
|
"inversion": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 7,
|
||||||
|
"parent_id": 0,
|
||||||
|
"type": "container",
|
||||||
|
"direction": 1,
|
||||||
|
"main_alignment": 1,
|
||||||
|
"cross_alignment": 2,
|
||||||
|
"dimension": {
|
||||||
|
"type": "rigid",
|
||||||
|
"width": 130,
|
||||||
|
"height": 34
|
||||||
|
},
|
||||||
|
"placement": {
|
||||||
|
"type": "absolute",
|
||||||
|
"left": 75,
|
||||||
|
"top": 161
|
||||||
|
},
|
||||||
|
"visible": true,
|
||||||
|
"inversion": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 8,
|
||||||
|
"parent_id": 7,
|
||||||
|
"type": "text",
|
||||||
|
"text": "#bottom_short_press_label",
|
||||||
|
"ppem": 17,
|
||||||
|
"color": 3,
|
||||||
|
"placement": {
|
||||||
|
"type": "relative"
|
||||||
|
},
|
||||||
|
"visible": true,
|
||||||
|
"inversion": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 9,
|
||||||
|
"parent_id": 7,
|
||||||
|
"type": "text",
|
||||||
|
"text": "#bottom_long_press_label",
|
||||||
|
"ppem": 17,
|
||||||
|
"color": 3,
|
||||||
|
"ascent": 17,
|
||||||
|
"placement": {
|
||||||
|
"type": "relative"
|
||||||
|
},
|
||||||
|
"visible": true,
|
||||||
|
"inversion": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 10,
|
||||||
|
"parent_id": 0,
|
||||||
|
"type": "text",
|
||||||
|
"text": "#menu_title",
|
||||||
|
"ppem": 25,
|
||||||
|
"color": 3,
|
||||||
|
"ascent": 35,
|
||||||
|
"placement": {
|
||||||
|
"type": "relative"
|
||||||
|
},
|
||||||
|
"visible": true,
|
||||||
|
"inversion": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 11,
|
||||||
|
"parent_id": 0,
|
||||||
|
"type": "text_page",
|
||||||
|
"text": "#message_to_display",
|
||||||
|
"ppem": 17,
|
||||||
|
"color": 3,
|
||||||
|
"ascent": 17,
|
||||||
|
"cross_alignment": 2,
|
||||||
|
"line_width": [
|
||||||
|
80,
|
||||||
|
85,
|
||||||
|
90,
|
||||||
|
90,
|
||||||
|
85,
|
||||||
|
80
|
||||||
|
],
|
||||||
|
"dimension": {
|
||||||
|
"type": "rigid",
|
||||||
|
"width": 80,
|
||||||
|
"height": 100
|
||||||
|
},
|
||||||
|
"placement": {
|
||||||
|
"type": "absolute",
|
||||||
|
"left": 20,
|
||||||
|
"top": 60
|
||||||
|
},
|
||||||
|
"visible": true,
|
||||||
|
"inversion": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
Binary file not shown.
@ -62,11 +62,13 @@ import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSett
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.database.DBOpenHelper;
|
import nodomain.freeyourgadget.gadgetbridge.database.DBOpenHelper;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.database.PeriodicExporter;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager;
|
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoMaster;
|
import nodomain.freeyourgadget.gadgetbridge.entities.DaoMaster;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.externalevents.BluetoothStateChangeReceiver;
|
import nodomain.freeyourgadget.gadgetbridge.externalevents.BluetoothStateChangeReceiver;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.externalevents.OpenTracksContentObserver;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceService;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceService;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
|
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
|
||||||
@ -143,6 +145,11 @@ public class GBApplication extends Application {
|
|||||||
private DeviceManager deviceManager;
|
private DeviceManager deviceManager;
|
||||||
private BluetoothStateChangeReceiver bluetoothStateChangeReceiver;
|
private BluetoothStateChangeReceiver bluetoothStateChangeReceiver;
|
||||||
|
|
||||||
|
private OpenTracksContentObserver openTracksObserver;
|
||||||
|
|
||||||
|
private long lastAutoExportTimestamp = 0;
|
||||||
|
private long autoExportScheduledTimestamp = 0;
|
||||||
|
|
||||||
public static void quit() {
|
public static void quit() {
|
||||||
GB.log("Quitting Gadgetbridge...", GB.INFO, null);
|
GB.log("Quitting Gadgetbridge...", GB.INFO, null);
|
||||||
Intent quitIntent = new Intent(GBApplication.ACTION_QUIT);
|
Intent quitIntent = new Intent(GBApplication.ACTION_QUIT);
|
||||||
@ -210,6 +217,8 @@ public class GBApplication extends Application {
|
|||||||
loadAppsPebbleBlackList();
|
loadAppsPebbleBlackList();
|
||||||
loadCalendarsBlackList();
|
loadCalendarsBlackList();
|
||||||
|
|
||||||
|
PeriodicExporter.enablePeriodicExport(context);
|
||||||
|
|
||||||
if (isRunningMarshmallowOrLater()) {
|
if (isRunningMarshmallowOrLater()) {
|
||||||
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
if (isRunningOreoOrLater()) {
|
if (isRunningOreoOrLater()) {
|
||||||
@ -1090,4 +1099,28 @@ public class GBApplication extends Application {
|
|||||||
return "Gadgetbridge";
|
return "Gadgetbridge";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setOpenTracksObserver(OpenTracksContentObserver openTracksObserver) {
|
||||||
|
this.openTracksObserver = openTracksObserver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OpenTracksContentObserver getOpenTracksObserver() {
|
||||||
|
return openTracksObserver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLastAutoExportTimestamp() {
|
||||||
|
return lastAutoExportTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastAutoExportTimestamp(long lastAutoExportTimestamp) {
|
||||||
|
this.lastAutoExportTimestamp = lastAutoExportTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getAutoExportScheduledTimestamp() {
|
||||||
|
return autoExportScheduledTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAutoExportScheduledTimestamp(long autoExportScheduledTimestamp) {
|
||||||
|
this.autoExportScheduledTimestamp = autoExportScheduledTimestamp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
@ -51,6 +52,7 @@ import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.database.PeriodicExporter;
|
import nodomain.freeyourgadget.gadgetbridge.database.PeriodicExporter;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.AndroidUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.AndroidUtils;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
|
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
|
||||||
@ -145,7 +147,7 @@ public class DataManagementActivity extends AbstractGBActivity {
|
|||||||
cleanExportDirectory();
|
cleanExportDirectory();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
GBApplication gbApp = GBApplication.app();
|
||||||
Prefs prefs = GBApplication.getPrefs();
|
Prefs prefs = GBApplication.getPrefs();
|
||||||
boolean autoExportEnabled = prefs.getBoolean(GBPrefs.AUTO_EXPORT_ENABLED, false);
|
boolean autoExportEnabled = prefs.getBoolean(GBPrefs.AUTO_EXPORT_ENABLED, false);
|
||||||
int autoExportInterval = prefs.getInt(GBPrefs.AUTO_EXPORT_INTERVAL, 0);
|
int autoExportInterval = prefs.getInt(GBPrefs.AUTO_EXPORT_INTERVAL, 0);
|
||||||
@ -153,16 +155,42 @@ public class DataManagementActivity extends AbstractGBActivity {
|
|||||||
//String autoExportLocation = prefs.getString(GBPrefs.AUTO_EXPORT_LOCATION, "");
|
//String autoExportLocation = prefs.getString(GBPrefs.AUTO_EXPORT_LOCATION, "");
|
||||||
|
|
||||||
int testExportVisibility = (autoExportInterval > 0 && autoExportEnabled) ? View.VISIBLE : View.GONE;
|
int testExportVisibility = (autoExportInterval > 0 && autoExportEnabled) ? View.VISIBLE : View.GONE;
|
||||||
|
boolean isExportEnabled = autoExportInterval > 0 && autoExportEnabled;
|
||||||
TextView autoExportLocation_label = findViewById(R.id.autoExportLocation_label);
|
TextView autoExportLocation_label = findViewById(R.id.autoExportLocation_label);
|
||||||
autoExportLocation_label.setVisibility(testExportVisibility);
|
autoExportLocation_label.setVisibility(testExportVisibility);
|
||||||
|
|
||||||
TextView autoExportLocation_intro = findViewById(R.id.autoExportLocation_intro);
|
|
||||||
autoExportLocation_intro.setVisibility(testExportVisibility);
|
|
||||||
|
|
||||||
TextView autoExportLocation_path = findViewById(R.id.autoExportLocation_path);
|
TextView autoExportLocation_path = findViewById(R.id.autoExportLocation_path);
|
||||||
autoExportLocation_path.setVisibility(testExportVisibility);
|
autoExportLocation_path.setVisibility(testExportVisibility);
|
||||||
autoExportLocation_path.setText(getAutoExportLocationSummary());
|
autoExportLocation_path.setText(getAutoExportLocationUserString() + " (" + getAutoExportLocationPreferenceString() + ")" );
|
||||||
|
|
||||||
|
TextView autoExportEnabled_label = findViewById(R.id.autoExportEnabled);
|
||||||
|
if (isExportEnabled) {
|
||||||
|
autoExportEnabled_label.setText(getString(R.string.activity_db_management_autoexport_enabled_yes));
|
||||||
|
} else {
|
||||||
|
autoExportEnabled_label.setText(getString(R.string.activity_db_management_autoexport_enabled_no));
|
||||||
|
}
|
||||||
|
|
||||||
|
TextView autoExportScheduled = findViewById(R.id.autoExportScheduled);
|
||||||
|
autoExportScheduled.setVisibility(testExportVisibility);
|
||||||
|
long setAutoExportScheduledTimestamp = gbApp.getAutoExportScheduledTimestamp();
|
||||||
|
if (setAutoExportScheduledTimestamp > 0) {
|
||||||
|
autoExportScheduled.setText(getString(R.string.activity_db_management_autoexport_scheduled_yes,
|
||||||
|
DateTimeUtils.formatDateTime(new Date(setAutoExportScheduledTimestamp))));
|
||||||
|
} else {
|
||||||
|
autoExportScheduled.setText(getResources().getString(R.string.activity_db_management_autoexport_scheduled_no));
|
||||||
|
}
|
||||||
|
|
||||||
|
TextView autoExport_lastTime_label = findViewById(R.id.autoExport_lastTime_label);
|
||||||
|
long lastAutoExportTimestamp = gbApp.getLastAutoExportTimestamp();
|
||||||
|
|
||||||
|
autoExport_lastTime_label.setVisibility(View.GONE);
|
||||||
|
autoExport_lastTime_label.setText(getString(R.string.autoExport_lastTime_label,
|
||||||
|
DateTimeUtils.formatDateTime(new Date(lastAutoExportTimestamp))));
|
||||||
|
|
||||||
|
if (lastAutoExportTimestamp > 0) {
|
||||||
|
autoExport_lastTime_label.setVisibility(testExportVisibility);
|
||||||
|
autoExport_lastTime_label.setVisibility(testExportVisibility);
|
||||||
|
}
|
||||||
|
|
||||||
final Context context = getApplicationContext();
|
final Context context = getApplicationContext();
|
||||||
Button testExportDBButton = findViewById(R.id.testExportDBButton);
|
Button testExportDBButton = findViewById(R.id.testExportDBButton);
|
||||||
@ -180,18 +208,25 @@ public class DataManagementActivity extends AbstractGBActivity {
|
|||||||
sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getAutoExportLocationPreferenceString() {
|
||||||
|
|
||||||
//would rather re-use method of SettingsActivity... but lifecycle...
|
|
||||||
private String getAutoExportLocationSummary() {
|
|
||||||
String autoExportLocation = GBApplication.getPrefs().getString(GBPrefs.AUTO_EXPORT_LOCATION, null);
|
String autoExportLocation = GBApplication.getPrefs().getString(GBPrefs.AUTO_EXPORT_LOCATION, null);
|
||||||
if (autoExportLocation == null) {
|
if (autoExportLocation == null) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
return autoExportLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getAutoExportLocationUri() {
|
||||||
|
String autoExportLocation = getAutoExportLocationPreferenceString();
|
||||||
|
if (autoExportLocation == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
Uri uri = Uri.parse(autoExportLocation);
|
Uri uri = Uri.parse(autoExportLocation);
|
||||||
try {
|
try {
|
||||||
|
|
||||||
return AndroidUtils.getFilePath(getApplicationContext(), uri);
|
return AndroidUtils.getFilePath(getApplicationContext(), uri);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
|
LOG.error("getFilePath did not work, trying to resolve content provider path");
|
||||||
try {
|
try {
|
||||||
Cursor cursor = getContentResolver().query(
|
Cursor cursor = getContentResolver().query(
|
||||||
uri,
|
uri,
|
||||||
@ -208,6 +243,13 @@ public class DataManagementActivity extends AbstractGBActivity {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getAutoExportLocationUserString() {
|
||||||
|
String location = getAutoExportLocationUri();
|
||||||
|
if (location == "") {
|
||||||
|
return getString(R.string.activity_db_management_autoexport_location);
|
||||||
|
}
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean hasOldActivityDatabase() {
|
private boolean hasOldActivityDatabase() {
|
||||||
return new DBHelper(this).existsDB("ActivityDatabase");
|
return new DBHelper(this).existsDB("ActivityDatabase");
|
||||||
@ -403,7 +445,7 @@ public class DataManagementActivity extends AbstractGBActivity {
|
|||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
try {
|
try {
|
||||||
File externalFilesDir = FileUtils.getExternalFilesDir();
|
File externalFilesDir = FileUtils.getExternalFilesDir();
|
||||||
String autoexportFile = getAutoExportLocationSummary();
|
String autoexportFile = getAutoExportLocationUri();
|
||||||
for (File file : externalFilesDir.listFiles()) {
|
for (File file : externalFilesDir.listFiles()) {
|
||||||
if (file.isFile() &&
|
if (file.isFile() &&
|
||||||
(!FileUtils.getExtension(file.toString()).toLowerCase().equals("gpx")) && //keep GPX files
|
(!FileUtils.getExtension(file.toString()).toLowerCase().equals("gpx")) && //keep GPX files
|
||||||
|
@ -35,6 +35,7 @@ import android.content.IntentFilter;
|
|||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
@ -70,6 +71,8 @@ import java.util.Locale;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
@ -83,6 +86,8 @@ import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager;
|
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.externalevents.OpenTracksContentObserver;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.externalevents.OpenTracksController;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
||||||
@ -508,6 +513,72 @@ public class DebugActivity extends AbstractGBActivity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Button startFitnessAppTracking = findViewById(R.id.startFitnessAppTracking);
|
||||||
|
startFitnessAppTracking.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
OpenTracksController.startRecording(DebugActivity.this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Button stopFitnessAppTracking = findViewById(R.id.stopFitnessAppTracking);
|
||||||
|
stopFitnessAppTracking.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
OpenTracksController.stopRecording(DebugActivity.this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Button showStatusFitnessAppTracking = findViewById(R.id.showStatusFitnessAppTracking);
|
||||||
|
final int delay = 2 * 1000;
|
||||||
|
|
||||||
|
showStatusFitnessAppTracking.setOnClickListener(new View.OnClickListener() {
|
||||||
|
final Handler handler = new Handler();
|
||||||
|
Runnable runnable;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
final AlertDialog.Builder fitnesStatusBuilder = new AlertDialog.Builder(DebugActivity.this);
|
||||||
|
fitnesStatusBuilder
|
||||||
|
.setCancelable(false)
|
||||||
|
.setTitle("openTracksObserver Status")
|
||||||
|
.setMessage("Starting openTracksObserver watcher, waiting for an update, refreshing every: " + delay + "ms")
|
||||||
|
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
handler.removeCallbacks(runnable);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
final AlertDialog alert = fitnesStatusBuilder.show();
|
||||||
|
|
||||||
|
|
||||||
|
runnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
LOG.debug("openTracksObserver debug watch dialog running");
|
||||||
|
handler.postDelayed(this, delay); //schedule next execution
|
||||||
|
|
||||||
|
OpenTracksContentObserver openTracksObserver = GBApplication.app().getOpenTracksObserver();
|
||||||
|
if (openTracksObserver == null) {
|
||||||
|
LOG.debug("openTracksObserver is null");
|
||||||
|
alert.cancel();
|
||||||
|
alert.setMessage("openTracksObserver not running");
|
||||||
|
alert.show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LOG.debug("openTracksObserver is not null, updating debug view");
|
||||||
|
long timeSecs = openTracksObserver.getTimeMillisChange() / 1000;
|
||||||
|
float distanceCM = openTracksObserver.getDistanceMeterChange() * 100;
|
||||||
|
|
||||||
|
LOG.debug("Time: " + timeSecs + " distanceCM " + distanceCM);
|
||||||
|
alert.cancel();
|
||||||
|
alert.setMessage("TimeSec: " + timeSecs + " distanceCM " + distanceCM);
|
||||||
|
alert.show();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
handler.postDelayed(runnable, delay);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -42,13 +42,13 @@ import android.os.Bundle;
|
|||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.preference.PreferenceCategory;
|
import android.preference.PreferenceCategory;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
import android.provider.Settings;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.database.PeriodicExporter;
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
|
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||||
|
|
||||||
@ -108,11 +108,31 @@ public class NotificationManagementActivity extends AbstractSettingsActivity {
|
|||||||
category.removePreference(pref);
|
category.removePreference(pref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pref = findPreference("notifications_settings");
|
||||||
|
pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||||
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
|
Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
|
||||||
|
//This could open notification channel settings, if needed...:
|
||||||
|
//Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
|
||||||
|
//intent.putExtra(Settings.EXTRA_CHANNEL_ID, GB.NOTIFICATION_CHANNEL_ID_TRANSFER);
|
||||||
|
startActivity(intent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (GBApplication.isRunningTenOrLater()) {
|
if (GBApplication.isRunningTenOrLater()) {
|
||||||
pref = findPreference("minimize_priority");
|
pref = findPreference("minimize_priority");
|
||||||
PreferenceCategory category = (PreferenceCategory) findPreference("pref_key_notifications");
|
PreferenceCategory category = (PreferenceCategory) findPreference("pref_key_notifications");
|
||||||
category.removePreference(pref);
|
category.removePreference(pref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!GBApplication.isRunningOreoOrLater()) {
|
||||||
|
pref = findPreference("notifications_settings");
|
||||||
|
PreferenceCategory category = (PreferenceCategory) findPreference("pref_key_notifications");
|
||||||
|
category.removePreference(pref);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,8 +19,11 @@
|
|||||||
package nodomain.freeyourgadget.gadgetbridge.activities;
|
package nodomain.freeyourgadget.gadgetbridge.activities;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
|
import android.app.AlertDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ResolveInfo;
|
import android.content.pm.ResolveInfo;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
@ -28,16 +31,19 @@ import android.location.Criteria;
|
|||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.location.LocationListener;
|
import android.location.LocationListener;
|
||||||
import android.location.LocationManager;
|
import android.location.LocationManager;
|
||||||
import android.media.Ringtone;
|
|
||||||
import android.media.RingtoneManager;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.EditTextPreference;
|
import android.preference.EditTextPreference;
|
||||||
import android.preference.ListPreference;
|
import android.preference.ListPreference;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.preference.PreferenceCategory;
|
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.provider.DocumentsContract;
|
import android.provider.DocumentsContract;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.Spinner;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.core.app.ActivityCompat;
|
import androidx.core.app.ActivityCompat;
|
||||||
@ -73,7 +79,8 @@ public class SettingsActivity extends AbstractSettingsActivity {
|
|||||||
public static final String PREF_MEASUREMENT_SYSTEM = "measurement_system";
|
public static final String PREF_MEASUREMENT_SYSTEM = "measurement_system";
|
||||||
|
|
||||||
private static final int FILE_REQUEST_CODE = 4711;
|
private static final int FILE_REQUEST_CODE = 4711;
|
||||||
|
private EditText fitnessAppEditText = null;
|
||||||
|
private int fitnessAppSelectionListSpinnerFirstRun = 0;
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@ -306,7 +313,7 @@ public class SettingsActivity extends AbstractSettingsActivity {
|
|||||||
Integer.valueOf((String) autoExportInterval));
|
Integer.valueOf((String) autoExportInterval));
|
||||||
preference.setSummary(summary);
|
preference.setSummary(summary);
|
||||||
boolean auto_export_enabled = GBApplication.getPrefs().getBoolean(GBPrefs.AUTO_EXPORT_ENABLED, false);
|
boolean auto_export_enabled = GBApplication.getPrefs().getBoolean(GBPrefs.AUTO_EXPORT_ENABLED, false);
|
||||||
PeriodicExporter.sheduleAlarm(getApplicationContext(), Integer.valueOf((String) autoExportInterval), auto_export_enabled);
|
PeriodicExporter.scheduleAlarm(getApplicationContext(), Integer.valueOf((String) autoExportInterval), auto_export_enabled);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -320,7 +327,7 @@ public class SettingsActivity extends AbstractSettingsActivity {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceChange(Preference preference, Object autoExportEnabled) {
|
public boolean onPreferenceChange(Preference preference, Object autoExportEnabled) {
|
||||||
int autoExportInterval = GBApplication.getPrefs().getInt(GBPrefs.AUTO_EXPORT_INTERVAL, 0);
|
int autoExportInterval = GBApplication.getPrefs().getInt(GBPrefs.AUTO_EXPORT_INTERVAL, 0);
|
||||||
PeriodicExporter.sheduleAlarm(getApplicationContext(), autoExportInterval, (boolean) autoExportEnabled);
|
PeriodicExporter.scheduleAlarm(getApplicationContext(), autoExportInterval, (boolean) autoExportEnabled);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -403,6 +410,70 @@ public class SettingsActivity extends AbstractSettingsActivity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//fitness app (OpenTracks) package name selection for OpenTracks observer
|
||||||
|
pref = findPreference("pref_key_opentracks_packagename");
|
||||||
|
pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||||
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
|
|
||||||
|
final LinearLayout outerLayout = new LinearLayout(SettingsActivity.this);
|
||||||
|
outerLayout.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
final LinearLayout innerLayout = new LinearLayout(SettingsActivity.this);
|
||||||
|
innerLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
innerLayout.setPadding(20, 0, 20, 0);
|
||||||
|
final Spinner selectionListSpinner = new Spinner(SettingsActivity.this);
|
||||||
|
String[] appListArray = getResources().getStringArray(R.array.fitness_tracking_apps_package_names);
|
||||||
|
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(SettingsActivity.this,
|
||||||
|
android.R.layout.simple_spinner_dropdown_item, appListArray);
|
||||||
|
selectionListSpinner.setAdapter(spinnerArrayAdapter);
|
||||||
|
fitnessAppSelectionListSpinnerFirstRun = 0;
|
||||||
|
addListenerOnSpinnerDeviceSelection(selectionListSpinner);
|
||||||
|
Prefs prefs = GBApplication.getPrefs();
|
||||||
|
String packageName = prefs.getString("opentracks_packagename", "de.dennisguse.opentracks");
|
||||||
|
fitnessAppEditText = new EditText(SettingsActivity.this);
|
||||||
|
fitnessAppEditText.setText(packageName);
|
||||||
|
innerLayout.addView(fitnessAppEditText);
|
||||||
|
outerLayout.addView(selectionListSpinner);
|
||||||
|
outerLayout.addView(innerLayout);
|
||||||
|
|
||||||
|
new AlertDialog.Builder(SettingsActivity.this)
|
||||||
|
.setCancelable(true)
|
||||||
|
.setTitle(R.string.pref_title_opentracks_packagename)
|
||||||
|
.setView(outerLayout)
|
||||||
|
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
SharedPreferences.Editor editor = GBApplication.getPrefs().getPreferences().edit();
|
||||||
|
editor.putString("opentracks_packagename", fitnessAppEditText.getText().toString());
|
||||||
|
editor.apply();
|
||||||
|
editor.commit();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton(R.string.Cancel, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addListenerOnSpinnerDeviceSelection(Spinner spinner) {
|
||||||
|
spinner.setOnItemSelectedListener(new SettingsActivity.CustomOnDeviceSelectedListener());
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CustomOnDeviceSelectedListener implements AdapterView.OnItemSelectedListener {
|
||||||
|
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
|
||||||
|
if (++fitnessAppSelectionListSpinnerFirstRun > 1) { //this prevents the setText to be set when spinner just is being initialized
|
||||||
|
fitnessAppEditText.setText(parent.getItemAtPosition(pos).toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNothingSelected(AdapterView<?> arg0) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -421,7 +492,7 @@ public class SettingsActivity extends AbstractSettingsActivity {
|
|||||||
.getPrefs().getBoolean(GBPrefs.AUTO_EXPORT_ENABLED, false);
|
.getPrefs().getBoolean(GBPrefs.AUTO_EXPORT_ENABLED, false);
|
||||||
int autoExportPeriod = GBApplication
|
int autoExportPeriod = GBApplication
|
||||||
.getPrefs().getInt(GBPrefs.AUTO_EXPORT_INTERVAL, 0);
|
.getPrefs().getInt(GBPrefs.AUTO_EXPORT_INTERVAL, 0);
|
||||||
PeriodicExporter.sheduleAlarm(getApplicationContext(), autoExportPeriod, autoExportEnabled);
|
PeriodicExporter.scheduleAlarm(getApplicationContext(), autoExportPeriod, autoExportEnabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,24 +44,30 @@ public class PeriodicExporter extends BroadcastReceiver {
|
|||||||
|
|
||||||
public static void enablePeriodicExport(Context context) {
|
public static void enablePeriodicExport(Context context) {
|
||||||
Prefs prefs = GBApplication.getPrefs();
|
Prefs prefs = GBApplication.getPrefs();
|
||||||
|
GBApplication gbApp = GBApplication.app();
|
||||||
|
long autoExportScheduled = gbApp.getAutoExportScheduledTimestamp();
|
||||||
boolean autoExportEnabled = prefs.getBoolean(GBPrefs.AUTO_EXPORT_ENABLED, false);
|
boolean autoExportEnabled = prefs.getBoolean(GBPrefs.AUTO_EXPORT_ENABLED, false);
|
||||||
Integer autoExportInterval = prefs.getInt(GBPrefs.AUTO_EXPORT_INTERVAL, 0);
|
Integer autoExportInterval = prefs.getInt(GBPrefs.AUTO_EXPORT_INTERVAL, 0);
|
||||||
sheduleAlarm(context, autoExportInterval, autoExportEnabled);
|
scheduleAlarm(context, autoExportInterval, autoExportEnabled && autoExportScheduled == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void sheduleAlarm(Context context, Integer autoExportInterval, boolean autoExportEnabled) {
|
public static void scheduleAlarm(Context context, Integer autoExportInterval, boolean autoExportEnabled) {
|
||||||
Intent i = new Intent(context, PeriodicExporter.class);
|
Intent i = new Intent(context, PeriodicExporter.class);
|
||||||
PendingIntent pi = PendingIntent.getBroadcast(context, 0 , i, 0);
|
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
|
||||||
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||||
am.cancel(pi);
|
am.cancel(pi);
|
||||||
if (!autoExportEnabled) {
|
if (!autoExportEnabled) {
|
||||||
|
LOG.info("Not scheduling periodic export, either already scheduled or not enabled");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int exportPeriod = autoExportInterval * 60 * 60 * 1000;
|
int exportPeriod = autoExportInterval * 60 * 60 * 1000;
|
||||||
if (exportPeriod == 0) {
|
if (exportPeriod == 0) {
|
||||||
|
LOG.info("Not scheduling periodic export, interval set to 0");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LOG.info("Enabling periodic export");
|
LOG.info("Scheduling periodic export");
|
||||||
|
GBApplication gbApp = GBApplication.app();
|
||||||
|
gbApp.setAutoExportScheduledTimestamp(System.currentTimeMillis() + exportPeriod);
|
||||||
am.setInexactRepeating(
|
am.setInexactRepeating(
|
||||||
AlarmManager.ELAPSED_REALTIME,
|
AlarmManager.ELAPSED_REALTIME,
|
||||||
SystemClock.elapsedRealtime() + exportPeriod,
|
SystemClock.elapsedRealtime() + exportPeriod,
|
||||||
@ -72,21 +78,46 @@ public class PeriodicExporter extends BroadcastReceiver {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
LOG.info("Exporting DB");
|
LOG.info("Received command to export DB");
|
||||||
|
createRefreshTask("Export database", context).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected RefreshTask createRefreshTask(String task, Context context) {
|
||||||
|
return new RefreshTask(task, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RefreshTask extends DBAccess {
|
||||||
|
Context localContext;
|
||||||
|
|
||||||
|
public RefreshTask(String task, Context context) {
|
||||||
|
super(task, context);
|
||||||
|
localContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doInBackground(DBHandler handler) {
|
||||||
|
LOG.info("Exporting DB in a background thread");
|
||||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||||
DBHelper helper = new DBHelper(context);
|
DBHelper helper = new DBHelper(localContext);
|
||||||
String dst = GBApplication.getPrefs().getString(GBPrefs.AUTO_EXPORT_LOCATION, null);
|
String dst = GBApplication.getPrefs().getString(GBPrefs.AUTO_EXPORT_LOCATION, null);
|
||||||
if (dst == null) {
|
if (dst == null) {
|
||||||
LOG.info("Unable to export DB, export location not set");
|
LOG.info("Unable to export DB, export location not set");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Uri dstUri = Uri.parse(dst);
|
Uri dstUri = Uri.parse(dst);
|
||||||
try (OutputStream out = context.getContentResolver().openOutputStream(dstUri)) {
|
try (OutputStream out = localContext.getContentResolver().openOutputStream(dstUri)) {
|
||||||
helper.exportDB(dbHandler, out);
|
helper.exportDB(dbHandler, out);
|
||||||
|
GBApplication gbApp = GBApplication.app();
|
||||||
|
gbApp.setLastAutoExportTimestamp(System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
GB.updateExportFailedNotification(context.getString(R.string.notif_export_failed_title), context);
|
GB.updateExportFailedNotification(localContext.getString(R.string.notif_export_failed_title), localContext);
|
||||||
LOG.info("Exception while exporting DB: ", ex);
|
LOG.info("Exception while exporting DB: ", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Object o) {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,8 @@ public class FitProDeviceCoordinator extends AbstractDeviceCoordinator {
|
|||||||
if (name != null && (
|
if (name != null && (
|
||||||
name.startsWith("M6") ||
|
name.startsWith("M6") ||
|
||||||
name.startsWith("M4") ||
|
name.startsWith("M4") ||
|
||||||
name.equals("LH716"))
|
name.equals("LH716") ||
|
||||||
|
name.equals("Fit1900"))
|
||||||
) {
|
) {
|
||||||
return DeviceType.FITPRO;
|
return DeviceType.FITPRO;
|
||||||
}
|
}
|
||||||
|
@ -80,6 +80,8 @@ public class HuamiConst {
|
|||||||
public static final String PREF_BUTTON_ACTION_BROADCAST = "button_action_broadcast";
|
public static final String PREF_BUTTON_ACTION_BROADCAST = "button_action_broadcast";
|
||||||
public static final String PREF_BUTTON_ACTION_SELECTION_OFF = "UNKNOWN";
|
public static final String PREF_BUTTON_ACTION_SELECTION_OFF = "UNKNOWN";
|
||||||
public static final String PREF_BUTTON_ACTION_SELECTION_BROADCAST = "BROADCAST";
|
public static final String PREF_BUTTON_ACTION_SELECTION_BROADCAST = "BROADCAST";
|
||||||
|
public static final String PREF_BUTTON_ACTION_SELECTION_FITNESS_APP_START = "FITNESS_CONTROL_START";
|
||||||
|
public static final String PREF_BUTTON_ACTION_SELECTION_FITNESS_APP_STOP = "FITNESS_CONTROL_STOP";
|
||||||
|
|
||||||
public static final String PREF_DEVICE_ACTION_SELECTION_OFF = "UNKNOWN";
|
public static final String PREF_DEVICE_ACTION_SELECTION_OFF = "UNKNOWN";
|
||||||
public static final String PREF_DEVICE_ACTION_SELECTION_BROADCAST = "BROADCAST";
|
public static final String PREF_DEVICE_ACTION_SELECTION_BROADCAST = "BROADCAST";
|
||||||
|
@ -39,11 +39,11 @@ public class FossilAppWriter {
|
|||||||
private String version;
|
private String version;
|
||||||
private LinkedHashMap<String, InputStream> code;
|
private LinkedHashMap<String, InputStream> code;
|
||||||
private LinkedHashMap<String, InputStream> icons;
|
private LinkedHashMap<String, InputStream> icons;
|
||||||
private LinkedHashMap<String, String> layout;
|
private LinkedHashMap<String, InputStream> layout;
|
||||||
private LinkedHashMap<String, String> displayName;
|
private LinkedHashMap<String, String> displayName;
|
||||||
private LinkedHashMap<String, String> config;
|
private LinkedHashMap<String, String> config;
|
||||||
|
|
||||||
public FossilAppWriter(Context context, String version, LinkedHashMap<String, InputStream> code, LinkedHashMap<String, InputStream> icons, LinkedHashMap<String, String> layout, LinkedHashMap<String, String> displayName, LinkedHashMap<String, String> config) {
|
public FossilAppWriter(Context context, String version, LinkedHashMap<String, InputStream> code, LinkedHashMap<String, InputStream> icons, LinkedHashMap<String, InputStream> layout, LinkedHashMap<String, String> displayName, LinkedHashMap<String, String> config) {
|
||||||
this.mContext = context;
|
this.mContext = context;
|
||||||
if (this.mContext == null) throw new AssertionError("context cannot be null");
|
if (this.mContext == null) throw new AssertionError("context cannot be null");
|
||||||
this.version = version;
|
this.version = version;
|
||||||
@ -61,9 +61,9 @@ public class FossilAppWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getWapp() throws IOException {
|
public byte[] getWapp() throws IOException {
|
||||||
byte[] codeData = loadFiles(code);
|
byte[] codeData = loadFiles(code, false);
|
||||||
byte[] iconsData = loadFiles(icons);
|
byte[] iconsData = loadFiles(icons, false);
|
||||||
byte[] layoutData = loadStringFiles(layout);
|
byte[] layoutData = loadFiles(layout, true);
|
||||||
byte[] displayNameData = loadStringFiles(displayName);
|
byte[] displayNameData = loadStringFiles(displayName);
|
||||||
byte[] configData = loadStringFiles(config);
|
byte[] configData = loadStringFiles(config);
|
||||||
|
|
||||||
@ -118,16 +118,23 @@ public class FossilAppWriter {
|
|||||||
return wapp.toByteArray();
|
return wapp.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] loadFiles(LinkedHashMap<String, InputStream> filesMap) throws IOException {
|
public byte[] loadFiles(LinkedHashMap<String, InputStream> filesMap, boolean appendNull) throws IOException {
|
||||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||||
for (String filename : filesMap.keySet()) {
|
for (String filename : filesMap.keySet()) {
|
||||||
InputStream in = filesMap.get(filename);
|
InputStream in = filesMap.get(filename);
|
||||||
output.write((byte)filename.length() + 1);
|
output.write((byte)filename.length() + 1);
|
||||||
output.write(StringUtils.terminateNull(filename).getBytes(StandardCharsets.UTF_8));
|
output.write(StringUtils.terminateNull(filename).getBytes(StandardCharsets.UTF_8));
|
||||||
output.write(shortToLEBytes((short)in.available()));
|
int fileLength = in.available();
|
||||||
|
if(appendNull){
|
||||||
|
fileLength++;
|
||||||
|
}
|
||||||
|
output.write(shortToLEBytes((short)fileLength));
|
||||||
byte[] fileBytes = new byte[in.available()];
|
byte[] fileBytes = new byte[in.available()];
|
||||||
in.read(fileBytes);
|
in.read(fileBytes);
|
||||||
output.write(fileBytes);
|
output.write(fileBytes);
|
||||||
|
if(appendNull){
|
||||||
|
output.write(0x00);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return output.toByteArray();
|
return output.toByteArray();
|
||||||
}
|
}
|
||||||
|
@ -456,6 +456,9 @@ public class HybridHRWatchfaceDesignerActivity extends AbstractGBActivity implem
|
|||||||
if (watchfaceConfig.has("powersave_hands")) {
|
if (watchfaceConfig.has("powersave_hands")) {
|
||||||
watchfaceSettings.setPowersaveHands(watchfaceConfig.getBoolean("powersave_hands"));
|
watchfaceSettings.setPowersaveHands(watchfaceConfig.getBoolean("powersave_hands"));
|
||||||
}
|
}
|
||||||
|
if (watchfaceConfig.has("light_up_on_notification")) {
|
||||||
|
watchfaceSettings.setLightUpOnNotification(watchfaceConfig.getBoolean("light_up_on_notification"));
|
||||||
|
}
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
LOG.warn("JSON parsing error", e);
|
LOG.warn("JSON parsing error", e);
|
||||||
}
|
}
|
||||||
@ -576,39 +579,46 @@ public class HybridHRWatchfaceDesignerActivity extends AbstractGBActivity implem
|
|||||||
if (widget != null) {
|
if (widget != null) {
|
||||||
posY.setText(Integer.toString(widget.getPosY()));
|
posY.setText(Integer.toString(widget.getPosY()));
|
||||||
}
|
}
|
||||||
// Configure position preset buttons
|
|
||||||
Button btnTop = layout.findViewById(R.id.watchface_widget_preset_top);
|
class WidgetPosition{
|
||||||
btnTop.setOnClickListener(new View.OnClickListener() {
|
final int posX, posY, buttonResource, hintStringResource;
|
||||||
|
|
||||||
|
public WidgetPosition(int posX, int posY, int buttonResource, int hintStringResource) {
|
||||||
|
this.posX = posX;
|
||||||
|
this.posY = posY;
|
||||||
|
this.buttonResource = buttonResource;
|
||||||
|
this.hintStringResource = hintStringResource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WidgetPosition[] positions = new WidgetPosition[]{
|
||||||
|
new WidgetPosition(120, 58, R.id.watchface_widget_preset_top, R.string.watchface_dialog_widget_preset_top),
|
||||||
|
new WidgetPosition(182, 120, R.id.watchface_widget_preset_right, R.string.watchface_dialog_widget_preset_right),
|
||||||
|
new WidgetPosition(120, 182, R.id.watchface_widget_preset_bottom, R.string.watchface_dialog_widget_preset_bottom),
|
||||||
|
new WidgetPosition(58, 120, R.id.watchface_widget_preset_left, R.string.watchface_dialog_widget_preset_left),
|
||||||
|
};
|
||||||
|
|
||||||
|
for(final WidgetPosition position : positions){
|
||||||
|
Button btn = layout.findViewById(position.buttonResource);
|
||||||
|
btn.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
posX.setText("120");
|
posX.setText(String.valueOf(position.posX));
|
||||||
posY.setText("58");
|
posY.setText(String.valueOf(position.posY));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Button btnBottom = layout.findViewById(R.id.watchface_widget_preset_bottom);
|
|
||||||
btnBottom.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
posX.setText("120");
|
|
||||||
posY.setText("182");
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
Button btnLeft = layout.findViewById(R.id.watchface_widget_preset_left);
|
if(widget == null){
|
||||||
btnLeft.setOnClickListener(new View.OnClickListener() {
|
int currentIndex = widgets.size();
|
||||||
@Override
|
if(currentIndex < 4){
|
||||||
public void onClick(View v) {
|
WidgetPosition newPosition = positions[currentIndex];
|
||||||
posX.setText("58");
|
posX.setText(String.valueOf(newPosition.posX));
|
||||||
posY.setText("120");
|
posY.setText(String.valueOf(newPosition.posY));
|
||||||
|
GB.toast(getString(R.string.watchface_dialog_pre_setting_position, getString(newPosition.hintStringResource)), Toast.LENGTH_SHORT, GB.INFO);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
Button btnRight = layout.findViewById(R.id.watchface_widget_preset_right);
|
|
||||||
btnRight.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
posX.setText("182");
|
|
||||||
posY.setText("120");
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
// Set widget size
|
// Set widget size
|
||||||
final LinearLayout sizeLayout = layout.findViewById(R.id.watchface_widget_size_layout);
|
final LinearLayout sizeLayout = layout.findViewById(R.id.watchface_widget_size_layout);
|
||||||
sizeLayout.setVisibility(View.GONE);
|
sizeLayout.setVisibility(View.GONE);
|
||||||
|
@ -185,22 +185,15 @@ public class HybridHRWatchfaceFactory {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LOG.warn("Unable to read asset file", e);
|
LOG.warn("Unable to read asset file", e);
|
||||||
}
|
}
|
||||||
LinkedHashMap<String, String> layout = new LinkedHashMap<>();
|
LinkedHashMap<String, InputStream> layout = new LinkedHashMap<>();
|
||||||
try {
|
layout.put("complication_layout", context.getAssets().open("fossil_hr/complication_layout.json"));
|
||||||
layout.put("complication_layout", getComplicationLayout());
|
layout.put("image_layout", context.getAssets().open("fossil_hr/image_layout.json"));
|
||||||
} catch (JSONException e) {
|
layout.put("menu_layout", context.getAssets().open("fossil_hr/menu_layout.json"));
|
||||||
LOG.warn("Could not generate complication_layout", e);
|
|
||||||
}
|
if (includeWidget("widgetBattery") > 0) {
|
||||||
try {
|
layout.put("battery_layout", context.getAssets().open("fossil_hr/battery_layout.json"));
|
||||||
layout.put("image_layout", getImageLayout());
|
|
||||||
} catch (JSONException e) {
|
|
||||||
LOG.warn("Could not generate image_layout", e);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if (includeWidget("widgetBattery") > 0) layout.put("battery_layout", getBatteryLayout());
|
|
||||||
} catch (JSONException e) {
|
|
||||||
LOG.warn("Could not generate battery_layout", e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkedHashMap<String, String> displayName = new LinkedHashMap<>();
|
LinkedHashMap<String, String> displayName = new LinkedHashMap<>();
|
||||||
displayName.put("display_name", watchfaceName);
|
displayName.put("display_name", watchfaceName);
|
||||||
displayName.put("theme_class", "complications");
|
displayName.put("theme_class", "complications");
|
||||||
@ -214,184 +207,6 @@ public class HybridHRWatchfaceFactory {
|
|||||||
return appWriter.getWapp();
|
return appWriter.getWapp();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getBatteryLayout() throws JSONException {
|
|
||||||
JSONArray batteryLayout = new JSONArray();
|
|
||||||
|
|
||||||
JSONObject complicationBackground = new JSONObject();
|
|
||||||
complicationBackground.put("id", 0);
|
|
||||||
complicationBackground.put("type", "complication_background");
|
|
||||||
complicationBackground.put("background", "#background");
|
|
||||||
complicationBackground.put("visible", true);
|
|
||||||
complicationBackground.put("inversion", false);
|
|
||||||
JSONObject goalRing = new JSONObject();
|
|
||||||
goalRing.put("is_enable", "#goal_ring");
|
|
||||||
goalRing.put("end_angle", "#fi");
|
|
||||||
goalRing.put("is_invert", "#$e");
|
|
||||||
complicationBackground.put("goal_ring", goalRing);
|
|
||||||
JSONObject dimension = new JSONObject();
|
|
||||||
dimension.put("type", "rigid");
|
|
||||||
dimension.put("width", "#size.w");
|
|
||||||
dimension.put("height", "#size.h");
|
|
||||||
complicationBackground.put("dimension", dimension);
|
|
||||||
JSONObject placement = new JSONObject();
|
|
||||||
placement.put("type", "absolute");
|
|
||||||
placement.put("left", "#pos.Ue");
|
|
||||||
placement.put("top", "#pos.Qe");
|
|
||||||
complicationBackground.put("placement", placement);
|
|
||||||
batteryLayout.put(complicationBackground);
|
|
||||||
|
|
||||||
JSONObject complicationContent = new JSONObject();
|
|
||||||
complicationContent.put("id", 1);
|
|
||||||
complicationContent.put("parent_id", 0);
|
|
||||||
complicationContent.put("type", "complication_content");
|
|
||||||
complicationContent.put("icon", "icBattery");
|
|
||||||
complicationContent.put("text_low", "#ci");
|
|
||||||
complicationContent.put("visible", true);
|
|
||||||
complicationContent.put("inversion", "#$e");
|
|
||||||
dimension = new JSONObject();
|
|
||||||
dimension.put("type", "rigid");
|
|
||||||
dimension.put("width", 76);
|
|
||||||
dimension.put("height", 76);
|
|
||||||
complicationContent.put("dimension", dimension);
|
|
||||||
placement = new JSONObject();
|
|
||||||
placement.put("type", "relative");
|
|
||||||
complicationContent.put("placement", placement);
|
|
||||||
batteryLayout.put(complicationContent);
|
|
||||||
|
|
||||||
JSONObject chargingStatus = new JSONObject();
|
|
||||||
chargingStatus.put("id", 2);
|
|
||||||
chargingStatus.put("parent_id", 1);
|
|
||||||
chargingStatus.put("type", "solid");
|
|
||||||
chargingStatus.put("color", "#nt");
|
|
||||||
chargingStatus.put("visible", true);
|
|
||||||
chargingStatus.put("inversion", false);
|
|
||||||
dimension = new JSONObject();
|
|
||||||
dimension.put("type", "rigid");
|
|
||||||
dimension.put("width", "#it");
|
|
||||||
dimension.put("height", 6);
|
|
||||||
chargingStatus.put("dimension", dimension);
|
|
||||||
placement = new JSONObject();
|
|
||||||
placement.put("type", "absolute");
|
|
||||||
placement.put("left", 29);
|
|
||||||
placement.put("top", 23);
|
|
||||||
chargingStatus.put("placement", placement);
|
|
||||||
batteryLayout.put(chargingStatus);
|
|
||||||
|
|
||||||
JSONObject image = new JSONObject();
|
|
||||||
image.put("id", 3);
|
|
||||||
image.put("parent_id", 1);
|
|
||||||
image.put("type", "image");
|
|
||||||
image.put("image_name", "icBattCharging");
|
|
||||||
image.put("draw_mode", 1);
|
|
||||||
image.put("visible", "#et");
|
|
||||||
image.put("inversion", false);
|
|
||||||
placement = new JSONObject();
|
|
||||||
placement.put("type", "absolute");
|
|
||||||
placement.put("left", 34);
|
|
||||||
placement.put("top", 21);
|
|
||||||
image.put("placement", placement);
|
|
||||||
dimension = new JSONObject();
|
|
||||||
dimension.put("width", 6);
|
|
||||||
dimension.put("height", 9);
|
|
||||||
image.put("dimension", dimension);
|
|
||||||
batteryLayout.put(image);
|
|
||||||
|
|
||||||
return batteryLayout.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getComplicationLayout() throws JSONException {
|
|
||||||
JSONArray complicationLayout = new JSONArray();
|
|
||||||
|
|
||||||
JSONObject complicationBackground = new JSONObject();
|
|
||||||
complicationBackground.put("id", 0);
|
|
||||||
complicationBackground.put("type", "complication_background");
|
|
||||||
complicationBackground.put("background", "#background");
|
|
||||||
complicationBackground.put("visible", true);
|
|
||||||
complicationBackground.put("inversion", false);
|
|
||||||
JSONObject goalRing = new JSONObject();
|
|
||||||
goalRing.put("is_enable", "#goal_ring");
|
|
||||||
goalRing.put("end_angle", "#fi");
|
|
||||||
goalRing.put("is_invert", "#$e");
|
|
||||||
complicationBackground.put("goal_ring", goalRing);
|
|
||||||
JSONObject dimension = new JSONObject();
|
|
||||||
dimension.put("type", "rigid");
|
|
||||||
dimension.put("width", "#size.w");
|
|
||||||
dimension.put("height", "#size.h");
|
|
||||||
complicationBackground.put("dimension", dimension);
|
|
||||||
JSONObject placement = new JSONObject();
|
|
||||||
placement.put("type", "absolute");
|
|
||||||
placement.put("left", "#pos.Ue");
|
|
||||||
placement.put("top", "#pos.Qe");
|
|
||||||
complicationBackground.put("placement", placement);
|
|
||||||
complicationLayout.put(complicationBackground);
|
|
||||||
|
|
||||||
JSONObject complicationContent = new JSONObject();
|
|
||||||
complicationContent.put("id", 1);
|
|
||||||
complicationContent.put("parent_id", 0);
|
|
||||||
complicationContent.put("type", "complication_content");
|
|
||||||
complicationContent.put("icon", "#icon");
|
|
||||||
complicationContent.put("text_high", "#dt");
|
|
||||||
complicationContent.put("text_low", "#ci");
|
|
||||||
complicationContent.put("visible", true);
|
|
||||||
complicationContent.put("inversion", "#$e");
|
|
||||||
dimension = new JSONObject();
|
|
||||||
dimension.put("type", "rigid");
|
|
||||||
dimension.put("width", "#size.w");
|
|
||||||
dimension.put("height", "#size.h");
|
|
||||||
complicationContent.put("dimension", dimension);
|
|
||||||
placement = new JSONObject();
|
|
||||||
placement.put("type", "relative");
|
|
||||||
complicationContent.put("placement", placement);
|
|
||||||
complicationLayout.put(complicationContent);
|
|
||||||
|
|
||||||
return complicationLayout.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getImageLayout() throws JSONException {
|
|
||||||
JSONArray imageLayout = new JSONArray();
|
|
||||||
|
|
||||||
JSONObject container = new JSONObject();
|
|
||||||
container.put("id", 0);
|
|
||||||
container.put("type", "container");
|
|
||||||
container.put("direction", 1);
|
|
||||||
container.put("main_alignment", 1);
|
|
||||||
container.put("cross_alignment", 1);
|
|
||||||
container.put("visible", true);
|
|
||||||
container.put("inversion", false);
|
|
||||||
JSONObject dimension = new JSONObject();
|
|
||||||
dimension.put("type", "rigid");
|
|
||||||
dimension.put("width", 240);
|
|
||||||
dimension.put("height", 240);
|
|
||||||
container.put("dimension", dimension);
|
|
||||||
JSONObject placement = new JSONObject();
|
|
||||||
placement.put("type", "absolute");
|
|
||||||
placement.put("left", 0);
|
|
||||||
placement.put("top", 0);
|
|
||||||
container.put("placement", placement);
|
|
||||||
imageLayout.put(container);
|
|
||||||
|
|
||||||
JSONObject image = new JSONObject();
|
|
||||||
image.put("id", 1);
|
|
||||||
image.put("parent_id", 0);
|
|
||||||
image.put("type", "image");
|
|
||||||
image.put("image_name", "#name");
|
|
||||||
image.put("draw_mode", 1);
|
|
||||||
image.put("visible", true);
|
|
||||||
image.put("inversion", false);
|
|
||||||
placement = new JSONObject();
|
|
||||||
placement.put("type", "absolute");
|
|
||||||
placement.put("left", "#pos.Ue");
|
|
||||||
placement.put("top", "#pos.Qe");
|
|
||||||
image.put("placement", placement);
|
|
||||||
dimension = new JSONObject();
|
|
||||||
dimension.put("width", "#size.w");
|
|
||||||
dimension.put("height", "#size.h");
|
|
||||||
image.put("dimension", dimension);
|
|
||||||
imageLayout.put(image);
|
|
||||||
|
|
||||||
return imageLayout.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getConfiguration() throws JSONException {
|
private String getConfiguration() throws JSONException {
|
||||||
JSONObject configuration = new JSONObject();
|
JSONObject configuration = new JSONObject();
|
||||||
|
|
||||||
@ -432,6 +247,7 @@ public class HybridHRWatchfaceFactory {
|
|||||||
config.put("wrist_flick_duration", settings.getWristFlickDuration());
|
config.put("wrist_flick_duration", settings.getWristFlickDuration());
|
||||||
config.put("wrist_flick_move_hour", settings.getWristFlickMoveHour());
|
config.put("wrist_flick_move_hour", settings.getWristFlickMoveHour());
|
||||||
config.put("wrist_flick_move_minute", settings.getWristFlickMoveMinute());
|
config.put("wrist_flick_move_minute", settings.getWristFlickMoveMinute());
|
||||||
|
config.put("light_up_on_notification", settings.getLightUpOnNotification());
|
||||||
config.put("powersave_display", settings.getPowersaveDisplay());
|
config.put("powersave_display", settings.getPowersaveDisplay());
|
||||||
config.put("powersave_hands", settings.getPowersaveHands());
|
config.put("powersave_hands", settings.getPowersaveHands());
|
||||||
configuration.put("config", config);
|
configuration.put("config", config);
|
||||||
|
@ -27,6 +27,7 @@ public class HybridHRWatchfaceSettings implements Serializable {
|
|||||||
private int wristFlickMoveMinute = -360;
|
private int wristFlickMoveMinute = -360;
|
||||||
private boolean powersaveDisplay = false;
|
private boolean powersaveDisplay = false;
|
||||||
private boolean powersaveHands = false;
|
private boolean powersaveHands = false;
|
||||||
|
private boolean lightUpOnNotification = false;
|
||||||
|
|
||||||
public HybridHRWatchfaceSettings() {
|
public HybridHRWatchfaceSettings() {
|
||||||
}
|
}
|
||||||
@ -63,6 +64,14 @@ public class HybridHRWatchfaceSettings implements Serializable {
|
|||||||
this.wristFlickDuration = wristFlickDuration;
|
this.wristFlickDuration = wristFlickDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean getLightUpOnNotification() {
|
||||||
|
return lightUpOnNotification;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLightUpOnNotification(boolean lightUpOnNotification) {
|
||||||
|
this.lightUpOnNotification = lightUpOnNotification;
|
||||||
|
}
|
||||||
|
|
||||||
public int getWristFlickMoveHour() {
|
public int getWristFlickMoveHour() {
|
||||||
return wristFlickMoveHour;
|
return wristFlickMoveHour;
|
||||||
}
|
}
|
||||||
|
@ -111,6 +111,10 @@ public class HybridHRWatchfaceSettingsActivity extends AbstractSettingsActivity
|
|||||||
SwitchPreference power_saving_hands = (SwitchPreference) findPreference("pref_hybridhr_watchface_power_saving_hands");
|
SwitchPreference power_saving_hands = (SwitchPreference) findPreference("pref_hybridhr_watchface_power_saving_hands");
|
||||||
power_saving_hands.setOnPreferenceChangeListener(new PreferenceChangeListener());
|
power_saving_hands.setOnPreferenceChangeListener(new PreferenceChangeListener());
|
||||||
power_saving_hands.setChecked(settings.getPowersaveHands());
|
power_saving_hands.setChecked(settings.getPowersaveHands());
|
||||||
|
|
||||||
|
SwitchPreference light_up_on_notification = (SwitchPreference) findPreference("pref_hybridhr_watchface_light_up_on_notification");
|
||||||
|
light_up_on_notification.setOnPreferenceChangeListener(new PreferenceChangeListener());
|
||||||
|
light_up_on_notification.setChecked(settings.getLightUpOnNotification());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class PreferenceChangeListener implements Preference.OnPreferenceChangeListener {
|
private static class PreferenceChangeListener implements Preference.OnPreferenceChangeListener {
|
||||||
@ -136,6 +140,9 @@ public class HybridHRWatchfaceSettingsActivity extends AbstractSettingsActivity
|
|||||||
settings.setWristFlickMoveMinute(Integer.parseInt(newValue.toString()));
|
settings.setWristFlickMoveMinute(Integer.parseInt(newValue.toString()));
|
||||||
preference.setSummary(newValue.toString());
|
preference.setSummary(newValue.toString());
|
||||||
break;
|
break;
|
||||||
|
case "pref_hybridhr_watchface_light_up_on_notification":
|
||||||
|
settings.setLightUpOnNotification((boolean) newValue);
|
||||||
|
break;
|
||||||
case "pref_hybridhr_watchface_wrist_flick_duration":
|
case "pref_hybridhr_watchface_wrist_flick_duration":
|
||||||
settings.setWristFlickDuration(Integer.parseInt(newValue.toString()));
|
settings.setWristFlickDuration(Integer.parseInt(newValue.toString()));
|
||||||
preference.setSummary(newValue.toString());
|
preference.setSummary(newValue.toString());
|
||||||
|
@ -5,17 +5,21 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity;
|
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.um25.Data.MeasurementData;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.um25.Data.MeasurementData;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.um25.Support.UM25Support;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.um25.Support.UM25Support;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
|
||||||
public class DataActivity extends AbstractGBActivity {
|
public class DataActivity extends AbstractGBActivity {
|
||||||
private HashMap<Integer, TextView> valueViews = new HashMap<>(ValueDisplay.values().length);
|
private HashMap<Integer, TextView> valueViews = new HashMap<>(ValueDisplay.values().length);
|
||||||
@ -51,6 +55,21 @@ public class DataActivity extends AbstractGBActivity {
|
|||||||
setContentView(R.layout.activity_um25_data);
|
setContentView(R.layout.activity_um25_data);
|
||||||
|
|
||||||
chargeDurationTextView = findViewById(R.id.um25_text_charge_duration);
|
chargeDurationTextView = findViewById(R.id.um25_text_charge_duration);
|
||||||
|
TextView wattHoursTextView = findViewById(R.id.um25_text_wattage_sum);
|
||||||
|
|
||||||
|
View.OnLongClickListener longClickListener = new View.OnLongClickListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onLongClick(View v) {
|
||||||
|
GB.toast("resetting", Toast.LENGTH_SHORT, GB.INFO);
|
||||||
|
LocalBroadcastManager.getInstance(DataActivity.this).sendBroadcast(
|
||||||
|
new Intent(UM25Support.ACTION_RESET_STATS)
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
chargeDurationTextView.setOnLongClickListener(longClickListener);
|
||||||
|
wattHoursTextView.setOnLongClickListener(longClickListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -72,8 +72,8 @@ public class VescControlActivity extends AbstractGBActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void restoreValues(){
|
private void restoreValues(){
|
||||||
rpmEditText.setText(preferences.getInt(PREFS_KEY_LAST_RPM, 0));
|
rpmEditText.setText(String.valueOf(preferences.getInt(PREFS_KEY_LAST_RPM, 0)));
|
||||||
breakCurrentEditText.setText(preferences.getInt(PREFS_KEY_LAST_BREAK_CURRENT, 0));
|
breakCurrentEditText.setText(String.valueOf(preferences.getInt(PREFS_KEY_LAST_BREAK_CURRENT, 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -29,6 +29,9 @@ public class XWatchService {
|
|||||||
public static final byte COMMAND_ACTION_BUTTON = 0x4c;
|
public static final byte COMMAND_ACTION_BUTTON = 0x4c;
|
||||||
public static final byte COMMAND_ACTIVITY_DATA = 0x43;
|
public static final byte COMMAND_ACTIVITY_DATA = 0x43;
|
||||||
public static final byte COMMAND_ACTIVITY_TOTALS = 0x46;
|
public static final byte COMMAND_ACTIVITY_TOTALS = 0x46;
|
||||||
|
public static final byte COMMAND_NOTIFICATION = 0x4d;
|
||||||
|
public static final byte COMMAND_NOTIFICATION_PHONE = 0x00;
|
||||||
|
public static final byte COMMAND_NOTIFICATION_MESSAGE = 0x01;
|
||||||
|
|
||||||
private static final Map<UUID, String> XWATCH_DEBUG;
|
private static final Map<UUID, String> XWATCH_DEBUG;
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ public class AutoStartReceiver extends BroadcastReceiver {
|
|||||||
} else {
|
} else {
|
||||||
GBApplication.deviceService().start();
|
GBApplication.deviceService().start();
|
||||||
}
|
}
|
||||||
|
Log.i(TAG, "Going to enable periodic exporter");
|
||||||
PeriodicExporter.enablePeriodicExport(context);
|
PeriodicExporter.enablePeriodicExport(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -881,6 +881,7 @@ public class NotificationListener extends NotificationListenerService {
|
|||||||
String source = sbn.getPackageName();
|
String source = sbn.getPackageName();
|
||||||
if (source.equals("de.dennisguse.opentracks")
|
if (source.equals("de.dennisguse.opentracks")
|
||||||
|| source.equals("de.dennisguse.opentracks.debug")
|
|| source.equals("de.dennisguse.opentracks.debug")
|
||||||
|
|| source.equals("de.dennisguse.opentracks.nightly")
|
||||||
|| source.equals("de.tadris.fitness")
|
|| source.equals("de.tadris.fitness")
|
||||||
|| source.equals("de.tadris.fitness.debug")
|
|| source.equals("de.tadris.fitness.debug")
|
||||||
) {
|
) {
|
||||||
|
@ -0,0 +1,393 @@
|
|||||||
|
/* Copyright (C) 2022 Arjan Schrijver
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.externalevents;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.ContentObserver;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Handler;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
public class OpenTracksContentObserver extends ContentObserver {
|
||||||
|
private Context mContext;
|
||||||
|
private Uri tracksUri;
|
||||||
|
private int protocolVersion;
|
||||||
|
private int totalTimeMillis;
|
||||||
|
private float totalDistanceMeter;
|
||||||
|
|
||||||
|
private long previousTimeMillis = 0;
|
||||||
|
private float previousDistanceMeter = 0;
|
||||||
|
|
||||||
|
public int getTotalTimeMillis() {
|
||||||
|
return totalTimeMillis;
|
||||||
|
}
|
||||||
|
public float getTotalDistanceMeter() {
|
||||||
|
return totalDistanceMeter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTimeMillisChange() {
|
||||||
|
/**
|
||||||
|
* We don't use the timeMillis received from OpenTracks here, because those updates do not
|
||||||
|
* come in very regularly when GPS reception is bad
|
||||||
|
*/
|
||||||
|
long timeMillisDelta = System.currentTimeMillis() - previousTimeMillis;
|
||||||
|
previousTimeMillis = System.currentTimeMillis();
|
||||||
|
return timeMillisDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getDistanceMeterChange() {
|
||||||
|
float distanceMeterDelta = totalDistanceMeter - previousDistanceMeter;
|
||||||
|
previousDistanceMeter = totalDistanceMeter;
|
||||||
|
return distanceMeterDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public OpenTracksContentObserver(Context context, final Uri tracksUri, final int protocolVersion) {
|
||||||
|
super(new Handler());
|
||||||
|
this.mContext = context;
|
||||||
|
this.tracksUri = tracksUri;
|
||||||
|
this.protocolVersion = protocolVersion;
|
||||||
|
this.previousTimeMillis = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChange(final boolean selfChange, final Uri uri) {
|
||||||
|
if (uri == null) {
|
||||||
|
return; // nothing can be done without an uri
|
||||||
|
}
|
||||||
|
if (tracksUri.toString().startsWith(uri.toString())) {
|
||||||
|
final List<Track> tracks = Track.readTracks(mContext.getContentResolver(), tracksUri, protocolVersion);
|
||||||
|
if (!tracks.isEmpty()) {
|
||||||
|
final TrackStatistics statistics = new TrackStatistics(tracks);
|
||||||
|
totalTimeMillis = statistics.getTotalTimeMillis();
|
||||||
|
totalDistanceMeter = statistics.getTotalDistanceMeter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unregister() {
|
||||||
|
if (mContext != null) {
|
||||||
|
mContext.getContentResolver().unregisterContentObserver(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void finish() {
|
||||||
|
unregister();
|
||||||
|
if (mContext != null) {
|
||||||
|
((Activity) mContext).finish();
|
||||||
|
mContext = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Track {
|
||||||
|
/**
|
||||||
|
* This class was copied and modified from
|
||||||
|
* https://github.com/OpenTracksApp/OSMDashboard/blob/main/src/main/java/de/storchp/opentracks/osmplugin/dashboardapi/Track.java
|
||||||
|
*/
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(Track.class);
|
||||||
|
|
||||||
|
private static final String TAG = Track.class.getSimpleName();
|
||||||
|
|
||||||
|
public static final String _ID = "_id";
|
||||||
|
public static final String NAME = "name"; // track name
|
||||||
|
public static final String DESCRIPTION = "description"; // track description
|
||||||
|
public static final String CATEGORY = "category"; // track activity type
|
||||||
|
public static final String STARTTIME = "starttime"; // track start time
|
||||||
|
public static final String STOPTIME = "stoptime"; // track stop time
|
||||||
|
public static final String TOTALDISTANCE = "totaldistance"; // total distance
|
||||||
|
public static final String TOTALTIME = "totaltime"; // total time
|
||||||
|
public static final String MOVINGTIME = "movingtime"; // moving time
|
||||||
|
public static final String AVGSPEED = "avgspeed"; // average speed
|
||||||
|
public static final String AVGMOVINGSPEED = "avgmovingspeed"; // average moving speed
|
||||||
|
public static final String MAXSPEED = "maxspeed"; // maximum speed
|
||||||
|
public static final String MINELEVATION = "minelevation"; // minimum elevation
|
||||||
|
public static final String MAXELEVATION = "maxelevation"; // maximum elevation
|
||||||
|
public static final String ELEVATIONGAIN = "elevationgain"; // elevation gain
|
||||||
|
|
||||||
|
public static final String[] PROJECTION = {
|
||||||
|
_ID,
|
||||||
|
NAME,
|
||||||
|
DESCRIPTION,
|
||||||
|
CATEGORY,
|
||||||
|
STARTTIME,
|
||||||
|
STOPTIME,
|
||||||
|
TOTALDISTANCE,
|
||||||
|
TOTALTIME,
|
||||||
|
MOVINGTIME,
|
||||||
|
AVGSPEED,
|
||||||
|
AVGMOVINGSPEED,
|
||||||
|
MAXSPEED,
|
||||||
|
MINELEVATION,
|
||||||
|
MAXELEVATION,
|
||||||
|
ELEVATIONGAIN
|
||||||
|
};
|
||||||
|
|
||||||
|
private final long id;
|
||||||
|
private final String trackname;
|
||||||
|
private final String description;
|
||||||
|
private final String category;
|
||||||
|
private final int startTimeEpochMillis;
|
||||||
|
private final int stopTimeEpochMillis;
|
||||||
|
private final float totalDistanceMeter;
|
||||||
|
private final int totalTimeMillis;
|
||||||
|
private final int movingTimeMillis;
|
||||||
|
private final float avgSpeedMeterPerSecond;
|
||||||
|
private final float avgMovingSpeedMeterPerSecond;
|
||||||
|
private final float maxSpeedMeterPerSecond;
|
||||||
|
private final float minElevationMeter;
|
||||||
|
private final float maxElevationMeter;
|
||||||
|
private final float elevationGainMeter;
|
||||||
|
|
||||||
|
public Track(final long id, final String trackname, final String description, final String category, final int startTimeEpochMillis, final int stopTimeEpochMillis, final float totalDistanceMeter, final int totalTimeMillis, final int movingTimeMillis, final float avgSpeedMeterPerSecond, final float avgMovingSpeedMeterPerSecond, final float maxSpeedMeterPerSecond, final float minElevationMeter, final float maxElevationMeter, final float elevationGainMeter) {
|
||||||
|
this.id = id;
|
||||||
|
this.trackname = trackname;
|
||||||
|
this.description = description;
|
||||||
|
this.category = category;
|
||||||
|
this.startTimeEpochMillis = startTimeEpochMillis;
|
||||||
|
this.stopTimeEpochMillis = stopTimeEpochMillis;
|
||||||
|
this.totalDistanceMeter = totalDistanceMeter;
|
||||||
|
this.totalTimeMillis = totalTimeMillis;
|
||||||
|
this.movingTimeMillis = movingTimeMillis;
|
||||||
|
this.avgSpeedMeterPerSecond = avgSpeedMeterPerSecond;
|
||||||
|
this.avgMovingSpeedMeterPerSecond = avgMovingSpeedMeterPerSecond;
|
||||||
|
this.maxSpeedMeterPerSecond = maxSpeedMeterPerSecond;
|
||||||
|
this.minElevationMeter = minElevationMeter;
|
||||||
|
this.maxElevationMeter = maxElevationMeter;
|
||||||
|
this.elevationGainMeter = elevationGainMeter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the Tracks from the Content Uri
|
||||||
|
*/
|
||||||
|
public static List<Track> readTracks(final ContentResolver resolver, final Uri data, final int protocolVersion) {
|
||||||
|
LOG.info("Loading track(s) from " + data);
|
||||||
|
|
||||||
|
final ArrayList<Track> tracks = new ArrayList<Track>();
|
||||||
|
try (final Cursor cursor = resolver.query(data, Track.PROJECTION, null, null, null)) {
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
final long id = cursor.getLong(cursor.getColumnIndexOrThrow(Track._ID));
|
||||||
|
final String trackname = cursor.getString(cursor.getColumnIndexOrThrow(Track.NAME));
|
||||||
|
final String description = cursor.getString(cursor.getColumnIndexOrThrow(Track.DESCRIPTION));
|
||||||
|
final String category = cursor.getString(cursor.getColumnIndexOrThrow(Track.CATEGORY));
|
||||||
|
final int startTimeEpochMillis = cursor.getInt(cursor.getColumnIndexOrThrow(Track.STARTTIME));
|
||||||
|
final int stopTimeEpochMillis = cursor.getInt(cursor.getColumnIndexOrThrow(Track.STOPTIME));
|
||||||
|
final float totalDistanceMeter = cursor.getFloat(cursor.getColumnIndexOrThrow(Track.TOTALDISTANCE));
|
||||||
|
final int totalTimeMillis = cursor.getInt(cursor.getColumnIndexOrThrow(Track.TOTALTIME));
|
||||||
|
final int movingTimeMillis = cursor.getInt(cursor.getColumnIndexOrThrow(Track.MOVINGTIME));
|
||||||
|
final float avgSpeedMeterPerSecond = cursor.getFloat(cursor.getColumnIndexOrThrow(Track.AVGSPEED));
|
||||||
|
final float avgMovingSpeedMeterPerSecond = cursor.getFloat(cursor.getColumnIndexOrThrow(Track.AVGMOVINGSPEED));
|
||||||
|
final float maxSpeedMeterPerSecond = cursor.getFloat(cursor.getColumnIndexOrThrow(Track.MAXSPEED));
|
||||||
|
final float minElevationMeter = cursor.getFloat(cursor.getColumnIndexOrThrow(Track.MINELEVATION));
|
||||||
|
final float maxElevationMeter = cursor.getFloat(cursor.getColumnIndexOrThrow(Track.MAXELEVATION));
|
||||||
|
final float elevationGainMeter = cursor.getFloat(cursor.getColumnIndexOrThrow(Track.ELEVATIONGAIN));
|
||||||
|
|
||||||
|
LOG.info("New Track data received: distance=" + totalDistanceMeter + " time=" + totalTimeMillis);
|
||||||
|
|
||||||
|
tracks.add(new Track(id, trackname, description, category, startTimeEpochMillis, stopTimeEpochMillis,
|
||||||
|
totalDistanceMeter, totalTimeMillis, movingTimeMillis, avgSpeedMeterPerSecond, avgMovingSpeedMeterPerSecond, maxSpeedMeterPerSecond,
|
||||||
|
minElevationMeter, maxElevationMeter, elevationGainMeter));
|
||||||
|
}
|
||||||
|
} catch (final SecurityException e) {
|
||||||
|
LOG.warn("No permission to read track", e);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
LOG.warn("Reading track failed", e);
|
||||||
|
}
|
||||||
|
return tracks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getElevationGainMeter() {
|
||||||
|
return elevationGainMeter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getMaxElevationMeter() {
|
||||||
|
return maxElevationMeter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getMinElevationMeter() {
|
||||||
|
return minElevationMeter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getMaxSpeedMeterPerSecond() {
|
||||||
|
return maxSpeedMeterPerSecond;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getAvgMovingSpeedMeterPerSecond() {
|
||||||
|
return avgMovingSpeedMeterPerSecond;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getAvgSpeedMeterPerSecond() {
|
||||||
|
return avgSpeedMeterPerSecond;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMovingTimeMillis() {
|
||||||
|
return movingTimeMillis;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTotalTimeMillis() {
|
||||||
|
return totalTimeMillis;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getTotalDistanceMeter() {
|
||||||
|
return totalDistanceMeter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStopTimeEpochMillis() {
|
||||||
|
return stopTimeEpochMillis;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStartTimeEpochMillis() {
|
||||||
|
return startTimeEpochMillis;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCategory() {
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTrackname() {
|
||||||
|
return trackname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TrackStatistics {
|
||||||
|
/**
|
||||||
|
* This class was copied and modified from
|
||||||
|
* https://github.com/OpenTracksApp/OSMDashboard/blob/main/src/main/java/de/storchp/opentracks/osmplugin/utils/TrackStatistics.java
|
||||||
|
*/
|
||||||
|
|
||||||
|
private String category = "unknown";
|
||||||
|
private int startTimeEpochMillis;
|
||||||
|
private int stopTimeEpochMillis;
|
||||||
|
private float totalDistanceMeter;
|
||||||
|
private int totalTimeMillis;
|
||||||
|
private int movingTimeMillis;
|
||||||
|
private float avgSpeedMeterPerSecond;
|
||||||
|
private float avgMovingSpeedMeterPerSecond;
|
||||||
|
private float maxSpeedMeterPerSecond;
|
||||||
|
private float minElevationMeter;
|
||||||
|
private float maxElevationMeter;
|
||||||
|
private float elevationGainMeter;
|
||||||
|
|
||||||
|
public TrackStatistics(final List<Track> tracks) {
|
||||||
|
if (tracks.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Track first = tracks.get(0);
|
||||||
|
category = first.getCategory();
|
||||||
|
startTimeEpochMillis = first.getStartTimeEpochMillis();
|
||||||
|
stopTimeEpochMillis = first.getStopTimeEpochMillis();
|
||||||
|
totalDistanceMeter = first.getTotalDistanceMeter();
|
||||||
|
totalTimeMillis = first.getTotalTimeMillis();
|
||||||
|
movingTimeMillis = first.getMovingTimeMillis();
|
||||||
|
avgSpeedMeterPerSecond = first.getAvgSpeedMeterPerSecond();
|
||||||
|
avgMovingSpeedMeterPerSecond = first.getAvgMovingSpeedMeterPerSecond();
|
||||||
|
maxSpeedMeterPerSecond = first.getMaxSpeedMeterPerSecond();
|
||||||
|
minElevationMeter = first.getMinElevationMeter();
|
||||||
|
maxElevationMeter = first.getMaxElevationMeter();
|
||||||
|
elevationGainMeter = first.getElevationGainMeter();
|
||||||
|
|
||||||
|
if (tracks.size() > 1) {
|
||||||
|
float totalAvgSpeedMeterPerSecond = avgSpeedMeterPerSecond;
|
||||||
|
float totalAvgMovingSpeedMeterPerSecond = avgMovingSpeedMeterPerSecond;
|
||||||
|
for (final Track track : tracks.subList(1, tracks.size())) {
|
||||||
|
if (!category.equals(track.getCategory())) {
|
||||||
|
category = "mixed";
|
||||||
|
}
|
||||||
|
startTimeEpochMillis = Math.min(startTimeEpochMillis, track.getStartTimeEpochMillis());
|
||||||
|
stopTimeEpochMillis = Math.max(stopTimeEpochMillis, track.getStopTimeEpochMillis());
|
||||||
|
totalDistanceMeter += track.getTotalDistanceMeter();
|
||||||
|
totalTimeMillis += track.getTotalTimeMillis();
|
||||||
|
movingTimeMillis += track.getMovingTimeMillis();
|
||||||
|
totalAvgSpeedMeterPerSecond += track.getAvgSpeedMeterPerSecond();
|
||||||
|
totalAvgMovingSpeedMeterPerSecond += track.getAvgMovingSpeedMeterPerSecond();
|
||||||
|
maxSpeedMeterPerSecond = Math.max(maxSpeedMeterPerSecond, track.getMaxSpeedMeterPerSecond());
|
||||||
|
minElevationMeter = Math.min(minElevationMeter, track.getMinElevationMeter());
|
||||||
|
maxElevationMeter = Math.max(maxElevationMeter, track.getMaxElevationMeter());
|
||||||
|
elevationGainMeter += track.getElevationGainMeter();
|
||||||
|
}
|
||||||
|
|
||||||
|
avgSpeedMeterPerSecond = totalAvgSpeedMeterPerSecond / tracks.size();
|
||||||
|
avgMovingSpeedMeterPerSecond = totalAvgMovingSpeedMeterPerSecond / tracks.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCategory() {
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStartTimeEpochMillis() {
|
||||||
|
return startTimeEpochMillis;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStopTimeEpochMillis() {
|
||||||
|
return stopTimeEpochMillis;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getTotalDistanceMeter() {
|
||||||
|
return totalDistanceMeter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTotalTimeMillis() {
|
||||||
|
return totalTimeMillis;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMovingTimeMillis() {
|
||||||
|
return movingTimeMillis;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getAvgSpeedMeterPerSecond() {
|
||||||
|
return avgSpeedMeterPerSecond;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getAvgMovingSpeedMeterPerSecond() {
|
||||||
|
return avgMovingSpeedMeterPerSecond;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getMaxSpeedMeterPerSecond() {
|
||||||
|
return maxSpeedMeterPerSecond;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getMinElevationMeter() {
|
||||||
|
return minElevationMeter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getMaxElevationMeter() {
|
||||||
|
return maxElevationMeter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getElevationGainMeter() {
|
||||||
|
return elevationGainMeter;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
/* Copyright (C) 2022 Arjan Schrijver
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.externalevents;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||||
|
|
||||||
|
public class OpenTracksController extends Activity {
|
||||||
|
/*
|
||||||
|
* A short explanation of how this integration with OpenTracks works:
|
||||||
|
* Starting the recording from a device requires calling `startRecording()`
|
||||||
|
* on this class. For a simple example, check out the implementation in
|
||||||
|
* `WorkoutRequestHandler`, used by the Fossil HR series.
|
||||||
|
* The OpenTracks class can be set in the Gadgetbridge settings and depends
|
||||||
|
* on the installation source used for OpenTracks. Details can be found in
|
||||||
|
* their documentation here: https://github.com/OpenTracksApp/OpenTracks#api
|
||||||
|
* `startRecording()` sends an explicit Intent to OpenTracks signalling it
|
||||||
|
* to start recording. It passes along the package name and class name of
|
||||||
|
* our `OpenTracksController` which OpenTracks will use to send the
|
||||||
|
* statistics URIs to. After starting the recording service, OpenTracks
|
||||||
|
* uses a new explicit Intent to start our `OpenTracksController` and passes
|
||||||
|
* along the URIs and the read permissions for those URIs (using
|
||||||
|
* `Intent.FLAG_GRANT_READ_URI_PERMISSION`). So at that point
|
||||||
|
* `OpenTracksController` is started as a new `Activity` (or `Context`)
|
||||||
|
* which has the read permissions for the statistics URIs. The controller
|
||||||
|
* saves its `Context` into the `OpenTracksContentObserver` in the GB main
|
||||||
|
* process, so it can keep running and read the statistics with the correct
|
||||||
|
* `Context`. So, whatever class, device or activity calls the methods on
|
||||||
|
* the `OpenTracksContentObserver` from, it will always work.
|
||||||
|
*/
|
||||||
|
private static final String EXTRAS_PROTOCOL_VERSION = "PROTOCOL_VERSION";
|
||||||
|
private static final String ACTION_DASHBOARD = "Intent.OpenTracks-Dashboard";
|
||||||
|
private static final String ACTION_DASHBOARD_PAYLOAD = ACTION_DASHBOARD + ".Payload";
|
||||||
|
|
||||||
|
private final Logger LOG = LoggerFactory.getLogger(OpenTracksController.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle bundle) {
|
||||||
|
super.onCreate(bundle);
|
||||||
|
GBApplication gbApp = GBApplication.app();
|
||||||
|
Intent intent = getIntent();
|
||||||
|
int protocolVersion = intent.getIntExtra(EXTRAS_PROTOCOL_VERSION, 1);
|
||||||
|
final ArrayList<Uri> uris = intent.getParcelableArrayListExtra(ACTION_DASHBOARD_PAYLOAD);
|
||||||
|
if (uris != null) {
|
||||||
|
if (gbApp.getOpenTracksObserver() != null) {
|
||||||
|
LOG.info("Unregistering old OpenTracksContentObserver");
|
||||||
|
gbApp.getOpenTracksObserver().unregister();
|
||||||
|
}
|
||||||
|
Uri tracksUri = uris.get(0);
|
||||||
|
LOG.info("Registering OpenTracksContentObserver with tracks URI: " + tracksUri);
|
||||||
|
gbApp.setOpenTracksObserver(new OpenTracksContentObserver(this, tracksUri, protocolVersion));
|
||||||
|
try {
|
||||||
|
getContentResolver().registerContentObserver(tracksUri, false, gbApp.getOpenTracksObserver());
|
||||||
|
} catch (final SecurityException se) {
|
||||||
|
LOG.error("Error registering OpenTracksContentObserver", se);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
moveTaskToBack(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sendIntent(Context context, String className) {
|
||||||
|
Prefs prefs = GBApplication.getPrefs();
|
||||||
|
String packageName = prefs.getString("opentracks_packagename", "de.dennisguse.opentracks");
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
intent.setClassName(packageName, className);
|
||||||
|
intent.putExtra("STATS_TARGET_PACKAGE", context.getPackageName());
|
||||||
|
intent.putExtra("STATS_TARGET_CLASS", "nodomain.freeyourgadget.gadgetbridge.externalevents.OpenTracksController");
|
||||||
|
try {
|
||||||
|
context.startActivity(intent);
|
||||||
|
} catch (Exception e) {
|
||||||
|
GB.toast(e.getMessage(), Toast.LENGTH_LONG, GB.WARN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void startRecording(Context context) {
|
||||||
|
sendIntent(context, "de.dennisguse.opentracks.publicapi.StartRecording");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void stopRecording(Context context) {
|
||||||
|
sendIntent(context, "de.dennisguse.opentracks.publicapi.StopRecording");
|
||||||
|
OpenTracksContentObserver openTracksObserver = GBApplication.app().getOpenTracksObserver();
|
||||||
|
if (openTracksObserver != null) {
|
||||||
|
openTracksObserver.finish();
|
||||||
|
}
|
||||||
|
GBApplication.app().setOpenTracksObserver(null);
|
||||||
|
}
|
||||||
|
}
|
@ -201,6 +201,9 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
batteryInfo.level = b;
|
batteryInfo.level = b;
|
||||||
batteryInfo.state = BatteryState.BATTERY_NORMAL;
|
batteryInfo.state = BatteryState.BATTERY_NORMAL;
|
||||||
}
|
}
|
||||||
|
if (json.has("chg") && json.getInt("chg") == 1) {
|
||||||
|
batteryInfo.state = BatteryState.BATTERY_CHARGING;
|
||||||
|
}
|
||||||
if (json.has("volt"))
|
if (json.has("volt"))
|
||||||
batteryInfo.voltage = (float) json.getDouble("volt");
|
batteryInfo.voltage = (float) json.getDouble("volt");
|
||||||
handleGBDeviceEvent(batteryInfo);
|
handleGBDeviceEvent(batteryInfo);
|
||||||
@ -407,9 +410,10 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
jsonalarms.put(jsonalarm);
|
jsonalarms.put(jsonalarm);
|
||||||
|
|
||||||
Calendar calendar = AlarmUtils.toCalendar(alarm);
|
Calendar calendar = AlarmUtils.toCalendar(alarm);
|
||||||
// TODO: getRepetition to ensure it only happens on correct day?
|
|
||||||
jsonalarm.put("h", alarm.getHour());
|
jsonalarm.put("h", alarm.getHour());
|
||||||
jsonalarm.put("m", alarm.getMinute());
|
jsonalarm.put("m", alarm.getMinute());
|
||||||
|
jsonalarm.put("rep", alarm.getRepetition());
|
||||||
}
|
}
|
||||||
uartTxJSON("onSetAlarms", o);
|
uartTxJSON("onSetAlarms", o);
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
|
@ -93,6 +93,7 @@ import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.MiBandActivitySample;
|
import nodomain.freeyourgadget.gadgetbridge.entities.MiBandActivitySample;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.User;
|
import nodomain.freeyourgadget.gadgetbridge.entities.User;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.externalevents.OpenTracksController;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice.State;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice.State;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
|
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
|
||||||
@ -157,6 +158,8 @@ import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.Dev
|
|||||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_TIMEFORMAT;
|
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_TIMEFORMAT;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_WEARLOCATION;
|
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_WEARLOCATION;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_BUTTON_ACTION_SELECTION_BROADCAST;
|
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_BUTTON_ACTION_SELECTION_BROADCAST;
|
||||||
|
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_BUTTON_ACTION_SELECTION_FITNESS_APP_START;
|
||||||
|
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_BUTTON_ACTION_SELECTION_FITNESS_APP_STOP;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_BUTTON_ACTION_SELECTION_OFF;
|
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_BUTTON_ACTION_SELECTION_OFF;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_DEVICE_ACTION_FELL_SLEEP_BROADCAST;
|
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_DEVICE_ACTION_FELL_SLEEP_BROADCAST;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_DEVICE_ACTION_FELL_SLEEP_SELECTION;
|
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_DEVICE_ACTION_FELL_SLEEP_SELECTION;
|
||||||
@ -1408,9 +1411,17 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
|||||||
if (prefs.getBoolean(HuamiConst.PREF_BUTTON_ACTION_VIBRATE, false)) {
|
if (prefs.getBoolean(HuamiConst.PREF_BUTTON_ACTION_VIBRATE, false)) {
|
||||||
vibrateOnce();
|
vibrateOnce();
|
||||||
}
|
}
|
||||||
if (buttonPreference.equals(PREF_BUTTON_ACTION_SELECTION_BROADCAST)) {
|
switch (buttonPreference) {
|
||||||
|
case PREF_BUTTON_ACTION_SELECTION_BROADCAST:
|
||||||
sendSystemBroadcastWithButtonId();
|
sendSystemBroadcastWithButtonId();
|
||||||
} else {
|
break;
|
||||||
|
case PREF_BUTTON_ACTION_SELECTION_FITNESS_APP_START:
|
||||||
|
OpenTracksController.startRecording(this.getContext());
|
||||||
|
break;
|
||||||
|
case PREF_BUTTON_ACTION_SELECTION_FITNESS_APP_STOP:
|
||||||
|
OpenTracksController.stopRecording(this.getContext());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
handleMediaButton(buttonPreference);
|
handleMediaButton(buttonPreference);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1419,9 +1430,17 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
|||||||
if (deviceAction.equals(PREF_DEVICE_ACTION_SELECTION_OFF)) {
|
if (deviceAction.equals(PREF_DEVICE_ACTION_SELECTION_OFF)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (deviceAction.equals(PREF_DEVICE_ACTION_SELECTION_BROADCAST)) {
|
switch (deviceAction) {
|
||||||
|
case PREF_BUTTON_ACTION_SELECTION_BROADCAST:
|
||||||
sendSystemBroadcast(message);
|
sendSystemBroadcast(message);
|
||||||
}else {
|
break;
|
||||||
|
case PREF_BUTTON_ACTION_SELECTION_FITNESS_APP_START:
|
||||||
|
OpenTracksController.startRecording(this.getContext());
|
||||||
|
break;
|
||||||
|
case PREF_BUTTON_ACTION_SELECTION_FITNESS_APP_STOP:
|
||||||
|
OpenTracksController.stopRecording(this.getContext());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
handleMediaButton(deviceAction);
|
handleMediaButton(deviceAction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,6 +144,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fos
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomWidgetElement;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomWidgetElement;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.Widget;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.Widget;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.WidgetsPutRequest;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.WidgetsPutRequest;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.workout.WorkoutRequestHandler;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.FactoryResetRequest;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.FactoryResetRequest;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||||
@ -1558,13 +1559,25 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
queueWrite(new SetCommuteMenuMessage(getContext().getString(R.string.fossil_hr_commute_processing), false, this));
|
|
||||||
|
|
||||||
Intent menuIntent = new Intent(QHybridSupport.QHYBRID_EVENT_COMMUTE_MENU);
|
Intent menuIntent = new Intent(QHybridSupport.QHYBRID_EVENT_COMMUTE_MENU);
|
||||||
menuIntent.putExtra("EXTRA_ACTION", action);
|
menuIntent.putExtra("EXTRA_ACTION", action);
|
||||||
getContext().sendBroadcast(menuIntent);
|
getContext().sendBroadcast(menuIntent);
|
||||||
} else if (request.has("master._.config.app_status")) {
|
} else if (request.has("master._.config.app_status")) {
|
||||||
queueWrite(new ConfirmAppStatusRequest(requestId, this));
|
queueWrite(new ConfirmAppStatusRequest(requestId, this));
|
||||||
|
} else if (request.has("workoutApp")) {
|
||||||
|
JSONObject workoutRequest = request.getJSONObject("workoutApp");
|
||||||
|
String workoutState = workoutRequest.optString("state");
|
||||||
|
String workoutType = workoutRequest.optString("type");
|
||||||
|
LOG.info("Got workoutApp request, state=" + workoutState + ", type=" + workoutType);
|
||||||
|
JSONObject workoutResponse = WorkoutRequestHandler.handleRequest(getContext(), requestId, workoutRequest);
|
||||||
|
if (workoutResponse.length() > 0) {
|
||||||
|
JSONObject responseObject = new JSONObject()
|
||||||
|
.put("res", new JSONObject()
|
||||||
|
.put("id", requestId)
|
||||||
|
.put("set", workoutResponse)
|
||||||
|
);
|
||||||
|
queueWrite(new JsonPutRequest(responseObject, this));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG.warn("Unhandled request from watch: " + requestJson.toString());
|
LOG.warn("Unhandled request from watch: " + requestJson.toString());
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,80 @@
|
|||||||
|
/* Copyright (C) 2022 Arjan Schrijver
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.workout;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.externalevents.OpenTracksController;
|
||||||
|
|
||||||
|
public class WorkoutRequestHandler {
|
||||||
|
public static void addStateResponse(JSONObject workoutResponse, String type, String msg) throws JSONException {
|
||||||
|
workoutResponse.put("workoutApp._.config.response", new JSONObject()
|
||||||
|
.put("message", msg)
|
||||||
|
.put("type", type)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JSONObject handleRequest(Context context, int requestId, JSONObject workoutRequest) throws JSONException {
|
||||||
|
final Logger LOG = LoggerFactory.getLogger(WorkoutRequestHandler.class);
|
||||||
|
|
||||||
|
JSONObject workoutResponse = new JSONObject();
|
||||||
|
if (workoutRequest.optString("state").equals("started") && workoutRequest.optString("gps").equals("on")) {
|
||||||
|
int activityType = workoutRequest.optInt("activity", -1);
|
||||||
|
LOG.info("Workout started, activity type is " + activityType);
|
||||||
|
addStateResponse(workoutResponse, "success", "");
|
||||||
|
OpenTracksController.startRecording(context);
|
||||||
|
} else if (workoutRequest.optString("type").equals("req_distance")) {
|
||||||
|
long timeSecs = GBApplication.app().getOpenTracksObserver().getTimeMillisChange() / 1000;
|
||||||
|
float distanceCM = GBApplication.app().getOpenTracksObserver().getDistanceMeterChange() * 100;
|
||||||
|
LOG.info("Workout distance requested, returning " + distanceCM + " cm, " + timeSecs + " sec");
|
||||||
|
workoutResponse.put("workoutApp._.config.gps", new JSONObject()
|
||||||
|
.put("distance", distanceCM)
|
||||||
|
.put("duration", timeSecs)
|
||||||
|
);
|
||||||
|
} else if (workoutRequest.optString("state").equals("paused")) {
|
||||||
|
LOG.info("Workout paused");
|
||||||
|
addStateResponse(workoutResponse, "success", "");
|
||||||
|
// Pause OpenTracks recording?
|
||||||
|
} else if (workoutRequest.optString("state").equals("resumed")) {
|
||||||
|
LOG.info("Workout resumed");
|
||||||
|
addStateResponse(workoutResponse, "success", "");
|
||||||
|
// Resume OpenTracks recording?
|
||||||
|
} else if (workoutRequest.optString("state").equals("end")) {
|
||||||
|
LOG.info("Workout stopped");
|
||||||
|
addStateResponse(workoutResponse, "success", "");
|
||||||
|
OpenTracksController.stopRecording(context);
|
||||||
|
} else if (workoutRequest.optString("type").equals("req_route")) {
|
||||||
|
LOG.info("Workout route image requested, returning error");
|
||||||
|
addStateResponse(workoutResponse, "error", "");
|
||||||
|
// Send the traveled route as an RLE encoded image (example name: 58270405)
|
||||||
|
// Send back a JSON packet, example:
|
||||||
|
// {"res":{"id":21,"set":{"workoutApp._.config.images":{"session_id":1213693133,"route":{"name":"58270405"},"layout_type":"vertical"}}}}
|
||||||
|
// or
|
||||||
|
// {"res":{"id":34,"set":{"workoutApp._.config.images":{"session_id":504875,"route":{"name":"211631088"},"layout_type":"horizontal"}}}}
|
||||||
|
} else {
|
||||||
|
LOG.info("Request not recognized: " + workoutRequest);
|
||||||
|
}
|
||||||
|
return workoutResponse;
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,10 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.um25.Support;
|
|||||||
|
|
||||||
import android.bluetooth.BluetoothGatt;
|
import android.bluetooth.BluetoothGatt;
|
||||||
import android.bluetooth.BluetoothGattCharacteristic;
|
import android.bluetooth.BluetoothGattCharacteristic;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||||
|
|
||||||
@ -29,10 +32,12 @@ public class UM25Support extends UM25BaseSupport {
|
|||||||
public static final String UUID_CHAR = "0000ffe1-0000-1000-8000-00805f9b34fb";
|
public static final String UUID_CHAR = "0000ffe1-0000-1000-8000-00805f9b34fb";
|
||||||
|
|
||||||
public static final String ACTION_MEASUREMENT_TAKEN = "com.nodomain.gadgetbridge.um25.MEASUREMENT_TAKEN";
|
public static final String ACTION_MEASUREMENT_TAKEN = "com.nodomain.gadgetbridge.um25.MEASUREMENT_TAKEN";
|
||||||
|
public static final String ACTION_RESET_STATS = "com.nodomain.gadgetbridge.um25.RESET_STATS";
|
||||||
public static final String EXTRA_KEY_MEASUREMENT_DATA = "EXTRA_MEASUREMENT_DATA";
|
public static final String EXTRA_KEY_MEASUREMENT_DATA = "EXTRA_MEASUREMENT_DATA";
|
||||||
public static final int LOOP_DELAY = 500;
|
public static final int LOOP_DELAY = 500;
|
||||||
|
|
||||||
private final byte[] COMMAND_UPDATE = new byte[]{(byte) 0xF0};
|
private final byte[] COMMAND_UPDATE = new byte[]{(byte) 0xF0};
|
||||||
|
private final byte[] COMMAND_RESET_STATS = new byte[]{(byte) 0xF4};
|
||||||
private final int PAYLOAD_LENGTH = 130;
|
private final int PAYLOAD_LENGTH = 130;
|
||||||
|
|
||||||
private ByteBuffer buffer = ByteBuffer.allocate(PAYLOAD_LENGTH);
|
private ByteBuffer buffer = ByteBuffer.allocate(PAYLOAD_LENGTH);
|
||||||
@ -46,6 +51,18 @@ public class UM25Support extends UM25BaseSupport {
|
|||||||
this.buffer.mark();
|
this.buffer.mark();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BroadcastReceiver resetReceiver = new BroadcastReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
if(!ACTION_RESET_STATS.equals(intent.getAction())){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
new TransactionBuilder("reset stats")
|
||||||
|
.write(getCharacteristic(UUID.fromString(UUID_CHAR)), COMMAND_RESET_STATS)
|
||||||
|
.queue(getQueue());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
|
protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
|
||||||
return builder
|
return builder
|
||||||
@ -60,6 +77,11 @@ public class UM25Support extends UM25BaseSupport {
|
|||||||
@Override
|
@Override
|
||||||
public boolean run(BluetoothGatt gatt) {
|
public boolean run(BluetoothGatt gatt) {
|
||||||
logger.debug("initialized, starting timers");
|
logger.debug("initialized, starting timers");
|
||||||
|
LocalBroadcastManager.getInstance(getContext())
|
||||||
|
.registerReceiver(
|
||||||
|
resetReceiver,
|
||||||
|
new IntentFilter(ACTION_RESET_STATS)
|
||||||
|
);
|
||||||
startLoop();
|
startLoop();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -67,6 +89,13 @@ public class UM25Support extends UM25BaseSupport {
|
|||||||
.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZED, getContext()));
|
.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZED, getContext()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
LocalBroadcastManager.getInstance(getContext())
|
||||||
|
.unregisterReceiver(resetReceiver);
|
||||||
|
}
|
||||||
|
|
||||||
private void startLoop(){
|
private void startLoop(){
|
||||||
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
|
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
|
||||||
executor.scheduleWithFixedDelay(new Runnable() {
|
executor.scheduleWithFixedDelay(new Runnable() {
|
||||||
|
@ -194,7 +194,15 @@ public class XWatchSupport extends AbstractBTLEDeviceSupport {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNotification(NotificationSpec notificationSpec) {
|
public void onNotification(NotificationSpec notificationSpec) {
|
||||||
//TODO: Implement
|
try {
|
||||||
|
TransactionBuilder builder = performInitialized("xwatch notification");
|
||||||
|
BluetoothGattCharacteristic deviceData = getCharacteristic(XWatchService.UUID_WRITE);
|
||||||
|
byte[] data = new byte[]{XWatchService.COMMAND_NOTIFICATION, XWatchService.COMMAND_NOTIFICATION_MESSAGE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
builder.write(deviceData, crcChecksum(data));
|
||||||
|
builder.queue(getQueue());
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOG.error("Unable to send message notification on XWatch device", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -215,7 +223,18 @@ public class XWatchSupport extends AbstractBTLEDeviceSupport {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSetCallState(CallSpec callSpec) {
|
public void onSetCallState(CallSpec callSpec) {
|
||||||
//TODO: Implement (if necessary)
|
if (callSpec.command == CallSpec.CALL_INCOMING) {
|
||||||
|
LOG.debug("Incoming call8");
|
||||||
|
try {
|
||||||
|
TransactionBuilder builder = performInitialized("callnotification");
|
||||||
|
BluetoothGattCharacteristic deviceData = getCharacteristic(XWatchService.UUID_WRITE);
|
||||||
|
byte[] data = new byte[]{XWatchService.COMMAND_NOTIFICATION, XWatchService.COMMAND_NOTIFICATION_PHONE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
builder.write(deviceData, crcChecksum(data));
|
||||||
|
builder.queue(getQueue());
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOG.error("Unable to send call notification on XWatch device", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -260,7 +279,7 @@ public class XWatchSupport extends AbstractBTLEDeviceSupport {
|
|||||||
@Override
|
@Override
|
||||||
public void onFetchRecordedData(int dataTypes) {
|
public void onFetchRecordedData(int dataTypes) {
|
||||||
try {
|
try {
|
||||||
if(builder == null) {
|
if (builder == null) {
|
||||||
builder = performInitialized("fetchActivityData");
|
builder = performInitialized("fetchActivityData");
|
||||||
}
|
}
|
||||||
requestSummarizedData(builder);
|
requestSummarizedData(builder);
|
||||||
@ -456,7 +475,7 @@ public class XWatchSupport extends AbstractBTLEDeviceSupport {
|
|||||||
|
|
||||||
if (value[5] == 95) {
|
if (value[5] == 95) {
|
||||||
dayToFetch++;
|
dayToFetch++;
|
||||||
if(dayToFetch <= maxDayToFetch) {
|
if (dayToFetch <= maxDayToFetch) {
|
||||||
try {
|
try {
|
||||||
builder = performInitialized("fetchActivityData");
|
builder = performInitialized("fetchActivityData");
|
||||||
requestDetailedData(builder);
|
requestDetailedData(builder);
|
||||||
@ -475,8 +494,8 @@ public class XWatchSupport extends AbstractBTLEDeviceSupport {
|
|||||||
private void handleButtonPressed(byte[] value) {
|
private void handleButtonPressed(byte[] value) {
|
||||||
long currentTimestamp = System.currentTimeMillis();
|
long currentTimestamp = System.currentTimeMillis();
|
||||||
|
|
||||||
AudioManager audioManager = (AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE);
|
AudioManager audioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
|
||||||
if(audioManager.isWiredHeadsetOn()) {
|
if (audioManager.isWiredHeadsetOn()) {
|
||||||
if (currentTimestamp - lastButtonTimestamp < 1000) {
|
if (currentTimestamp - lastButtonTimestamp < 1000) {
|
||||||
if (audioManager.isMusicActive()) {
|
if (audioManager.isMusicActive()) {
|
||||||
audioManager.dispatchMediaKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT));
|
audioManager.dispatchMediaKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT));
|
||||||
@ -570,7 +589,7 @@ public class XWatchSupport extends AbstractBTLEDeviceSupport {
|
|||||||
minutes
|
minutes
|
||||||
);
|
);
|
||||||
|
|
||||||
timestamp = (int)(cal.getTimeInMillis() / 1000);
|
timestamp = (int) (cal.getTimeInMillis() / 1000);
|
||||||
|
|
||||||
return timestamp;
|
return timestamp;
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@
|
|||||||
android:text="@string/activity_db_management_clean_export_directory_label" />
|
android:text="@string/activity_db_management_clean_export_directory_label" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/autoExportLocation_label"
|
android:id="@+id/autoExportTitleLabel"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="20dp"
|
android:layout_marginTop="20dp"
|
||||||
@ -109,7 +109,29 @@
|
|||||||
android:textColor="@color/accent" />
|
android:textColor="@color/accent" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/autoExportLocation_intro"
|
android:id="@+id/autoExportEnabled"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text=""
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/autoExportScheduled"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/activity_db_management_autoexport_scheduled_no"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/autoExport_lastTime_label"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/autoExport_lastTime_label"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/autoExportLocation_label"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/activity_db_management_autoexport_explanation"
|
android:text="@string/activity_db_management_autoexport_explanation"
|
||||||
|
@ -233,6 +233,29 @@
|
|||||||
grid:layout_columnSpan="2"
|
grid:layout_columnSpan="2"
|
||||||
grid:layout_gravity="fill_horizontal" />
|
grid:layout_gravity="fill_horizontal" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/startFitnessAppTracking"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/pref_device_action_fitness_app_control_start"
|
||||||
|
grid:layout_columnSpan="2"
|
||||||
|
grid:layout_gravity="fill_horizontal" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/stopFitnessAppTracking"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/pref_device_action_fitness_app_control_stop"
|
||||||
|
grid:layout_columnSpan="2"
|
||||||
|
grid:layout_gravity="fill_horizontal" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/showStatusFitnessAppTracking"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Show Fit.App.Track. Status"
|
||||||
|
grid:layout_columnSpan="2"
|
||||||
|
grid:layout_gravity="fill_horizontal" />
|
||||||
</androidx.gridlayout.widget.GridLayout>
|
</androidx.gridlayout.widget.GridLayout>
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
@ -1566,4 +1566,33 @@
|
|||||||
<string name="devicetype_sonyswr12">Sony SWR12</string>
|
<string name="devicetype_sonyswr12">Sony SWR12</string>
|
||||||
<string name="audio_codec">Zvukový kodek</string>
|
<string name="audio_codec">Zvukový kodek</string>
|
||||||
<string name="pref_header_sony_device_info">Informace o zařízení</string>
|
<string name="pref_header_sony_device_info">Informace o zařízení</string>
|
||||||
|
<string name="unknown">Neznámé</string>
|
||||||
|
<string name="start">Start</string>
|
||||||
|
<string name="devicetype_amazfit_pop">Amazfit Pop</string>
|
||||||
|
<string name="devicetype_amazfit_pop_pro">Amazfit Pop Pro</string>
|
||||||
|
<string name="pref_header_sony_anc_optimizer">Optimalizátor potlačení hluku</string>
|
||||||
|
<string name="sony_anc_optimize_description">Kliknutím spustíte optimalizátor pro potlačení šumu.</string>
|
||||||
|
<string name="sony_anc_optimize_confirmation_description">Používejte sluchátka jako obvykle. Pokud se změní podmínky nošení nebo atmosférický tlak, spusťte optimalizátor znovu.</string>
|
||||||
|
<string name="sony_anc_optimize_title">Optimalizovat</string>
|
||||||
|
<string name="sony_anc_optimizer_status_starting">Začínáme…</string>
|
||||||
|
<string name="sony_anc_optimizer_status_not_running">Neprobíhá</string>
|
||||||
|
<string name="sony_anc_optimizer_status_atmospheric_pressure">Měření atmostférického tlaku…</string>
|
||||||
|
<string name="sony_anc_optimizer_status_analyzing">Analýza…</string>
|
||||||
|
<string name="sony_anc_optimizer_status_finished">Dokončování…</string>
|
||||||
|
<string name="sony_anc_optimize_confirmation_title">Optimalizátor potlačení šumu</string>
|
||||||
|
<string name="pref_anc_optimizer_state_pressure">Atmosférický tlak</string>
|
||||||
|
<string name="sony_anc_optimizer_status_wearing_condition">Měření stavu nošení…</string>
|
||||||
|
<string name="menuitem_nothing">Nic</string>
|
||||||
|
<string name="pref_device_action_fitness_app_control_start">Start Sledování Sportovní aplikací</string>
|
||||||
|
<string name="pref_device_action_fitness_app_control_stop">Stop Sledování Sportovní aplikací</string>
|
||||||
|
<string name="pref_title_opentracks_packagename">OpenTracks aplikační jméno</string>
|
||||||
|
<string name="pref_title_notifications_generic_settings">Systémové nastavení notifikací</string>
|
||||||
|
<string name="pref_summary_opentracks_packagename">Použito pro ovládání nahrávání GPS trasy pomocí externí fitness aplikace.</string>
|
||||||
|
<string name="autoExport_lastTime_label">Poslední AutoExport: %1$s</string>
|
||||||
|
<string name="activity_db_management_autoexport_enabled_yes">AutoExport je aktivní.</string>
|
||||||
|
<string name="activity_db_management_autoexport_scheduled_yes">AutoExport byl (prvně) naplánován na %1$s</string>
|
||||||
|
<string name="activity_db_management_autoexport_location">Umístění nebylo pochopeno. Pravděpodobně problém novějšího systému oprávnění Android. AutoExport s největší pravděpodobností nyní nefunguje.</string>
|
||||||
|
<string name="watchface_dialog_pre_setting_position">přednastavuji pozici na %s</string>
|
||||||
|
<string name="activity_db_management_autoexport_enabled_no">AutoExport není aktivní.</string>
|
||||||
|
<string name="activity_db_management_autoexport_scheduled_no">AutoExport zatím nebyl naplánován.</string>
|
||||||
</resources>
|
</resources>
|
@ -457,7 +457,7 @@
|
|||||||
\nINSTALLATION AUF EIGENE GEFAHR!</string>
|
\nINSTALLATION AUF EIGENE GEFAHR!</string>
|
||||||
<string name="mi2_prefs_button_press_count">Anzahl der Tastendrücke</string>
|
<string name="mi2_prefs_button_press_count">Anzahl der Tastendrücke</string>
|
||||||
<string name="pref_title_charts_swipe">Streichen nach links/rechts im Diagrammbetrieb aktivieren</string>
|
<string name="pref_title_charts_swipe">Streichen nach links/rechts im Diagrammbetrieb aktivieren</string>
|
||||||
<string name="pref_summary_pebble_enable_bgjs">Wenn aktiviert, kann Zifferblatt Wetter, Akkuinfos, usw. anzeigen</string>
|
<string name="pref_summary_pebble_enable_bgjs">Wenn aktiviert, kann Zifferblatt Wetter, Akkuinfos, usw. anzeigen.</string>
|
||||||
<string name="prefs_title_heartrate_measurement_interval">Ganztägige Messung der Herzfrequenz</string>
|
<string name="prefs_title_heartrate_measurement_interval">Ganztägige Messung der Herzfrequenz</string>
|
||||||
<string name="interval_one_minute">einmal pro Minute</string>
|
<string name="interval_one_minute">einmal pro Minute</string>
|
||||||
<string name="interval_five_minutes">alle 5 Minuten</string>
|
<string name="interval_five_minutes">alle 5 Minuten</string>
|
||||||
@ -1589,4 +1589,8 @@
|
|||||||
<string name="sony_anc_optimize_confirmation_description">Verwende den Kopfhörer wie gewohnt. Wenn sich die Tragebedingungen oder der Luftdruck ändern, führe den Optimierer erneut aus.</string>
|
<string name="sony_anc_optimize_confirmation_description">Verwende den Kopfhörer wie gewohnt. Wenn sich die Tragebedingungen oder der Luftdruck ändern, führe den Optimierer erneut aus.</string>
|
||||||
<string name="devicetype_amazfit_pop">Amazfit Pop</string>
|
<string name="devicetype_amazfit_pop">Amazfit Pop</string>
|
||||||
<string name="devicetype_amazfit_pop_pro">Amazfit Pop Pro</string>
|
<string name="devicetype_amazfit_pop_pro">Amazfit Pop Pro</string>
|
||||||
|
<string name="pref_title_opentracks_packagename">OpenTracks Paketname</string>
|
||||||
|
<string name="pref_summary_opentracks_packagename">Dient zum Starten/Stoppen der GPS-Track-Aufzeichnung in der externen Fitness-App.</string>
|
||||||
|
<string name="pref_title_notifications_generic_settings">Android-Benachrichtigungseinstellungen</string>
|
||||||
|
<string name="watchface_dialog_pre_setting_position">setze position auf %s</string>
|
||||||
</resources>
|
</resources>
|
@ -1173,7 +1173,7 @@
|
|||||||
\nNote: You do not have to install .res if it is exactly the same as the one previously installed.
|
\nNote: You do not have to install .res if it is exactly the same as the one previously installed.
|
||||||
\n
|
\n
|
||||||
\nPROCEED AT YOUR OWN RISK!</string>
|
\nPROCEED AT YOUR OWN RISK!</string>
|
||||||
<string name="activity_type_jump_roping">Jump Rope</string>
|
<string name="activity_type_jump_roping">Skipping rope</string>
|
||||||
<string name="sony_automatic_power_off_off">Do not turn off</string>
|
<string name="sony_automatic_power_off_off">Do not turn off</string>
|
||||||
<string name="sony_equalizer_band_400">400</string>
|
<string name="sony_equalizer_band_400">400</string>
|
||||||
<string name="button_watchface_save_apply">Save and apply</string>
|
<string name="button_watchface_save_apply">Save and apply</string>
|
||||||
@ -1578,4 +1578,16 @@
|
|||||||
<string name="sony_anc_optimize_confirmation_description">Use the headphones as you normally would. If the wearing condition or atmospheric pressure change, run the optimiser again.</string>
|
<string name="sony_anc_optimize_confirmation_description">Use the headphones as you normally would. If the wearing condition or atmospheric pressure change, run the optimiser again.</string>
|
||||||
<string name="devicetype_amazfit_pop_pro">Amazfit Pop Pro</string>
|
<string name="devicetype_amazfit_pop_pro">Amazfit Pop Pro</string>
|
||||||
<string name="devicetype_amazfit_pop">Amazfit Pop</string>
|
<string name="devicetype_amazfit_pop">Amazfit Pop</string>
|
||||||
|
<string name="menuitem_nothing">Nothing</string>
|
||||||
|
<string name="autoExport_lastTime_label">Last AutoExport: %1$s</string>
|
||||||
|
<string name="activity_db_management_autoexport_scheduled_no">AutoExport has not been not scheduled.</string>
|
||||||
|
<string name="pref_title_notifications_generic_settings">Android notification settings</string>
|
||||||
|
<string name="activity_db_management_autoexport_scheduled_yes">AutoExport has (originally) been scheduled for %1$s</string>
|
||||||
|
<string name="activity_db_management_autoexport_location">Location could not be understood. Likely an issue of newer Android permission system. Most likely, autoexport is not working now.</string>
|
||||||
|
<string name="pref_title_opentracks_packagename">OpenTracks package name</string>
|
||||||
|
<string name="pref_summary_opentracks_packagename">Used for starting/stopping GPS track recording in external fitness app.</string>
|
||||||
|
<string name="activity_db_management_autoexport_enabled_yes">AutoExport is enabled.</string>
|
||||||
|
<string name="activity_db_management_autoexport_enabled_no">AutoExport is not enabled.</string>
|
||||||
|
<string name="pref_device_action_fitness_app_control_start">Fitness App Tracking Start</string>
|
||||||
|
<string name="pref_device_action_fitness_app_control_stop">Fitness App Tracking Stop</string>
|
||||||
</resources>
|
</resources>
|
@ -1585,4 +1585,10 @@
|
|||||||
<string name="audio_codec">Códec de audio</string>
|
<string name="audio_codec">Códec de audio</string>
|
||||||
<string name="pref_header_sony_device_info">Información del dispositivo</string>
|
<string name="pref_header_sony_device_info">Información del dispositivo</string>
|
||||||
<string name="sony_anc_optimize_description">Pulse para iniciar el optimizador de cancelación de ruido.</string>
|
<string name="sony_anc_optimize_description">Pulse para iniciar el optimizador de cancelación de ruido.</string>
|
||||||
|
<string name="menuitem_nothing">Nada</string>
|
||||||
|
<string name="pref_title_notifications_generic_settings">Ajustes de notificaciones de Android</string>
|
||||||
|
<string name="pref_device_action_fitness_app_control_start">Inicio del seguimiento de la aplicación de ejercicio físico</string>
|
||||||
|
<string name="pref_device_action_fitness_app_control_stop">Parada de seguimiento de la aplicación de ejercicio físico</string>
|
||||||
|
<string name="pref_title_opentracks_packagename">Nombre del paquete OpenTracks</string>
|
||||||
|
<string name="pref_summary_opentracks_packagename">Se usa para iniciar/detener la grabación del seguimiento GPS en la aplicación externa de ejercicio físico.</string>
|
||||||
</resources>
|
</resources>
|
@ -434,4 +434,44 @@
|
|||||||
<string name="notification_channel_low_battery_name">Akku vähissä</string>
|
<string name="notification_channel_low_battery_name">Akku vähissä</string>
|
||||||
<string name="waiting_for_reconnect">Odottaa yhteyden muodostumista</string>
|
<string name="waiting_for_reconnect">Odottaa yhteyden muodostumista</string>
|
||||||
<string name="activity_prefs_about_you">Tietoja sinusta</string>
|
<string name="activity_prefs_about_you">Tietoja sinusta</string>
|
||||||
|
<string name="activity_list_summary_active_steps">Aktiiviset askeleet</string>
|
||||||
|
<string name="pref_screen_notification_profile_generic_navigation">Navigaatio</string>
|
||||||
|
<string name="stats_y_axis_label">Askeleita minuutissa</string>
|
||||||
|
<string name="about_links">Linkit</string>
|
||||||
|
<string name="zetime_prefs_inactivity_mo">Maanantai</string>
|
||||||
|
<string name="zetime_prefs_inactivity_we">Keskiviikko</string>
|
||||||
|
<string name="zetime_prefs_inactivity_su">Sunnuntai</string>
|
||||||
|
<string name="preferences_category_device_specific_settings">Laitekohtaiset asetukset</string>
|
||||||
|
<string name="calories">Kalorit</string>
|
||||||
|
<string name="distance">Etäisyys</string>
|
||||||
|
<string name="live_activity_steps_history">Askeleiden historia</string>
|
||||||
|
<string name="live_activity_total_steps">Kokonaisaskeleet</string>
|
||||||
|
<string name="about_title">Tietoja</string>
|
||||||
|
<string name="about_activity_title">Tietoja Gadgetbridgestä</string>
|
||||||
|
<string name="activity_filter_date_from">Alkaen</string>
|
||||||
|
<string name="activity_filter_date_to">Päättyen</string>
|
||||||
|
<string name="pref_screen_notification_profile_missed_call">Vastaamatta jääneen puhelun ilmoitus</string>
|
||||||
|
<string name="about_version">Versio %s</string>
|
||||||
|
<string name="chart_steps">Askeleet</string>
|
||||||
|
<string name="pref_screen_notification_profile_email">Sähköposti-ilmoitus</string>
|
||||||
|
<string name="pref_screen_notification_profile_generic_social">Sosiaalinen verkosto</string>
|
||||||
|
<string name="pref_screen_notification_profile_incoming_call">Saapuvan puhelun ilmoitus</string>
|
||||||
|
<string name="zetime_prefs_inactivity_th">Torstai</string>
|
||||||
|
<string name="zetime_prefs_inactivity_tu">Tiistai</string>
|
||||||
|
<string name="pref_screen_notification_profile_calendar">Kalenteri-ilmoitus</string>
|
||||||
|
<string name="activity_detail_duration_label">Kesto</string>
|
||||||
|
<string name="watchface_setting_wrist_flick_duration">Kesto (ms):</string>
|
||||||
|
<string name="sleep_activity_date_range">Alkaen %1$s päättyen %2$s</string>
|
||||||
|
<string name="weekstepschart_steps_a_week">Askeleita viikossa</string>
|
||||||
|
<string name="title_activity_device_specific_settings">Laitekohtaiset asetukset</string>
|
||||||
|
<string name="zetime_prefs_inactivity_sa">Lauantai</string>
|
||||||
|
<string name="zetime_prefs_inactivity_fr">Perjantai</string>
|
||||||
|
<string name="pref_title_location_latitude">Leveysaste</string>
|
||||||
|
<string name="pref_title_location_longitude">Pituusaste</string>
|
||||||
|
<string name="distance_format_feet">###ft</string>
|
||||||
|
<string name="distance_format_kilometers">###.#km</string>
|
||||||
|
<string name="distance_format_meters">###m</string>
|
||||||
|
<string name="devicetype_vesc">VESC</string>
|
||||||
|
<string name="watchface_dialog_widget_width">Leveys:</string>
|
||||||
|
<string name="watchface_dialog_widget_timezone">Aikavyöhyke:</string>
|
||||||
</resources>
|
</resources>
|
@ -914,7 +914,7 @@ Temps de sommeil préféré en heures</string>
|
|||||||
<string name="prefs_events_forwarding_fellsleep">Au sommeil</string>
|
<string name="prefs_events_forwarding_fellsleep">Au sommeil</string>
|
||||||
<string name="prefs_events_forwarding_title">Actions de l\'appareil</string>
|
<string name="prefs_events_forwarding_title">Actions de l\'appareil</string>
|
||||||
<string name="prefs_events_forwarding_summary">Utiliser les évènements de l\'appareil pour déclencher des actions et des messages diffusé Android</string>
|
<string name="prefs_events_forwarding_summary">Utiliser les évènements de l\'appareil pour déclencher des actions et des messages diffusé Android</string>
|
||||||
<string name="menuitem_cycles">Période</string>
|
<string name="menuitem_cycles">Suivi des Cycles féminins</string>
|
||||||
<string name="freestyle">Style libre</string>
|
<string name="freestyle">Style libre</string>
|
||||||
<string name="breaststroke">Rythme mammaire</string>
|
<string name="breaststroke">Rythme mammaire</string>
|
||||||
<string name="activity_filter_to_placeholder">aujourd\'hui</string>
|
<string name="activity_filter_to_placeholder">aujourd\'hui</string>
|
||||||
@ -1583,4 +1583,17 @@ Temps de sommeil préféré en heures</string>
|
|||||||
<string name="sony_anc_optimizer_status_wearing_condition">Mesure des conditions actuelles…</string>
|
<string name="sony_anc_optimizer_status_wearing_condition">Mesure des conditions actuelles…</string>
|
||||||
<string name="devicetype_amazfit_pop">Amazfit Pop</string>
|
<string name="devicetype_amazfit_pop">Amazfit Pop</string>
|
||||||
<string name="devicetype_amazfit_pop_pro">Amazfit Pop Pro</string>
|
<string name="devicetype_amazfit_pop_pro">Amazfit Pop Pro</string>
|
||||||
|
<string name="menuitem_nothing">Rien</string>
|
||||||
|
<string name="pref_title_opentracks_packagename">Nom du logiciel OpenTracks</string>
|
||||||
|
<string name="pref_summary_opentracks_packagename">Utilisé pour démarrer/arrêter l\'enregistrement GPS dans une app. de fitness externe.</string>
|
||||||
|
<string name="pref_device_action_fitness_app_control_start">Démarrage de l\'enregistrement dans l\'app Fitness</string>
|
||||||
|
<string name="pref_device_action_fitness_app_control_stop">Arrêt de l\'enregistrement dans l\'app Fitness</string>
|
||||||
|
<string name="pref_title_notifications_generic_settings">Configuration des notifications Android</string>
|
||||||
|
<string name="autoExport_lastTime_label">Dernier export automatique : %1$s</string>
|
||||||
|
<string name="activity_db_management_autoexport_enabled_yes">L\'export automatique est activé.</string>
|
||||||
|
<string name="activity_db_management_autoexport_scheduled_yes">L\'export automatique a été (initialement) réglé pour %1$s</string>
|
||||||
|
<string name="activity_db_management_autoexport_scheduled_no">L\'export automatique n\'a pas été planifié.</string>
|
||||||
|
<string name="activity_db_management_autoexport_enabled_no">L\'export automatique est désactivé.</string>
|
||||||
|
<string name="activity_db_management_autoexport_location">L\'emplacement n\'a pas pu être détecté. Probablement un problème avec les nouvelles permissions du système Android. Très probablement, l\'export automatique ne fonctionne pas actuellement.</string>
|
||||||
|
<string name="watchface_dialog_pre_setting_position">pré-configuration de la position à %s</string>
|
||||||
</resources>
|
</resources>
|
@ -931,7 +931,7 @@
|
|||||||
\n
|
\n
|
||||||
\nהמשך מעבר לנקודה זו הוא על אחריותך!</string>
|
\nהמשך מעבר לנקודה זו הוא על אחריותך!</string>
|
||||||
<string name="menuitem_stress">לחץ</string>
|
<string name="menuitem_stress">לחץ</string>
|
||||||
<string name="menuitem_cycles">מעקב מחזוריות</string>
|
<string name="menuitem_cycles">מעקב מחזור</string>
|
||||||
<string name="menuitem_breathing">נשימה</string>
|
<string name="menuitem_breathing">נשימה</string>
|
||||||
<string name="devicetype_miband5">Mi Band 5</string>
|
<string name="devicetype_miband5">Mi Band 5</string>
|
||||||
<string name="ignore_bonded_devices_description">הפעלת אפשרות זו תתעלם ממכשירים שכבר אוגדו/צומדו טרם הסריקה</string>
|
<string name="ignore_bonded_devices_description">הפעלת אפשרות זו תתעלם ממכשירים שכבר אוגדו/צומדו טרם הסריקה</string>
|
||||||
@ -1579,4 +1579,17 @@
|
|||||||
<string name="sony_anc_optimize_confirmation_description">ניתן להשתמש באוזניות כרגיל. אם מצב הבלאי או הלחץ האטמוספרי משתנה, יש להריץ את המשפר שוב.</string>
|
<string name="sony_anc_optimize_confirmation_description">ניתן להשתמש באוזניות כרגיל. אם מצב הבלאי או הלחץ האטמוספרי משתנה, יש להריץ את המשפר שוב.</string>
|
||||||
<string name="devicetype_amazfit_pop">Amazfit Pop</string>
|
<string name="devicetype_amazfit_pop">Amazfit Pop</string>
|
||||||
<string name="devicetype_amazfit_pop_pro">Amazfit Pop Pro</string>
|
<string name="devicetype_amazfit_pop_pro">Amazfit Pop Pro</string>
|
||||||
|
<string name="menuitem_nothing">כלום</string>
|
||||||
|
<string name="pref_title_opentracks_packagename">שם חבילה ב־OpenTracks</string>
|
||||||
|
<string name="pref_summary_opentracks_packagename">משמש להפעלת/עצירת הקלטת מסלולי GPS מיישומוני חיטוב חיצוניים.</string>
|
||||||
|
<string name="pref_device_action_fitness_app_control_stop">עצירת מעקב יישומון חיטוב</string>
|
||||||
|
<string name="pref_device_action_fitness_app_control_start">התחלת מעקב יישומון חיטוב</string>
|
||||||
|
<string name="pref_title_notifications_generic_settings">הגדרות הודעות של Android</string>
|
||||||
|
<string name="autoExport_lastTime_label">הייצוא האוטומטי האחרון: %1$s</string>
|
||||||
|
<string name="activity_db_management_autoexport_enabled_yes">ייצוא אוטומטי מופעל.</string>
|
||||||
|
<string name="activity_db_management_autoexport_enabled_no">ייצוא אוטומטי מושבת.</string>
|
||||||
|
<string name="activity_db_management_autoexport_scheduled_no">הייצוא האוטומטי לא תוזמן.</string>
|
||||||
|
<string name="activity_db_management_autoexport_scheduled_yes">הייצוא האוטומטי תוזמן (במקור) ל־%1$s</string>
|
||||||
|
<string name="activity_db_management_autoexport_location">לא ניתן לפענח את המיקום. כנראה תקלה במערכת ההרשאות החדשה של Android. סביר להניח שהייצוא האוטומטי לא עובד כרגע.</string>
|
||||||
|
<string name="watchface_dialog_pre_setting_position">המיקום מוגדר מראש לכדי %s</string>
|
||||||
</resources>
|
</resources>
|
@ -1552,4 +1552,9 @@
|
|||||||
<string name="sony_speak_to_chat">Speak-to-chat</string>
|
<string name="sony_speak_to_chat">Speak-to-chat</string>
|
||||||
<string name="pref_header_sony_device_info">Informacije urađaja</string>
|
<string name="pref_header_sony_device_info">Informacije urađaja</string>
|
||||||
<string name="audio_codec">Audio kodek</string>
|
<string name="audio_codec">Audio kodek</string>
|
||||||
|
<string name="start">Početak</string>
|
||||||
|
<string name="devicetype_amazfit_pop">Amazfit Pop</string>
|
||||||
|
<string name="devicetype_amazfit_pop_pro">Amazfit Pop Pro</string>
|
||||||
|
<string name="menuitem_nothing">Ništa</string>
|
||||||
|
<string name="unknown">Nepoznato</string>
|
||||||
</resources>
|
</resources>
|
@ -121,7 +121,7 @@
|
|||||||
<string name="pref_title_location_aquire">Acquisisci posizione</string>
|
<string name="pref_title_location_aquire">Acquisisci posizione</string>
|
||||||
<string name="pref_title_location_latitude">Latitudine</string>
|
<string name="pref_title_location_latitude">Latitudine</string>
|
||||||
<string name="pref_title_location_longitude">Longitudine</string>
|
<string name="pref_title_location_longitude">Longitudine</string>
|
||||||
<string name="pref_title_location_keep_uptodate">Mantieni aggiornata la posizion</string>
|
<string name="pref_title_location_keep_uptodate">Mantieni aggiornata la posizione</string>
|
||||||
<string name="pref_summary_location_keep_uptodate">Cerca di ottenere la posizione aggiornata durante l\'utilizzo, usa quella memorizzata come backup</string>
|
<string name="pref_summary_location_keep_uptodate">Cerca di ottenere la posizione aggiornata durante l\'utilizzo, usa quella memorizzata come backup</string>
|
||||||
<string name="toast_enable_networklocationprovider">Per cortesia abilita la localizzazione utilizzando la rete</string>
|
<string name="toast_enable_networklocationprovider">Per cortesia abilita la localizzazione utilizzando la rete</string>
|
||||||
<string name="toast_aqurired_networklocation">posizione acquisita</string>
|
<string name="toast_aqurired_networklocation">posizione acquisita</string>
|
||||||
@ -317,8 +317,8 @@
|
|||||||
<string name="mi2_prefs_goal_notification_summary">La band vibrerà una volta raggiunto l\'obbiettivo passi giornalieri</string>
|
<string name="mi2_prefs_goal_notification_summary">La band vibrerà una volta raggiunto l\'obbiettivo passi giornalieri</string>
|
||||||
<string name="mi2_prefs_display_items">Elementi mostrati</string>
|
<string name="mi2_prefs_display_items">Elementi mostrati</string>
|
||||||
<string name="mi2_prefs_display_items_summary">Scegli gli elementi da mostrare sullo schermo della band</string>
|
<string name="mi2_prefs_display_items_summary">Scegli gli elementi da mostrare sullo schermo della band</string>
|
||||||
<string name="mi2_prefs_activate_display_on_lift">Attiva il display quando sollevato</string>
|
<string name="mi2_prefs_activate_display_on_lift">Attiva il display quando il dispositivo viene sollevato</string>
|
||||||
<string name="mi2_prefs_rotate_wrist_to_switch_info">Rotazione polso per cambiare vista</string>
|
<string name="mi2_prefs_rotate_wrist_to_switch_info">Rotazione del polso per passare da una vista all\'altra</string>
|
||||||
<string name="mi2_prefs_do_not_disturb">Non disturbare</string>
|
<string name="mi2_prefs_do_not_disturb">Non disturbare</string>
|
||||||
<string name="mi2_prefs_do_not_disturb_summary">La band non riceverà notifiche quando è attiva</string>
|
<string name="mi2_prefs_do_not_disturb_summary">La band non riceverà notifiche quando è attiva</string>
|
||||||
<string name="mi2_prefs_inactivity_warnings">Allarmi inattività</string>
|
<string name="mi2_prefs_inactivity_warnings">Allarmi inattività</string>
|
||||||
@ -564,7 +564,7 @@
|
|||||||
<string name="minutes_30">30 minuti</string>
|
<string name="minutes_30">30 minuti</string>
|
||||||
<string name="you_slept">Hai dormito dalle %1$s alle %2$s</string>
|
<string name="you_slept">Hai dormito dalle %1$s alle %2$s</string>
|
||||||
<string name="you_did_not_sleep">Non hai dormito</string>
|
<string name="you_did_not_sleep">Non hai dormito</string>
|
||||||
<string name="mi3_prefs_band_screen_unlock_summary">Swipe up per sbloccare lo schermo della band</string>
|
<string name="mi3_prefs_band_screen_unlock_summary">Scorri verso l\'alto per sbloccare lo schermo della band</string>
|
||||||
<string name="mi3_prefs_night_mode">Modalità notturna</string>
|
<string name="mi3_prefs_night_mode">Modalità notturna</string>
|
||||||
<string name="norwegian_bokmal">Norvegese Bokmål</string>
|
<string name="norwegian_bokmal">Norvegese Bokmål</string>
|
||||||
<string name="russian">Russo</string>
|
<string name="russian">Russo</string>
|
||||||
@ -1120,8 +1120,8 @@
|
|||||||
<string name="menuitem_mutephone">Silenzia cellulare</string>
|
<string name="menuitem_mutephone">Silenzia cellulare</string>
|
||||||
<string name="menuitem_findphone">Trova cellulare</string>
|
<string name="menuitem_findphone">Trova cellulare</string>
|
||||||
<string name="menuitem_spo2">Ossigenazione sangue</string>
|
<string name="menuitem_spo2">Ossigenazione sangue</string>
|
||||||
<string name="pref_summary_connected_advertisement">Mantieni visibile via Bluetooth anche quando connesso</string>
|
<string name="pref_summary_connected_advertisement">Mantieni visibile il dispositivo via Bluetooth anche quando questo è connesso</string>
|
||||||
<string name="pref_title_connected_advertisement">Visibile mentre connessi</string>
|
<string name="pref_title_connected_advertisement">Dispositivo visibile durante la connessione</string>
|
||||||
<string name="prefs_autoremove_message">Chiudi automaticamente le notifiche SMS</string>
|
<string name="prefs_autoremove_message">Chiudi automaticamente le notifiche SMS</string>
|
||||||
<string name="prefs_fake_ring_duration">Suoneria continua fittizia</string>
|
<string name="prefs_fake_ring_duration">Suoneria continua fittizia</string>
|
||||||
<string name="prefs_operating_sounds">Suoni di operazione</string>
|
<string name="prefs_operating_sounds">Suoni di operazione</string>
|
||||||
@ -1261,4 +1261,50 @@
|
|||||||
<string name="pref_title_developer_settings">Impostazioni sviluppatore</string>
|
<string name="pref_title_developer_settings">Impostazioni sviluppatore</string>
|
||||||
<string name="button_watchface_add_widget">Aggiungi widget</string>
|
<string name="button_watchface_add_widget">Aggiungi widget</string>
|
||||||
<string name="watchface_toast_settings_incomplete">Impostazioni incomplete, widget non aggiunto</string>
|
<string name="watchface_toast_settings_incomplete">Impostazioni incomplete, widget non aggiunto</string>
|
||||||
|
<string name="reminder_date">Data</string>
|
||||||
|
<string name="unknown">Sconosciuto</string>
|
||||||
|
<string name="title_activity_set_reminders">Configura promemoria</string>
|
||||||
|
<string name="reminder_repeat">Ripeti</string>
|
||||||
|
<string name="reminder_time">Orario</string>
|
||||||
|
<string name="reminder_message">Messaggio</string>
|
||||||
|
<string name="miband_prefs_reserve_reminder_calendar">Promemoria da riservare per i prossimi eventi del calendario</string>
|
||||||
|
<string name="controlcenter_power_off">Spegni</string>
|
||||||
|
<string name="controlcenter_power_off_confirm_title">Spegni</string>
|
||||||
|
<string name="controlcenter_power_off_confirm_description">Sei sicuro di voler spegnere il dispositivo\?</string>
|
||||||
|
<string name="device_card_activity_card_title">Informazioni sull\'attività nella carta del dispositivo</string>
|
||||||
|
<string name="device_card_activity_card_title_summary">Scegli quale attività mostrare nella carta del dispositivo</string>
|
||||||
|
<string name="prefs_activity_in_device_card_title">Mostra informazioni sull\'attività nella carta del dispositivo</string>
|
||||||
|
<string name="prefs_activity_in_device_card_title_summary">Mostra i passi, la distanza o il sonno attuali nella carta del dispositivo</string>
|
||||||
|
<string name="prefs_activity_in_device_card_sleep_title_summary">Mostra la durata del sonno</string>
|
||||||
|
<string name="prefs_activity_in_device_card_distance_title_summary">La distanza viene calcolata dai passi e dalla lunghezza del passo (configurabile in Impostazioni - Informazioni sull\'utilizzatore)</string>
|
||||||
|
<string name="prefs_activity_in_device_card_steps_title_summary">Mostra passi totali</string>
|
||||||
|
<string name="pref_header_system">Sistema</string>
|
||||||
|
<string name="pref_header_equalizer">Equalizzatore</string>
|
||||||
|
<string name="pref_title_notification_use_as">Utilizza la lista delle applicazioni per...</string>
|
||||||
|
<string name="pref_title_message_privacy_mode">Modalità privacy per i messaggi</string>
|
||||||
|
<string name="pref_message_privacy_mode_off">Mostra contenuto</string>
|
||||||
|
<string name="controlcenter_start_configure_reminders">Configura promemoria</string>
|
||||||
|
<string name="reminder_no_free_slots_title">Spazio esaurito</string>
|
||||||
|
<string name="reminder_no_free_slots_description">Il dispositivo non ha spazio libero per aggiungere altri promemoria (totali: %1$s)</string>
|
||||||
|
<string name="title_activity_reminder_details">Dettagli promemoria</string>
|
||||||
|
<string name="reminder_time_every_day">%1$s, ogni giorno</string>
|
||||||
|
<string name="reminder_time_every_week">%1$s, ogni settimana</string>
|
||||||
|
<string name="reminder_time_every_month">%1$s, ogni mese</string>
|
||||||
|
<string name="reminder_time_every_year">%1$s, ogni anno</string>
|
||||||
|
<string name="reminder_once">Una volta sola</string>
|
||||||
|
<string name="reminder_every_day">Ogni giorno</string>
|
||||||
|
<string name="reminder_every_week">Ogni settimana</string>
|
||||||
|
<string name="reminder_every_month">Ogni mese</string>
|
||||||
|
<string name="reminder_every_year">Ogni anno</string>
|
||||||
|
<string name="reminder_delete_confirm_title">Elimina promemoria</string>
|
||||||
|
<string name="reminder_delete_confirm_description">Sei sicuro di voler eliminare il promemoria\?</string>
|
||||||
|
<string name="mi2_prefs_do_not_disturb_lift_wrist">Attiva il display quando il dispositivo viene sollevato durante la modalità non disturbare</string>
|
||||||
|
<string name="pref_title_ping_tone">Suono di ping</string>
|
||||||
|
<string name="prefs_activity_in_device_card_sleep_title">Sonno</string>
|
||||||
|
<string name="pref_header_other">Altro</string>
|
||||||
|
<string name="discovery_bluetooth_scan">Scansione Bluetooth:</string>
|
||||||
|
<string name="discovery_bluetooth_le_scan">Scansione Bluetooth LE:</string>
|
||||||
|
<string name="reminder_time_once">%1$s, una volta sola</string>
|
||||||
|
<string name="check_all_applications">Controlla tutte le applicazioni</string>
|
||||||
|
<string name="prefs_reserve_reminder_calendar_summary">Numero di eventi del calendario che verranno sincronizzati</string>
|
||||||
</resources>
|
</resources>
|
@ -303,7 +303,7 @@
|
|||||||
<string name="liveactivity_live_activity">Aktivitet i sanntid</string>
|
<string name="liveactivity_live_activity">Aktivitet i sanntid</string>
|
||||||
<string name="weeksteps_today_steps_description">Steg i dag, mål: %1$s</string>
|
<string name="weeksteps_today_steps_description">Steg i dag, mål: %1$s</string>
|
||||||
<string name="pref_title_dont_ack_transfer">Ikke send bekreftelse på aktivitetsdataoverføring</string>
|
<string name="pref_title_dont_ack_transfer">Ikke send bekreftelse på aktivitetsdataoverføring</string>
|
||||||
<string name="pref_summary_dont_ack_transfers">Hvis aktivitetsdataen ikke bekreftes til bandet, vil de ikke bli tømt. Nyttig hvis Gb brukes sammen med andre programmer.</string>
|
<string name="pref_summary_dont_ack_transfers">Hvis de ikke bekreftes til bandet, vil de ikke bli tømt. Nyttig hvis GB brukes sammen med andre programmer.</string>
|
||||||
<string name="pref_summary_keep_data_on_device">Beholder aktivitetsdata på Mi Band-et, selv etter synkronisering. Nyttig hvis Gb brukes sammen med andre programmer.</string>
|
<string name="pref_summary_keep_data_on_device">Beholder aktivitetsdata på Mi Band-et, selv etter synkronisering. Nyttig hvis Gb brukes sammen med andre programmer.</string>
|
||||||
<string name="pref_title_low_latency_fw_update">Bruk lav-latens-modus for fastvareoppgraderinger</string>
|
<string name="pref_title_low_latency_fw_update">Bruk lav-latens-modus for fastvareoppgraderinger</string>
|
||||||
<string name="pref_summary_low_latency_fw_update">Dette kan hjelpe på enheter der fastvareoppgraderinger mislykkes.</string>
|
<string name="pref_summary_low_latency_fw_update">Dette kan hjelpe på enheter der fastvareoppgraderinger mislykkes.</string>
|
||||||
@ -377,7 +377,7 @@
|
|||||||
<string name="dbmanagementactivity_error_exporting_db">Feil ved eksport av DB: %1$s</string>
|
<string name="dbmanagementactivity_error_exporting_db">Feil ved eksport av DB: %1$s</string>
|
||||||
<string name="dbmanagementactivity_error_exporting_shared">Feil ved eksport av innstilling: %1$s</string>
|
<string name="dbmanagementactivity_error_exporting_shared">Feil ved eksport av innstilling: %1$s</string>
|
||||||
<string name="dbmanagementactivity_import_data_title">Importer data?</string>
|
<string name="dbmanagementactivity_import_data_title">Importer data?</string>
|
||||||
<string name="dbmanagementactivity_overwrite_database_confirmation">Vil du virkelig overskrive gjeldende database? All nåværende aktivitetsdata (hvis noen) vil gå tapt.</string>
|
<string name="dbmanagementactivity_overwrite_database_confirmation">Vil du virkelig overskrive gjeldende data\? All nåværende aktivitetsdata (hvis noen) vil bli overskrevet.</string>
|
||||||
<string name="dbmanagementactivity_import_successful">Importert.</string>
|
<string name="dbmanagementactivity_import_successful">Importert.</string>
|
||||||
<string name="dbmanagementactivity_error_importing_db">Feil ved import av DB: %1$s</string>
|
<string name="dbmanagementactivity_error_importing_db">Feil ved import av DB: %1$s</string>
|
||||||
<string name="dbmanagementactivity_error_importing_shared">Feil ved import av innstilling: %1$s</string>
|
<string name="dbmanagementactivity_error_importing_shared">Feil ved import av innstilling: %1$s</string>
|
||||||
@ -906,7 +906,7 @@
|
|||||||
<string name="about_title">Om</string>
|
<string name="about_title">Om</string>
|
||||||
<string name="menuitem_worldclock">Verdensklokke</string>
|
<string name="menuitem_worldclock">Verdensklokke</string>
|
||||||
<string name="menuitem_stress">Stress</string>
|
<string name="menuitem_stress">Stress</string>
|
||||||
<string name="menuitem_cycles">Periode</string>
|
<string name="menuitem_cycles">Følg m.-syklus</string>
|
||||||
<string name="menuitem_breathing">Pusting</string>
|
<string name="menuitem_breathing">Pusting</string>
|
||||||
<string name="devicetype_miband5">Mi Band 5</string>
|
<string name="devicetype_miband5">Mi Band 5</string>
|
||||||
<string name="ascentSeconds">Stigende</string>
|
<string name="ascentSeconds">Stigende</string>
|
||||||
@ -1096,7 +1096,7 @@
|
|||||||
<string name="pref_notifications_and_calls_enable_misscall">Varsle om tapt anrop</string>
|
<string name="pref_notifications_and_calls_enable_misscall">Varsle om tapt anrop</string>
|
||||||
<string name="prefs_notifications_and_calls_continious_ring">Merknad for oppringing</string>
|
<string name="prefs_notifications_and_calls_continious_ring">Merknad for oppringing</string>
|
||||||
<string name="pref_title_notifications_and_calls_repeat_on_call">Merknad for tapt anrop</string>
|
<string name="pref_title_notifications_and_calls_repeat_on_call">Merknad for tapt anrop</string>
|
||||||
<string name="qhybrid_calibration_align_hint">juster visere til 12:00</string>
|
<string name="qhybrid_calibration_align_hint">Bruk knappene nedenfor for å justere viserne til 12:00.</string>
|
||||||
<string name="gps_track">GPS-spor</string>
|
<string name="gps_track">GPS-spor</string>
|
||||||
<string name="about_version">Versjon %s</string>
|
<string name="about_version">Versjon %s</string>
|
||||||
<string name="pref_title_lower_button_function_double">Nedre knapp dobbel</string>
|
<string name="pref_title_lower_button_function_double">Nedre knapp dobbel</string>
|
||||||
@ -1579,4 +1579,20 @@
|
|||||||
<string name="sony_anc_optimize_confirmation_description">Bruk hodetelefonene som vanlig. Hvis måten du bruker dem på eller lufttrykket endrer seg kan du kjøre optimalisatoren igjen.</string>
|
<string name="sony_anc_optimize_confirmation_description">Bruk hodetelefonene som vanlig. Hvis måten du bruker dem på eller lufttrykket endrer seg kan du kjøre optimalisatoren igjen.</string>
|
||||||
<string name="pref_header_sony_device_info">Enhetsinfo</string>
|
<string name="pref_header_sony_device_info">Enhetsinfo</string>
|
||||||
<string name="sony_anc_optimize_title">Optimaliser</string>
|
<string name="sony_anc_optimize_title">Optimaliser</string>
|
||||||
|
<string name="menuitem_nothing">Ingenting</string>
|
||||||
|
<string name="devicetype_amazfit_pop">Amazfit Pop</string>
|
||||||
|
<string name="devicetype_amazfit_pop_pro">Amazfit Pop Pro</string>
|
||||||
|
<string name="devicetype_sony_wh_1000xm4">Sony WH-1000XM4</string>
|
||||||
|
<string name="pref_device_action_fitness_app_control_start">Sporingsstart for trimprogram</string>
|
||||||
|
<string name="pref_device_action_fitness_app_control_stop">Sporingsstopp for trimprogram</string>
|
||||||
|
<string name="pref_title_opentracks_packagename">OpenTracks-pakkenavn</string>
|
||||||
|
<string name="pref_title_notifications_generic_settings">Android-merknadsinnstillinger</string>
|
||||||
|
<string name="pref_summary_opentracks_packagename">Brukt for start/stopp av GPS-sporingslagring i eksternt trimprogram.</string>
|
||||||
|
<string name="activity_db_management_autoexport_enabled_yes">Auto-eksport er påslått.</string>
|
||||||
|
<string name="activity_db_management_autoexport_enabled_no">Auto-eksport er avslått.</string>
|
||||||
|
<string name="autoExport_lastTime_label">Siste auto-eksport:%1$s</string>
|
||||||
|
<string name="activity_db_management_autoexport_scheduled_yes">Auto-eksport ble (opprinnelig) planlagt %1$s</string>
|
||||||
|
<string name="activity_db_management_autoexport_scheduled_no">Auto-eksport er ikke planlagt.</string>
|
||||||
|
<string name="activity_db_management_autoexport_location">Forsto ikke plassering. Antagelig er dette et tilgangsproblem i Android. Mest sannsynlig fungerer ikke auto-eksport nå.</string>
|
||||||
|
<string name="watchface_dialog_pre_setting_position">forhåndsinnstiller posisjon til %s</string>
|
||||||
</resources>
|
</resources>
|
@ -1580,4 +1580,16 @@
|
|||||||
<string name="sony_anc_optimizer_status_starting">Starten…</string>
|
<string name="sony_anc_optimizer_status_starting">Starten…</string>
|
||||||
<string name="devicetype_amazfit_pop_pro">Amazfit Pop Pro</string>
|
<string name="devicetype_amazfit_pop_pro">Amazfit Pop Pro</string>
|
||||||
<string name="devicetype_amazfit_pop">Amazfit Pop</string>
|
<string name="devicetype_amazfit_pop">Amazfit Pop</string>
|
||||||
|
<string name="menuitem_nothing">Niets</string>
|
||||||
|
<string name="pref_summary_opentracks_packagename">Wordt gebruikt voor het starten/stoppen van GPS-trackregistratie in externe fitness-app.</string>
|
||||||
|
<string name="pref_title_opentracks_packagename">OpenTracks-pakketnaam</string>
|
||||||
|
<string name="pref_device_action_fitness_app_control_start">Fitness-app-tracking starten</string>
|
||||||
|
<string name="pref_device_action_fitness_app_control_stop">Fitness-app-tracking stoppen</string>
|
||||||
|
<string name="pref_title_notifications_generic_settings">Instellingen voor Android-meldingen</string>
|
||||||
|
<string name="activity_db_management_autoexport_scheduled_no">AutoExport is niet gepland.</string>
|
||||||
|
<string name="activity_db_management_autoexport_location">Locatie was niet te begrijpen. Waarschijnlijk een probleem met het nieuwere Android-toestemmingssysteem. Hoogstwaarschijnlijk werkt automatisch exporteren nu niet.</string>
|
||||||
|
<string name="activity_db_management_autoexport_enabled_no">AutoExport is niet ingeschakeld.</string>
|
||||||
|
<string name="activity_db_management_autoexport_enabled_yes">AutoExport is ingeschakeld.</string>
|
||||||
|
<string name="activity_db_management_autoexport_scheduled_yes">AutoExport is (oorspronkelijk) gepland voor %1$s</string>
|
||||||
|
<string name="autoExport_lastTime_label">Laatste AutoExport: %1$s</string>
|
||||||
</resources>
|
</resources>
|
@ -1241,7 +1241,7 @@
|
|||||||
<string name="pref_summary_canned_messages_dismisscall">Odrzucaj połączenia na zegarku z wiadomością SMS</string>
|
<string name="pref_summary_canned_messages_dismisscall">Odrzucaj połączenia na zegarku z wiadomością SMS</string>
|
||||||
<string name="qhybrid_summary_file_management">Przesyłanie i pobieranie plików</string>
|
<string name="qhybrid_summary_file_management">Przesyłanie i pobieranie plików</string>
|
||||||
<string name="pref_summary_physical_buttons">Konfiguracja funkcji przycisków fizycznych zegarka</string>
|
<string name="pref_summary_physical_buttons">Konfiguracja funkcji przycisków fizycznych zegarka</string>
|
||||||
<string name="kind_agps_bundle">AGPS Bundle</string>
|
<string name="kind_agps_bundle">Pakiet AGPS</string>
|
||||||
<string name="qhybrid_calibration_100_steps">100 kroków</string>
|
<string name="qhybrid_calibration_100_steps">100 kroków</string>
|
||||||
<string name="qhybrid_calibration_10_steps">10 kroków</string>
|
<string name="qhybrid_calibration_10_steps">10 kroków</string>
|
||||||
<string name="qhybrid_calibration_1_step">1 krok</string>
|
<string name="qhybrid_calibration_1_step">1 krok</string>
|
||||||
@ -1268,7 +1268,7 @@
|
|||||||
<string name="qhybrid_pref_summary_external_intents">Umożliwia innym aplikacjom Androida na przesyłanie/nadpisywanie plików</string>
|
<string name="qhybrid_pref_summary_external_intents">Umożliwia innym aplikacjom Androida na przesyłanie/nadpisywanie plików</string>
|
||||||
<string name="pref_summary_developer_settings">Ustawienia i funkcje wykorzystywane przez programistów</string>
|
<string name="pref_summary_developer_settings">Ustawienia i funkcje wykorzystywane przez programistów</string>
|
||||||
<string name="pref_title_developer_settings">Opcje programistyczne</string>
|
<string name="pref_title_developer_settings">Opcje programistyczne</string>
|
||||||
<string name="menuitem_barometer">Barometer</string>
|
<string name="menuitem_barometer">Barometr</string>
|
||||||
<string name="pref_theme_black_background">Używaj czarnego tła w ciemnym motywie</string>
|
<string name="pref_theme_black_background">Używaj czarnego tła w ciemnym motywie</string>
|
||||||
<string name="activity_summary_detail_editing_gpx_track">Edycja połączonej ścieżki GPX</string>
|
<string name="activity_summary_detail_editing_gpx_track">Edycja połączonej ścieżki GPX</string>
|
||||||
<string name="set">Ustaw</string>
|
<string name="set">Ustaw</string>
|
||||||
@ -1453,12 +1453,12 @@
|
|||||||
<string name="title_activity_reminder_details">Szczegóły przypomnienia</string>
|
<string name="title_activity_reminder_details">Szczegóły przypomnienia</string>
|
||||||
<string name="activity_prefs_discovery_pairing">Opcje wykrywania i parowania</string>
|
<string name="activity_prefs_discovery_pairing">Opcje wykrywania i parowania</string>
|
||||||
<string name="prefs_fm_preset_instructions">Długie naciśnięcie przycisku powoduje zapisanie ustawień</string>
|
<string name="prefs_fm_preset_instructions">Długie naciśnięcie przycisku powoduje zapisanie ustawień</string>
|
||||||
<string name="prefs_fm_presets_presets">Ustawienia</string>
|
<string name="prefs_fm_presets_presets">Ustawienia wstępne</string>
|
||||||
<string name="minHR">Minimalne tętno</string>
|
<string name="minHR">Minimalne tętno</string>
|
||||||
<string name="sony_sound_position_off">Wyłączony</string>
|
<string name="sony_sound_position_off">Wyłączony</string>
|
||||||
<string name="sony_sound_position_front">Przód</string>
|
<string name="sony_sound_position_front">Przód</string>
|
||||||
<string name="pref_header_system">System</string>
|
<string name="pref_header_system">System</string>
|
||||||
<string name="pref_header_other">Pozostałe</string>
|
<string name="pref_header_other">Inne</string>
|
||||||
<string name="devicetype_bose_qc35">Bose QC35</string>
|
<string name="devicetype_bose_qc35">Bose QC35</string>
|
||||||
<string name="devicetype_vesc">VESC</string>
|
<string name="devicetype_vesc">VESC</string>
|
||||||
<string name="maxHR">Maksymalne tętno</string>
|
<string name="maxHR">Maksymalne tętno</string>
|
||||||
@ -1467,7 +1467,7 @@
|
|||||||
<string name="add_test_device">Dodaj urządzenie testowe</string>
|
<string name="add_test_device">Dodaj urządzenie testowe</string>
|
||||||
<string name="ascentDistance">Dystans pod górę</string>
|
<string name="ascentDistance">Dystans pod górę</string>
|
||||||
<string name="descentDistance">Dystans w dół</string>
|
<string name="descentDistance">Dystans w dół</string>
|
||||||
<string name="maxStride">Maksymalny Krok</string>
|
<string name="maxStride">Maksymalny krok</string>
|
||||||
<string name="activity_type_climbing">Wspinaczka</string>
|
<string name="activity_type_climbing">Wspinaczka</string>
|
||||||
<string name="devicetype_sonyswr12">Sony SWR12</string>
|
<string name="devicetype_sonyswr12">Sony SWR12</string>
|
||||||
<string name="devicetype_sony_wf_sp800n">Sony WF-SP800N</string>
|
<string name="devicetype_sony_wf_sp800n">Sony WF-SP800N</string>
|
||||||
@ -1486,7 +1486,7 @@
|
|||||||
<string name="reminder_delete_confirm_title">Usuń przypomnienie</string>
|
<string name="reminder_delete_confirm_title">Usuń przypomnienie</string>
|
||||||
<string name="reminder_no_free_slots_description">Urządzenie nie ma wolnych slotów na przypomnienia (całkowita liczba slotów: %1$s)</string>
|
<string name="reminder_no_free_slots_description">Urządzenie nie ma wolnych slotów na przypomnienia (całkowita liczba slotów: %1$s)</string>
|
||||||
<string name="devicetype_sony_wh_1000xm4">Sony WH-1000XM4</string>
|
<string name="devicetype_sony_wh_1000xm4">Sony WH-1000XM4</string>
|
||||||
<string name="about_hash">Zatwierdź %s</string>
|
<string name="about_hash">Zatwierdzenie %s</string>
|
||||||
<string name="device_unsupported">NIEOBSŁUGIWANE</string>
|
<string name="device_unsupported">NIEOBSŁUGIWANE</string>
|
||||||
<string name="discover_unsupported_devices">Odkryj nieobsługiwane urządzenia</string>
|
<string name="discover_unsupported_devices">Odkryj nieobsługiwane urządzenia</string>
|
||||||
<string name="averageAltitude">Średnia</string>
|
<string name="averageAltitude">Średnia</string>
|
||||||
@ -1518,11 +1518,11 @@
|
|||||||
<string name="sony_equalizer_preset_relaxed">Zrelaksowany</string>
|
<string name="sony_equalizer_preset_relaxed">Zrelaksowany</string>
|
||||||
<string name="sony_equalizer_preset_manual">Niestandardowe</string>
|
<string name="sony_equalizer_preset_manual">Niestandardowe</string>
|
||||||
<string name="sony_equalizer_preset_custom_2">Niestandardowy 2</string>
|
<string name="sony_equalizer_preset_custom_2">Niestandardowy 2</string>
|
||||||
<string name="pref_header_sony_equalizer_bands">Zespoły</string>
|
<string name="pref_header_sony_equalizer_bands">Pasma</string>
|
||||||
<string name="pref_header_sony_equalizer_preset_custom_1">Niestandardowe ustawienie 1</string>
|
<string name="pref_header_sony_equalizer_preset_custom_1">Niestandardowe ustawienie 1</string>
|
||||||
<string name="pref_header_sony_equalizer_preset_custom_2">Niestandardowe ustawienie 2</string>
|
<string name="pref_header_sony_equalizer_preset_custom_2">Niestandardowe ustawienie 2</string>
|
||||||
<string name="sony_equalizer_clear_bass">Czysty bas</string>
|
<string name="sony_equalizer_clear_bass">Czysty bas</string>
|
||||||
<string name="sony_audio_upsampling">Upsampling dzięku</string>
|
<string name="sony_audio_upsampling">Upsampling dźwięku</string>
|
||||||
<string name="sony_speak_to_chat_sensitivity">Czułość wykrywania głosu</string>
|
<string name="sony_speak_to_chat_sensitivity">Czułość wykrywania głosu</string>
|
||||||
<string name="sony_speak_to_chat_sensitivity_auto">Automatyczny</string>
|
<string name="sony_speak_to_chat_sensitivity_auto">Automatyczny</string>
|
||||||
<string name="sony_speak_to_chat_sensitivity_high">Wysoki</string>
|
<string name="sony_speak_to_chat_sensitivity_high">Wysoki</string>
|
||||||
@ -1573,4 +1573,35 @@
|
|||||||
<string name="pref_activity_recognition_mode_auto">automatyczny</string>
|
<string name="pref_activity_recognition_mode_auto">automatyczny</string>
|
||||||
<string name="menuitem_menu">Menu</string>
|
<string name="menuitem_menu">Menu</string>
|
||||||
<string name="devicetype_domyos_t540">Domyos T540</string>
|
<string name="devicetype_domyos_t540">Domyos T540</string>
|
||||||
|
<string name="unknown">Nieznany</string>
|
||||||
|
<string name="devicetype_amazfit_pop_pro">Amazfit Pop Pro</string>
|
||||||
|
<string name="start">Start</string>
|
||||||
|
<string name="devicetype_amazfit_pop">Amazfit Pop</string>
|
||||||
|
<string name="audio_codec">Kodek audio</string>
|
||||||
|
<string name="pref_header_sony_device_info">Informacje o urządzeniu</string>
|
||||||
|
<string name="pref_anc_optimizer_state_pressure">Ciśnienie atmosferyczne</string>
|
||||||
|
<string name="sony_anc_optimizer_status_analyzing">Analizowanie…</string>
|
||||||
|
<string name="sony_anc_optimize_title">Zoptymalizuj</string>
|
||||||
|
<string name="menuitem_nothing">Nic</string>
|
||||||
|
<string name="pref_header_sony_anc_optimizer">Optymalizator redukcji szumów</string>
|
||||||
|
<string name="pref_title_opentracks_packagename">Nazwa pakietu aplikacji OpenTracks</string>
|
||||||
|
<string name="pref_summary_opentracks_packagename">Używane do uruchamiania/zatrzymywania rejestracji trasy GPS w zewnętrznej aplikacji fitness.</string>
|
||||||
|
<string name="sony_anc_optimize_description">Kliknij, aby uruchomić optymalizator redukcji szumów.</string>
|
||||||
|
<string name="sony_anc_optimize_confirmation_title">Optymalizator redukcji szumów</string>
|
||||||
|
<string name="sony_anc_optimizer_status_starting">Uruchamianie…</string>
|
||||||
|
<string name="sony_anc_optimizer_status_not_running">Nieuruchomiony</string>
|
||||||
|
<string name="sony_anc_optimizer_status_atmospheric_pressure">Pomiar ciśnienia atmosferycznego…</string>
|
||||||
|
<string name="sony_anc_optimizer_status_finished">Kończenie…</string>
|
||||||
|
<string name="sony_anc_optimizer_status_wearing_condition">Mierzenie warunków użytkowania…</string>
|
||||||
|
<string name="pref_device_action_fitness_app_control_start">Rozpoczęcie śledzenia aplikacji fitness</string>
|
||||||
|
<string name="pref_title_notifications_generic_settings">Ustawienia powiadomień Androida</string>
|
||||||
|
<string name="autoExport_lastTime_label">Ostatni automatyczny eksport: %1$s</string>
|
||||||
|
<string name="activity_db_management_autoexport_enabled_yes">Automatyczny eksport jest włączony.</string>
|
||||||
|
<string name="activity_db_management_autoexport_enabled_no">Automatyczny eksport jest wyłączony.</string>
|
||||||
|
<string name="activity_db_management_autoexport_scheduled_yes">Automatyczny eksport został zaplanowany na %1$s</string>
|
||||||
|
<string name="activity_db_management_autoexport_scheduled_no">Automatyczny eksport nie został zaplanowany.</string>
|
||||||
|
<string name="sony_anc_optimize_confirmation_description">Używaj słuchawek tak, jak zwykle. Jeśli warunki użytkowania lub ciśnienie powietrza ulegną zmianie, uruchom optymalizator ponownie.</string>
|
||||||
|
<string name="pref_device_action_fitness_app_control_stop">Zatrzymanie śledzenia aplikacji fitness</string>
|
||||||
|
<string name="watchface_dialog_pre_setting_position">Wstępne ustawienie położenia na %s</string>
|
||||||
|
<string name="activity_db_management_autoexport_location">Lokalizacja nie jest dostępna. Najprawdopodobniej jest to spowodowane nowym systemem uprawnień Androida. Prawdopodobnie automatyczny eksport teraz nie działa.</string>
|
||||||
</resources>
|
</resources>
|
@ -70,7 +70,7 @@
|
|||||||
<string name="pref_title_notifications_generic">Suporte a notificações genéricas</string>
|
<string name="pref_title_notifications_generic">Suporte a notificações genéricas</string>
|
||||||
<string name="pref_title_whenscreenon">…quando a tela estiver ligada</string>
|
<string name="pref_title_whenscreenon">…quando a tela estiver ligada</string>
|
||||||
<string name="pref_title_notification_filter">Não perturbar</string>
|
<string name="pref_title_notification_filter">Não perturbar</string>
|
||||||
<string name="pref_summary_notification_filter">Notificações indesejadas são bloqueadas neste modo</string>
|
<string name="pref_summary_notification_filter">Bloqueia todas as notificações quando o modo Não pertubar está ativo no telefone</string>
|
||||||
<string name="pref_title_transliteration">Transliteração</string>
|
<string name="pref_title_transliteration">Transliteração</string>
|
||||||
<string name="pref_summary_transliteration">Ative isso se seu dispositivo não tiver suporte à fonte do seu idioma</string>
|
<string name="pref_summary_transliteration">Ative isso se seu dispositivo não tiver suporte à fonte do seu idioma</string>
|
||||||
<string name="always">Sempre</string>
|
<string name="always">Sempre</string>
|
||||||
@ -938,7 +938,7 @@
|
|||||||
<string name="error_background_service_reason">A inicialização do serviço de segundo plano falhou por causa de uma exceção. Erro:</string>
|
<string name="error_background_service_reason">A inicialização do serviço de segundo plano falhou por causa de uma exceção. Erro:</string>
|
||||||
<string name="error_background_service">Falha ao iniciar o serviço de segundo plano</string>
|
<string name="error_background_service">Falha ao iniciar o serviço de segundo plano</string>
|
||||||
<string name="menuitem_stress">Estresse</string>
|
<string name="menuitem_stress">Estresse</string>
|
||||||
<string name="menuitem_cycles">Período</string>
|
<string name="menuitem_cycles">Acompanhamento de ciclo</string>
|
||||||
<string name="menuitem_breathing">Respiração</string>
|
<string name="menuitem_breathing">Respiração</string>
|
||||||
<string name="devicetype_miband5">Mi Band 5</string>
|
<string name="devicetype_miband5">Mi Band 5</string>
|
||||||
<string name="devicetype_tlw64">TLW64</string>
|
<string name="devicetype_tlw64">TLW64</string>
|
||||||
@ -1461,4 +1461,30 @@
|
|||||||
<string name="watchface_dialog_widget_update_timeout">Tempo limite de atualização em minutos:</string>
|
<string name="watchface_dialog_widget_update_timeout">Tempo limite de atualização em minutos:</string>
|
||||||
<string name="watchface_dialog_widget_timeout_hide_text">Ocultar texto ao exceder o tempo limite:</string>
|
<string name="watchface_dialog_widget_timeout_hide_text">Ocultar texto ao exceder o tempo limite:</string>
|
||||||
<string name="watchface_dialog_widget_timeout_show_circle">Mostrar círculo ao exceder o tempo limite:</string>
|
<string name="watchface_dialog_widget_timeout_show_circle">Mostrar círculo ao exceder o tempo limite:</string>
|
||||||
|
<string name="controlcenter_power_off_confirm_description">Tem a certeza que deseja desligar o dispositivo\?</string>
|
||||||
|
<string name="reminder_time_every_week">%1$s, todas as semanas</string>
|
||||||
|
<string name="reminder_time_every_month">%1$s, todos os meses</string>
|
||||||
|
<string name="reminder_once">Uma vez</string>
|
||||||
|
<string name="reminder_time_every_day">%1$s, todos os dias</string>
|
||||||
|
<string name="reminder_time_every_year">%1$s, todos os anos</string>
|
||||||
|
<string name="reminder_every_week">Todas as semanas</string>
|
||||||
|
<string name="reminder_every_day">Todos os dias</string>
|
||||||
|
<string name="reminder_every_month">Todos os meses</string>
|
||||||
|
<string name="reminder_every_year">Todos os anos</string>
|
||||||
|
<string name="reminder_delete_confirm_title">Excluir lembrete</string>
|
||||||
|
<string name="unknown">Desconhecido</string>
|
||||||
|
<string name="controlcenter_power_off">Desligar</string>
|
||||||
|
<string name="controlcenter_power_off_confirm_title">Desligar</string>
|
||||||
|
<string name="title_activity_set_reminders">Configurar lembretes</string>
|
||||||
|
<string name="controlcenter_start_configure_reminders">Configurar lembretes</string>
|
||||||
|
<string name="reminder_repeat">Repetir</string>
|
||||||
|
<string name="reminder_date">Data</string>
|
||||||
|
<string name="reminder_time">Hora</string>
|
||||||
|
<string name="reminder_message">Mensagem</string>
|
||||||
|
<string name="pref_title_notifications_generic_settings">Configurações de notificação de Android</string>
|
||||||
|
<string name="reminder_time_once">%1$s, uma vez</string>
|
||||||
|
<string name="reminder_delete_confirm_description">Tem certeza de que deseja excluir o lembrete\?</string>
|
||||||
|
<string name="reminder_no_free_slots_title">Não há posição livre</string>
|
||||||
|
<string name="discovery_bluetooth_scan">Busca por Bluetooth:</string>
|
||||||
|
<string name="discovery_bluetooth_le_scan">Busca por Bluetooth LE:</string>
|
||||||
</resources>
|
</resources>
|
@ -1566,4 +1566,14 @@
|
|||||||
<string name="sony_speak_to_chat_timeout">Tempo limite</string>
|
<string name="sony_speak_to_chat_timeout">Tempo limite</string>
|
||||||
<string name="watchface_dialog_widget_width">Largura:</string>
|
<string name="watchface_dialog_widget_width">Largura:</string>
|
||||||
<string name="devicetype_sonyswr12">Sony SWR12</string>
|
<string name="devicetype_sonyswr12">Sony SWR12</string>
|
||||||
|
<string name="unknown">Desconhecido</string>
|
||||||
|
<string name="start">Começar</string>
|
||||||
|
<string name="sony_anc_optimize_title">Optimizar</string>
|
||||||
|
<string name="pref_header_sony_anc_optimizer">Optimizador de cancelamento de ruído</string>
|
||||||
|
<string name="devicetype_amazfit_pop">Amazfit Pop</string>
|
||||||
|
<string name="devicetype_amazfit_pop_pro">Amazfit Pop Pro</string>
|
||||||
|
<string name="sony_anc_optimize_description">Clique para começar o optimizador de cancelamento de ruído.</string>
|
||||||
|
<string name="sony_anc_optimize_confirmation_title">Optimizador de cancelamento de ruído</string>
|
||||||
|
<string name="pref_anc_optimizer_state_pressure">Pressão atmosférica</string>
|
||||||
|
<string name="sony_anc_optimize_confirmation_description">Coloque os headphones como os utilizaria normalmente. Se as condições de utilização ou pressão atmosférica alterarem, execute o optimizador novamente.</string>
|
||||||
</resources>
|
</resources>
|
@ -523,7 +523,7 @@
|
|||||||
<string name="kind_firmware">Прошивка</string>
|
<string name="kind_firmware">Прошивка</string>
|
||||||
<string name="menuitem_shortcut_weather">Погода (ярлык)</string>
|
<string name="menuitem_shortcut_weather">Погода (ярлык)</string>
|
||||||
<string name="menuitem_alarm">Будильник</string>
|
<string name="menuitem_alarm">Будильник</string>
|
||||||
<string name="menuitem_timer">Таймер</string>
|
<string name="menuitem_timer">Обратный отсчёт</string>
|
||||||
<string name="activity_type_biking">Велопрогулка</string>
|
<string name="activity_type_biking">Велопрогулка</string>
|
||||||
<string name="devicetype_test">Тестовое устройство</string>
|
<string name="devicetype_test">Тестовое устройство</string>
|
||||||
<string name="devicetype_miband">Mi Band</string>
|
<string name="devicetype_miband">Mi Band</string>
|
||||||
@ -1332,7 +1332,7 @@
|
|||||||
<string name="controlcenter_power_off_confirm_title">Выключить</string>
|
<string name="controlcenter_power_off_confirm_title">Выключить</string>
|
||||||
<string name="controlcenter_power_off_confirm_description">Вы уверены, что хотите выключить браслет/часы\?</string>
|
<string name="controlcenter_power_off_confirm_description">Вы уверены, что хотите выключить браслет/часы\?</string>
|
||||||
<string name="add_test_device">Добавить тестовые часы/браслет</string>
|
<string name="add_test_device">Добавить тестовые часы/браслет</string>
|
||||||
<string name="device_card_activity_card_title_summary"></string>
|
<string name="device_card_activity_card_title_summary"/>
|
||||||
<string name="prefs_activity_in_device_card_title">Показать/Отключить (шаги, расстояние, сон)</string>
|
<string name="prefs_activity_in_device_card_title">Показать/Отключить (шаги, расстояние, сон)</string>
|
||||||
<string name="prefs_activity_in_device_card_sleep_title">Сон</string>
|
<string name="prefs_activity_in_device_card_sleep_title">Сон</string>
|
||||||
<string name="prefs_activity_in_device_card_sleep_title_summary">Показывать продолжительность сна</string>
|
<string name="prefs_activity_in_device_card_sleep_title_summary">Показывать продолжительность сна</string>
|
||||||
@ -1352,4 +1352,87 @@
|
|||||||
<string name="sony_automatic_power_off_3_hour">3 часа</string>
|
<string name="sony_automatic_power_off_3_hour">3 часа</string>
|
||||||
<string name="pref_button_action_disabled">Отключен</string>
|
<string name="pref_button_action_disabled">Отключен</string>
|
||||||
<string name="sony_equalizer">Эквалайзер</string>
|
<string name="sony_equalizer">Эквалайзер</string>
|
||||||
|
<string name="reminder_time_every_month">%1$s, каждый месяц</string>
|
||||||
|
<string name="reminder_time_every_week">%1$s, каждую неделю</string>
|
||||||
|
<string name="prefs_activity_in_device_card_title_summary">Показывать шаги, пройденное расстояние и продолжительность сна на карточке устройства</string>
|
||||||
|
<string name="title_activity_set_reminders">Настроить напоминания</string>
|
||||||
|
<string name="pref_header_other">Другое</string>
|
||||||
|
<string name="controlcenter_start_configure_reminders">Настроить напоминания</string>
|
||||||
|
<string name="title_activity_reminder_details">Настройки напоминания</string>
|
||||||
|
<string name="prefs_activity_in_device_card_distance_title_summary">Расстояние вычисляется по количеству шагов и ширине шага (настраивается в разделе Настройки - About you)</string>
|
||||||
|
<string name="pref_title_notification_use_as">Используйте список приложения для того чтобы...</string>
|
||||||
|
<string name="reminder_repeat">Повтор</string>
|
||||||
|
<string name="reminder_date">Дата</string>
|
||||||
|
<string name="reminder_time">Время</string>
|
||||||
|
<string name="reminder_message">Сообщение</string>
|
||||||
|
<string name="reminder_time_every_day">%1$s, ежедневно</string>
|
||||||
|
<string name="reminder_time_once">%1$s, один раз</string>
|
||||||
|
<string name="reminder_time_every_year">%1$s, каждый год</string>
|
||||||
|
<string name="reminder_once">Один раз</string>
|
||||||
|
<string name="reminder_every_day">Каждый день</string>
|
||||||
|
<string name="reminder_every_week">Каждую неделю</string>
|
||||||
|
<string name="reminder_every_month">Каждый месяц</string>
|
||||||
|
<string name="reminder_every_year">Каждый год</string>
|
||||||
|
<string name="reminder_delete_confirm_title">Удалить напоминание</string>
|
||||||
|
<string name="reminder_delete_confirm_description">Вы уверены что хотите удалить это напоминание\?</string>
|
||||||
|
<string name="reminder_no_free_slots_title">Нет свободных слотов</string>
|
||||||
|
<string name="reminder_no_free_slots_description">Нет свободных слотов для напоминаний (всего слотов: %1$s)</string>
|
||||||
|
<string name="pref_header_system">Система</string>
|
||||||
|
<string name="sony_surround_mode_concert_hall">Концертный зал</string>
|
||||||
|
<string name="nothing_prefs_audiomode_title">Аудиорежим</string>
|
||||||
|
<string name="sony_automatic_power_off_30_min">30 минут</string>
|
||||||
|
<string name="devicetype_galaxybuds_live">Galaxy Buds Live</string>
|
||||||
|
<string name="sony_speak_to_chat_timeout_standard">Стандартный (30с)</string>
|
||||||
|
<string name="sony_speak_to_chat_timeout_short">Короткий (15с)</string>
|
||||||
|
<string name="sony_speak_to_chat_timeout_off">Выкл</string>
|
||||||
|
<string name="distance_format_kilometers">###.#км</string>
|
||||||
|
<string name="distance_format_feet">###фт</string>
|
||||||
|
<string name="distance_format_meters">###м</string>
|
||||||
|
<string name="sony_surround_mode_off">Выкл</string>
|
||||||
|
<string name="averageCadence">Средний каденс</string>
|
||||||
|
<string name="sony_speak_to_chat_timeout_long">Долгий (1м)</string>
|
||||||
|
<string name="sony_ambient_sound">Режим</string>
|
||||||
|
<string name="sony_equalizer_band_6300">6,3к</string>
|
||||||
|
<string name="sony_equalizer_preset_bright">Яркий</string>
|
||||||
|
<string name="sony_sound_position_off">Выкл</string>
|
||||||
|
<string name="sony_anc_optimizer_status_analyzing">Анализ…</string>
|
||||||
|
<string name="sony_surround_mode_club">Клуб</string>
|
||||||
|
<string name="sony_surround_mode_arena">Арена</string>
|
||||||
|
<string name="sony_ambient_sound_noise_cancelling">Шумоподавление</string>
|
||||||
|
<string name="devicetype_galaxybuds">Galaxy Buds</string>
|
||||||
|
<string name="prefs_autoheartrate_interval">Частота измерений</string>
|
||||||
|
<string name="prefs_notifications_enable">Включить уведомления</string>
|
||||||
|
<string name="sony_ambient_sound_off">Выкл</string>
|
||||||
|
<string name="prefs_vibration_enable">Включить вибрацию</string>
|
||||||
|
<string name="pref_header_sony_device_info">Информация об устройстве</string>
|
||||||
|
<string name="audio_codec">Аудиокодек</string>
|
||||||
|
<string name="watchface_setting_title_power_saving">Энергосбережение</string>
|
||||||
|
<string name="watchface_widget_type_calories">Калории</string>
|
||||||
|
<string name="watchface_widget_type_battery">Батарея</string>
|
||||||
|
<string name="minSpeed">Минимум</string>
|
||||||
|
<string name="unknown">Неизвестно</string>
|
||||||
|
<string name="sony_button_mode_off">Выкл</string>
|
||||||
|
<string name="devicetype_amazfit_pop">Amazfit Pop</string>
|
||||||
|
<string name="devicetype_sony_wh_1000xm4">Sony WH-1000XM4</string>
|
||||||
|
<string name="devicetype_amazfit_pop_pro">Amazfit Pop Pro</string>
|
||||||
|
<string name="devicetype_sony_wf_sp800n">Sony WF-SP800N</string>
|
||||||
|
<string name="devicetype_domyos_t540">Domyos T540</string>
|
||||||
|
<string name="spm">шагов/мин</string>
|
||||||
|
<string name="sony_equalizer_band_1000">1к</string>
|
||||||
|
<string name="devicetype_sony_wh_1000xm3">Sony WH-1000XM3</string>
|
||||||
|
<string name="prefs_dolby_mode">Режим Dolby</string>
|
||||||
|
<string name="prefs_sleep_time">Время сна</string>
|
||||||
|
<string name="sony_equalizer_preset_off">Выкл</string>
|
||||||
|
<string name="sony_automatic_power_off_5_min">5 минут</string>
|
||||||
|
<string name="devicetype_bose_qc35">Bose QC35</string>
|
||||||
|
<string name="devicetype_vesc">VESC</string>
|
||||||
|
<string name="about_hash">Коммит %s</string>
|
||||||
|
<string name="sony_equalizer_clear_bass">Чистый бас</string>
|
||||||
|
<string name="sony_equalizer_band_16000">16к</string>
|
||||||
|
<string name="sony_equalizer_band_2500">2,5к</string>
|
||||||
|
<string name="sony_equalizer_band_400">400</string>
|
||||||
|
<string name="menuitem_menu">Меню</string>
|
||||||
|
<string name="watchface_dialog_widget_width">Ширина:</string>
|
||||||
|
<string name="prefs_game_mode">Игровой режим</string>
|
||||||
|
<string name="prefs_equalizer">Эквалайзер</string>
|
||||||
</resources>
|
</resources>
|
@ -1596,4 +1596,17 @@
|
|||||||
<string name="sony_anc_optimizer_status_finished">Bitiriliyor…</string>
|
<string name="sony_anc_optimizer_status_finished">Bitiriliyor…</string>
|
||||||
<string name="devicetype_amazfit_pop_pro">Amazfit Pop Pro</string>
|
<string name="devicetype_amazfit_pop_pro">Amazfit Pop Pro</string>
|
||||||
<string name="devicetype_amazfit_pop">Amazfit Pop</string>
|
<string name="devicetype_amazfit_pop">Amazfit Pop</string>
|
||||||
|
<string name="menuitem_nothing">Hiçbir Şey</string>
|
||||||
|
<string name="pref_title_opentracks_packagename">OpenTracks paket adı</string>
|
||||||
|
<string name="pref_summary_opentracks_packagename">Harici fitness uygulamasında GPS izleme kaydını başlatmak/durdurmak için kullanılır.</string>
|
||||||
|
<string name="pref_device_action_fitness_app_control_stop">Fitness Uygulaması İzlemesini Durdur</string>
|
||||||
|
<string name="pref_device_action_fitness_app_control_start">Fitness Uygulaması İzlemesini Başlat</string>
|
||||||
|
<string name="pref_title_notifications_generic_settings">Android bildirim ayarları</string>
|
||||||
|
<string name="autoExport_lastTime_label">Son Otomatik Dışa Aktarma: %1$s</string>
|
||||||
|
<string name="activity_db_management_autoexport_enabled_no">Otomatik dışa aktarma etkin değil.</string>
|
||||||
|
<string name="activity_db_management_autoexport_scheduled_yes">Otomatik dışa aktarma (başlangıçta) %1$s için zamanlandı</string>
|
||||||
|
<string name="activity_db_management_autoexport_scheduled_no">Otomatik dışa aktarma zamanlanmadı.</string>
|
||||||
|
<string name="activity_db_management_autoexport_enabled_yes">Otomatik dışa aktarma etkin.</string>
|
||||||
|
<string name="activity_db_management_autoexport_location">Konum anlaşılamadı. Bu, muhtemelen daha yeni bir Android izin sistemi sorunudur. Büyük olasılıkla, otomatik dışa aktarma şu anda çalışmıyor.</string>
|
||||||
|
<string name="watchface_dialog_pre_setting_position">konumu %s olarak ön ayarlama</string>
|
||||||
</resources>
|
</resources>
|
@ -1587,4 +1587,17 @@
|
|||||||
<string name="sony_anc_optimizer_status_finished">Завершення…</string>
|
<string name="sony_anc_optimizer_status_finished">Завершення…</string>
|
||||||
<string name="devicetype_amazfit_pop">Amazfit Pop</string>
|
<string name="devicetype_amazfit_pop">Amazfit Pop</string>
|
||||||
<string name="devicetype_amazfit_pop_pro">Amazfit Pop Pro</string>
|
<string name="devicetype_amazfit_pop_pro">Amazfit Pop Pro</string>
|
||||||
|
<string name="menuitem_nothing">Порожньо</string>
|
||||||
|
<string name="pref_title_opentracks_packagename">Назва пакунка OpenTracks</string>
|
||||||
|
<string name="pref_summary_opentracks_packagename">Використовується для запуску/зупинки запису треків GPS у зовнішньому фітнес-застосунку.</string>
|
||||||
|
<string name="pref_device_action_fitness_app_control_start">Початок відстеження застосунку для фітнесу</string>
|
||||||
|
<string name="pref_device_action_fitness_app_control_stop">Зупинка відстеження застосунку для фітнесу</string>
|
||||||
|
<string name="pref_title_notifications_generic_settings">Налаштування сповіщень Android</string>
|
||||||
|
<string name="activity_db_management_autoexport_scheduled_yes">Автоекспорт (початково) було заплановано на %1$s</string>
|
||||||
|
<string name="activity_db_management_autoexport_enabled_yes">Автоекспорт увімкнено.</string>
|
||||||
|
<string name="activity_db_management_autoexport_enabled_no">Автоекспорт не ввімкнено.</string>
|
||||||
|
<string name="activity_db_management_autoexport_scheduled_no">Автоекспорт не заплановано.</string>
|
||||||
|
<string name="autoExport_lastTime_label">Останній автоекспорт: %1$s</string>
|
||||||
|
<string name="activity_db_management_autoexport_location">Не вдалося встановити місцеперебування. Ймовірно, проблема з новішою системою дозволів Android. Швидше за все, автоекспорт зараз не працює.</string>
|
||||||
|
<string name="watchface_dialog_pre_setting_position">попереднє встановлення розташування на %s</string>
|
||||||
</resources>
|
</resources>
|
@ -1585,4 +1585,17 @@
|
|||||||
<string name="sony_anc_optimizer_status_starting">正在开始…</string>
|
<string name="sony_anc_optimizer_status_starting">正在开始…</string>
|
||||||
<string name="devicetype_amazfit_pop_pro">华米 Pop Pro</string>
|
<string name="devicetype_amazfit_pop_pro">华米 Pop Pro</string>
|
||||||
<string name="devicetype_amazfit_pop">华米 Pop</string>
|
<string name="devicetype_amazfit_pop">华米 Pop</string>
|
||||||
|
<string name="menuitem_nothing">无</string>
|
||||||
|
<string name="pref_title_opentracks_packagename">OpenTracks 包名</string>
|
||||||
|
<string name="pref_summary_opentracks_packagename">用于启动/停止外部健身应用的 GPS 追踪记录。</string>
|
||||||
|
<string name="pref_device_action_fitness_app_control_start">Fitness 应用追踪开始</string>
|
||||||
|
<string name="pref_device_action_fitness_app_control_stop">Fitness 应用追踪结束</string>
|
||||||
|
<string name="pref_title_notifications_generic_settings">Android 通知设置</string>
|
||||||
|
<string name="activity_db_management_autoexport_scheduled_yes">为 %1$s 自动导出(原始的)已经启用计划</string>
|
||||||
|
<string name="activity_db_management_autoexport_scheduled_no">尚未计划自动导出。</string>
|
||||||
|
<string name="activity_db_management_autoexport_location">位置无法理解。 可能是较新的 Android 权限系统的问题。 最有可能的是,自动导出现在不起作用。</string>
|
||||||
|
<string name="autoExport_lastTime_label">最后一次自动导出:%1$s</string>
|
||||||
|
<string name="activity_db_management_autoexport_enabled_no">自动导出未开启。</string>
|
||||||
|
<string name="activity_db_management_autoexport_enabled_yes">自动导出已开启。</string>
|
||||||
|
<string name="watchface_dialog_pre_setting_position">预设位置为 %s</string>
|
||||||
</resources>
|
</resources>
|
@ -142,7 +142,7 @@
|
|||||||
<string name="pref_title_support_voip_calls">啟用 VoIP 應用程式電話通知</string>
|
<string name="pref_title_support_voip_calls">啟用 VoIP 應用程式電話通知</string>
|
||||||
<string name="pref_title_notifications_timeout">最低通知間隔時間</string>
|
<string name="pref_title_notifications_timeout">最低通知間隔時間</string>
|
||||||
<string name="pref_title_whenscreenon">在螢幕開啟時仍要通知</string>
|
<string name="pref_title_whenscreenon">在螢幕開啟時仍要通知</string>
|
||||||
<string name="pref_summary_notification_filter">在此模式下將停止不必要的通知</string>
|
<string name="pref_summary_notification_filter">當手機啟用請勿打擾時阻止所有通知</string>
|
||||||
<string name="pref_blacklist">應用程式黑名單</string>
|
<string name="pref_blacklist">應用程式黑名單</string>
|
||||||
<string name="pref_header_development">開發人員選項</string>
|
<string name="pref_header_development">開發人員選項</string>
|
||||||
<string name="pref_title_expose_hr">第三方即時心率資料存取</string>
|
<string name="pref_title_expose_hr">第三方即時心率資料存取</string>
|
||||||
@ -296,8 +296,8 @@
|
|||||||
<string name="devicetype_miband4">小米手環 4</string>
|
<string name="devicetype_miband4">小米手環 4</string>
|
||||||
<string name="menuitem_status">狀態</string>
|
<string name="menuitem_status">狀態</string>
|
||||||
<string name="menuitem_notifications">通知</string>
|
<string name="menuitem_notifications">通知</string>
|
||||||
<string name="menuitem_activity">活動</string>
|
<string name="menuitem_activity">鍛煉歷史</string>
|
||||||
<string name="menuitem_timer">計時器</string>
|
<string name="menuitem_timer">倒數</string>
|
||||||
<string name="menuitem_more">更多</string>
|
<string name="menuitem_more">更多</string>
|
||||||
<string name="menuitem_nfc">NFC</string>
|
<string name="menuitem_nfc">NFC</string>
|
||||||
<string name="widget_steps_label">步數:%1$02d</string>
|
<string name="widget_steps_label">步數:%1$02d</string>
|
||||||
@ -334,9 +334,14 @@
|
|||||||
<string name="mi2_prefs_inactivity_warnings_summary">手環將在您一段時間未活動時震動</string>
|
<string name="mi2_prefs_inactivity_warnings_summary">手環將在您一段時間未活動時震動</string>
|
||||||
<string name="mi2_prefs_inactivity_warnings_threshold">未活動閾值(分鐘)</string>
|
<string name="mi2_prefs_inactivity_warnings_threshold">未活動閾值(分鐘)</string>
|
||||||
<string name="mi2_prefs_inactivity_warnings_dnd_summary">在時間內停用久坐提醒</string>
|
<string name="mi2_prefs_inactivity_warnings_dnd_summary">在時間內停用久坐提醒</string>
|
||||||
<string name="activity_db_management_import_export_explanation">資料庫的存取將使用下列在裝置上的路徑。
|
<string name="activity_db_management_import_export_explanation">匯出/匯入動作將使用這些(見下方)在裝置上的路徑。此資料夾可供其他 Android 應用程式及您的電腦存取。請注意,如果您移除 Gadgetbridge,此目錄和所有內含檔案都會被刪除。這些資料包含:
|
||||||
\n此路徑可供其他 Android 應用程式及您的電腦存取。
|
\n Export_preference - 全域設定
|
||||||
\n您可以在那裏找到已匯出的資料庫(或放入要匯入的資料庫):</string>
|
\n Export_preference_MAC - 裝置額外設定
|
||||||
|
\n Gadgetbridge - 裝置及活動的資料庫
|
||||||
|
\n Gadgetbridge_date - 在某個日期匯出的資料庫
|
||||||
|
\n *.gpx - GPS 紀錄
|
||||||
|
\n *.log - 記錄檔
|
||||||
|
\n您可以在那裏找到已匯出的檔案(或放入要匯入的檔案):</string>
|
||||||
<string name="activity_DB_ExportButton">匯出資料</string>
|
<string name="activity_DB_ExportButton">匯出資料</string>
|
||||||
<string name="activity_DB_import_button">匯入資料</string>
|
<string name="activity_DB_import_button">匯入資料</string>
|
||||||
<string name="activity_db_management_exportimport_label">匯出和匯入</string>
|
<string name="activity_db_management_exportimport_label">匯出和匯入</string>
|
||||||
@ -485,7 +490,7 @@
|
|||||||
<string name="watch9_time_hours">小時:</string>
|
<string name="watch9_time_hours">小時:</string>
|
||||||
<string name="watch9_time_minutes">分鐘:</string>
|
<string name="watch9_time_minutes">分鐘:</string>
|
||||||
<string name="menuitem_compass">羅盤</string>
|
<string name="menuitem_compass">羅盤</string>
|
||||||
<string name="notification_channel_name">Gadgetbridge 通知</string>
|
<string name="notification_channel_name">一般</string>
|
||||||
<string name="devicetype_roidmi3">睿米3</string>
|
<string name="devicetype_roidmi3">睿米3</string>
|
||||||
<string name="devicetype_roidmi">睿米</string>
|
<string name="devicetype_roidmi">睿米</string>
|
||||||
<string name="devicetype_watch9">Watch 9</string>
|
<string name="devicetype_watch9">Watch 9</string>
|
||||||
@ -578,7 +583,7 @@
|
|||||||
<string name="about_additional_device_support">額外裝置支援</string>
|
<string name="about_additional_device_support">額外裝置支援</string>
|
||||||
<string name="about_contributors">貢獻者</string>
|
<string name="about_contributors">貢獻者</string>
|
||||||
<string name="about_core_team_title">核心團隊(按第一次程式碼貢獻順序排列)</string>
|
<string name="about_core_team_title">核心團隊(按第一次程式碼貢獻順序排列)</string>
|
||||||
<string name="about_description">一款免費且離線的替代品,用來取代您的裝置廠商提供的閉源 Android 應用程式。</string>
|
<string name="about_description">用來取代廠商提供的閉源 Android 小裝置應用程式的離線且版權自由的替代品。</string>
|
||||||
<string name="about_activity_title">關於 Gadgetbridge</string>
|
<string name="about_activity_title">關於 Gadgetbridge</string>
|
||||||
<string name="about_title">關於</string>
|
<string name="about_title">關於</string>
|
||||||
<string name="activity_summaries">運動活動</string>
|
<string name="activity_summaries">運動活動</string>
|
||||||
@ -648,4 +653,39 @@
|
|||||||
<string name="battery_detail_activity_title">電池資訊</string>
|
<string name="battery_detail_activity_title">電池資訊</string>
|
||||||
<string name="controlcenter_set_alias">設定別名</string>
|
<string name="controlcenter_set_alias">設定別名</string>
|
||||||
<string name="find_lost_device_message">尋找 %1$s\?</string>
|
<string name="find_lost_device_message">尋找 %1$s\?</string>
|
||||||
|
<string name="controlcenter_power_off_confirm_title">關機</string>
|
||||||
|
<string name="controlcenter_power_off_confirm_description">您確定要關閉裝置電源嗎?</string>
|
||||||
|
<string name="check_all_applications">勾選所有應用程式</string>
|
||||||
|
<string name="uncheck_all_applications">取消勾選所有應用程式</string>
|
||||||
|
<string name="pref_title_notification_use_as_deny">拒絕來自所選應用程式的通知</string>
|
||||||
|
<string name="pref_header_other">其他</string>
|
||||||
|
<string name="pref_header_system">系統</string>
|
||||||
|
<string name="pref_title_message_privacy_mode">訊息隱私模式</string>
|
||||||
|
<string name="pref_message_privacy_mode_off">顯示內容</string>
|
||||||
|
<string name="pref_message_privacy_mode_complete">隱藏內容</string>
|
||||||
|
<string name="controlcenter_power_off">關機</string>
|
||||||
|
<string name="mi2_prefs_do_not_disturb_lift_wrist">在請勿打擾期間啟用抬腕顯示</string>
|
||||||
|
<string name="prefs_activity_in_device_card_title_summary">在裝置卡上顯示目前步數、距離或睡眠</string>
|
||||||
|
<string name="title_activity_notification_management">通知設定</string>
|
||||||
|
<string name="pref_title_notification_use_as">使用應用程式清單來...</string>
|
||||||
|
<string name="pref_applications_settings">應用程式清單</string>
|
||||||
|
<string name="pref_title_notification_use_as_allow">允許來自所選應用程式的通知</string>
|
||||||
|
<string name="pref_header_notification_application_settings">個別應用程式設定</string>
|
||||||
|
<string name="discovery_trying_to_connect_to">正在嘗試連線到: %1$s</string>
|
||||||
|
<string name="activity_prefs_discovery_pairing">探索和配對選項</string>
|
||||||
|
<string name="pref_summary_location_keep_uptodate">嘗試在執行時獲取目前位置,使用儲存的位置作為後備</string>
|
||||||
|
<string name="pref_theme_black_background">在深色主題中使用黑色背景</string>
|
||||||
|
<string name="pref_header_auto_fetch">自動提取</string>
|
||||||
|
<string name="device_card_activity_card_title_summary">選擇在裝置卡上要顯示哪些活動詳細資訊</string>
|
||||||
|
<string name="device_card_activity_card_title">裝置卡上的活動狀態</string>
|
||||||
|
<string name="prefs_activity_in_device_card_title">在裝置卡上顯示活動資訊</string>
|
||||||
|
<string name="prefs_activity_in_device_card_sleep_title">睡眠</string>
|
||||||
|
<string name="prefs_activity_in_device_card_sleep_title_summary">顯示睡眠時間</string>
|
||||||
|
<string name="prefs_activity_in_device_card_distance_title_summary">距離是根據步數和步長計算出的(可以在設定 - 關於你中調整)</string>
|
||||||
|
<string name="prefs_activity_in_device_card_steps_title_summary">顯示總步數</string>
|
||||||
|
<string name="discover_unsupported_devices_description">啟用此選項將在掃描時顯示所有發現的藍芽裝置。短按會將設備名稱和 mac 位址複製到剪貼簿。長按將開啟「新增測試裝置」對話框。</string>
|
||||||
|
<string name="discover_unsupported_devices">探索不支援的裝置</string>
|
||||||
|
<string name="pref_theme_system">根據系統</string>
|
||||||
|
<string name="discovery_bluetooth_scan">藍芽掃描:</string>
|
||||||
|
<string name="discovery_bluetooth_le_scan">低功耗藍芽掃描:</string>
|
||||||
</resources>
|
</resources>
|
@ -1654,6 +1654,12 @@
|
|||||||
<item>@string/pref_media_forward</item>
|
<item>@string/pref_media_forward</item>
|
||||||
<item>@string/pref_media_rewind</item>
|
<item>@string/pref_media_rewind</item>
|
||||||
<item>@string/pref_device_action_broadcast</item>
|
<item>@string/pref_device_action_broadcast</item>
|
||||||
|
<item>@string/pref_device_action_fitness_app_control_start</item>
|
||||||
|
<!--
|
||||||
|
Enable when OpenTracks allows to be stopped via intent
|
||||||
|
https://github.com/OpenTracksApp/OpenTracks/issues/1103
|
||||||
|
<item>@string/pref_device_action_fitness_app_control_stop</item>
|
||||||
|
-->
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string-array name="button_action_values">
|
<string-array name="button_action_values">
|
||||||
@ -1668,6 +1674,12 @@
|
|||||||
<item>@string/pref_media_forward_value</item>
|
<item>@string/pref_media_forward_value</item>
|
||||||
<item>@string/pref_media_rewind_value</item>
|
<item>@string/pref_media_rewind_value</item>
|
||||||
<item>@string/pref_device_action_broadcast_value</item>
|
<item>@string/pref_device_action_broadcast_value</item>
|
||||||
|
<item>@string/pref_device_action_fitness_app_control_start_value</item>
|
||||||
|
<!--
|
||||||
|
Enable when OpenTracks allows to be stopped via intent
|
||||||
|
https://github.com/OpenTracksApp/OpenTracks/issues/1103
|
||||||
|
<item>@string/pref_device_action_fitness_app_control_stop_value</item>
|
||||||
|
-->
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string-array name="device_action_options">
|
<string-array name="device_action_options">
|
||||||
@ -1676,6 +1688,12 @@
|
|||||||
<item>@string/pref_media_pause</item>
|
<item>@string/pref_media_pause</item>
|
||||||
<item>@string/pref_media_playpause</item>
|
<item>@string/pref_media_playpause</item>
|
||||||
<item>@string/pref_device_action_broadcast</item>
|
<item>@string/pref_device_action_broadcast</item>
|
||||||
|
<item>@string/pref_device_action_fitness_app_control_start</item>
|
||||||
|
<!--
|
||||||
|
Enable when OpenTracks allows to be stopped via intent
|
||||||
|
https://github.com/OpenTracksApp/OpenTracks/issues/1103
|
||||||
|
<item>@string/pref_device_action_fitness_app_control_stop</item>
|
||||||
|
-->
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string-array name="device_action_values">
|
<string-array name="device_action_values">
|
||||||
@ -1684,6 +1702,12 @@
|
|||||||
<item>@string/pref_media_pause_value</item>
|
<item>@string/pref_media_pause_value</item>
|
||||||
<item>@string/pref_media_playpause_value</item>
|
<item>@string/pref_media_playpause_value</item>
|
||||||
<item>@string/pref_device_action_broadcast_value</item>
|
<item>@string/pref_device_action_broadcast_value</item>
|
||||||
|
<item>@string/pref_device_action_fitness_app_control_start_value</item>
|
||||||
|
<!--
|
||||||
|
Enable when OpenTracks allows to be stopped via intent
|
||||||
|
https://github.com/OpenTracksApp/OpenTracks/issues/1103
|
||||||
|
<item>@string/pref_device_action_fitness_app_control_stop_value</item>
|
||||||
|
-->
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string-array name="pref_hybridhr_buttonfunctions">
|
<string-array name="pref_hybridhr_buttonfunctions">
|
||||||
@ -2085,5 +2109,13 @@
|
|||||||
<item>mode_ask</item>
|
<item>mode_ask</item>
|
||||||
<item>mode_auto</item>
|
<item>mode_auto</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="fitness_tracking_apps_package_names">
|
||||||
|
<item>de.dennisguse.opentracks</item>
|
||||||
|
<item>de.dennisguse.opentracks.playStore</item>
|
||||||
|
<item>de.dennisguse.opentracks.debug</item>
|
||||||
|
<item>de.dennisguse.opentracks.nightly</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
|
@ -142,6 +142,7 @@
|
|||||||
<string name="pref_title_notifications_pebblemsg">Pebble Messages</string>
|
<string name="pref_title_notifications_pebblemsg">Pebble Messages</string>
|
||||||
<string name="pref_summary_notifications_pebblemsg">Support for apps that send notifications to the Pebble via PebbleKit.</string>
|
<string name="pref_summary_notifications_pebblemsg">Support for apps that send notifications to the Pebble via PebbleKit.</string>
|
||||||
<string name="pref_title_notifications_generic">Generic notification support</string>
|
<string name="pref_title_notifications_generic">Generic notification support</string>
|
||||||
|
<string name="pref_title_notifications_generic_settings">Android notification settings</string>
|
||||||
<string name="pref_title_whenscreenon">…also when screen is on</string>
|
<string name="pref_title_whenscreenon">…also when screen is on</string>
|
||||||
<string name="pref_title_notification_filter">Do Not Disturb</string>
|
<string name="pref_title_notification_filter">Do Not Disturb</string>
|
||||||
<string name="pref_summary_notification_filter">Block all notifications when Do Not Disturb is enabled on the phone</string>
|
<string name="pref_summary_notification_filter">Block all notifications when Do Not Disturb is enabled on the phone</string>
|
||||||
@ -759,7 +760,13 @@
|
|||||||
<string name="dbmanagementactivity_old_activity_db_deletion_failed">Old Activity database deletion failed.</string>
|
<string name="dbmanagementactivity_old_activity_db_deletion_failed">Old Activity database deletion failed.</string>
|
||||||
<string name="dbmanagementactivity_overwrite">Overwrite</string>
|
<string name="dbmanagementactivity_overwrite">Overwrite</string>
|
||||||
<string name="activity_db_management_autoexport_explanation">Database autoexport location has been set to:</string>
|
<string name="activity_db_management_autoexport_explanation">Database autoexport location has been set to:</string>
|
||||||
|
<string name="autoExport_lastTime_label">Last AutoExport: %1$s</string>
|
||||||
|
<string name="activity_db_management_autoexport_enabled_yes">AutoExport is enabled.</string>
|
||||||
|
<string name="activity_db_management_autoexport_enabled_no">AutoExport is not enabled.</string>
|
||||||
|
<string name="activity_db_management_autoexport_scheduled_yes">AutoExport has (originally) been scheduled for %1$s</string>
|
||||||
|
<string name="activity_db_management_autoexport_scheduled_no">AutoExport has not been not scheduled.</string>
|
||||||
<string name="activity_db_management_autoexport_label">AutoExport</string>
|
<string name="activity_db_management_autoexport_label">AutoExport</string>
|
||||||
|
<string name="activity_db_management_autoexport_location">Location could not be understood. Likely an issue of newer Android permission system. Most likely, autoexport is not working now.</string>
|
||||||
<string name="activity_DB_ExportButton">Export Data</string>
|
<string name="activity_DB_ExportButton">Export Data</string>
|
||||||
<string name="activity_DB_import_button">Import Data</string>
|
<string name="activity_DB_import_button">Import Data</string>
|
||||||
<string name="activity_DB_test_export_button">Run AutoExport Now</string>
|
<string name="activity_DB_test_export_button">Run AutoExport Now</string>
|
||||||
@ -1495,6 +1502,8 @@
|
|||||||
<string name="pref_media_forward">Skip forward</string>
|
<string name="pref_media_forward">Skip forward</string>
|
||||||
<string name="pref_media_rewind">Skip back</string>
|
<string name="pref_media_rewind">Skip back</string>
|
||||||
<string name="pref_device_action_broadcast">Send Broadcast</string>
|
<string name="pref_device_action_broadcast">Send Broadcast</string>
|
||||||
|
<string name="pref_device_action_fitness_app_control_start">Fitness App Tracking Start</string>
|
||||||
|
<string name="pref_device_action_fitness_app_control_stop">Fitness App Tracking Stop</string>
|
||||||
<!-- Translators: the ### indicate number of digits, keep intact -->
|
<!-- Translators: the ### indicate number of digits, keep intact -->
|
||||||
<string name="distance_format_meters">###m</string>
|
<string name="distance_format_meters">###m</string>
|
||||||
<!-- Translators: the ### indicate number of digits, keep intact -->
|
<!-- Translators: the ### indicate number of digits, keep intact -->
|
||||||
@ -1516,4 +1525,8 @@
|
|||||||
<string name="menuitem_menu">Menu</string>
|
<string name="menuitem_menu">Menu</string>
|
||||||
<string name="fossil_hr_button_config_info">Some buttons cannot be configured because their functions are hard-coded in the watch firmware.\n\nWarning: long-pressing the upper button when a watchface from the official Fossil app is installed will also toggle between showing/hiding widgets.</string>
|
<string name="fossil_hr_button_config_info">Some buttons cannot be configured because their functions are hard-coded in the watch firmware.\n\nWarning: long-pressing the upper button when a watchface from the official Fossil app is installed will also toggle between showing/hiding widgets.</string>
|
||||||
<string name="watchface_dialog_widget_width">Width:</string>
|
<string name="watchface_dialog_widget_width">Width:</string>
|
||||||
|
<string name="pref_title_opentracks_packagename">OpenTracks package name</string>
|
||||||
|
<string name="pref_summary_opentracks_packagename">Used for starting/stopping GPS track recording in external fitness app.</string>
|
||||||
|
<string name="watchface_dialog_pre_setting_position">pre-setting position to %s</string>
|
||||||
|
<string name="watchface_setting_light_up_on_notification">Light up on new notification</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -106,6 +106,8 @@
|
|||||||
<item name="pref_media_forward_value" translatable="false" type="string">FORWARD</item>
|
<item name="pref_media_forward_value" translatable="false" type="string">FORWARD</item>
|
||||||
<item name="pref_media_rewind_value" translatable="false" type="string">REWIND</item>
|
<item name="pref_media_rewind_value" translatable="false" type="string">REWIND</item>
|
||||||
<item name="pref_device_action_broadcast_value" translatable="false" type="string">BROADCAST</item>
|
<item name="pref_device_action_broadcast_value" translatable="false" type="string">BROADCAST</item>
|
||||||
|
<item name="pref_device_action_fitness_app_control_start_value" translatable="false" type="string">FITNESS_CONTROL_START</item>
|
||||||
|
<item name="pref_device_action_fitness_app_control_stop_value" translatable="false" type="string">FITNESS_CONTROL_STOP</item>
|
||||||
<item name="pref_title_touch_voice_assistant" type="string">Voice Assistant</item>
|
<item name="pref_title_touch_voice_assistant" type="string">Voice Assistant</item>
|
||||||
<item name="pref_title_touch_anc" type="string">Active Noise Cancelling</item>
|
<item name="pref_title_touch_anc" type="string">Active Noise Cancelling</item>
|
||||||
<item name="pref_title_touch_quick_ambient" type="string">Quick Ambient Sound</item>
|
<item name="pref_title_touch_quick_ambient" type="string">Quick Ambient Sound</item>
|
||||||
|
@ -1,5 +1,26 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<changelog>
|
<changelog>
|
||||||
|
<release version="0.66.0" versioncode="210">
|
||||||
|
<change>Add basic support for Casio GBD-H1000</change>
|
||||||
|
<change>Add support for Hama Fit Track 1900 - via FitPro device support</change>
|
||||||
|
<change>Add OpenTracksController for interactions with OpenTracks</change>
|
||||||
|
<change>Fossil Hybrid HR: Start/stop track in OpenTracks from GPS workout on watch</change>
|
||||||
|
<change>Fossil Hybrid HR: Try guessing new widget position</change>
|
||||||
|
<change>Fossil Hybrid HR: Allow assigning no function to a button</change>
|
||||||
|
<change>Add Huami button/device action to control fitness tracking via OpenTracksController</change>
|
||||||
|
<change>Mi Band 6: Sync alarms set on the watch like on Amazfit Bip U and others</change>
|
||||||
|
<change>Bangle.js: Handle battery charging status and fix battery chart.</change>
|
||||||
|
<change>Bangle.js: Prevent exception in case UART RX line is empty</change>
|
||||||
|
<change>Bangle.js: Add repetitions in alarm JSON</change>
|
||||||
|
<change>WaspOS: Fix battery chart.</change>
|
||||||
|
<change>WaspOS: Add condition code to weather JSON</change>
|
||||||
|
<change>XWatch: Add notifications and calls support</change>
|
||||||
|
<change>UM-25: Make cumulative values resettable</change>
|
||||||
|
<change>VESC: Fixed crash when loading a saved value</change>
|
||||||
|
<change>Allow to open Android notification settings from Notification settings</change>
|
||||||
|
<change>AutoExporter changes for better operation and troubleshooting</change>
|
||||||
|
<change>Change Nightly icons background color</change>
|
||||||
|
</release>
|
||||||
<release version="0.65.0" versioncode="209">
|
<release version="0.65.0" versioncode="209">
|
||||||
<change>Amazfit Pop/Pro: Initial Support (probably the same as Bip U but has a different firmware)</change>
|
<change>Amazfit Pop/Pro: Initial Support (probably the same as Bip U but has a different firmware)</change>
|
||||||
<change>Sony WH-1000XM4: Initial Support</change>
|
<change>Sony WH-1000XM4: Initial Support</change>
|
||||||
|
@ -41,11 +41,12 @@
|
|||||||
android:key="button_3_function_short"
|
android:key="button_3_function_short"
|
||||||
android:summary="%s"
|
android:summary="%s"
|
||||||
android:title="@string/pref_title_lower_button_function_short" />
|
android:title="@string/pref_title_lower_button_function_short" />
|
||||||
<Preference
|
<ListPreference
|
||||||
android:selectable="false"
|
android:defaultValue="musicApp"
|
||||||
android:persistent="false"
|
android:entries="@array/pref_hybridhr_buttonfunctions"
|
||||||
|
android:entryValues="@array/pref_hybridhr_buttonfunctions_values"
|
||||||
android:key="button_3_function_long"
|
android:key="button_3_function_long"
|
||||||
android:summary="@string/menuitem_notifications"
|
android:summary="%s"
|
||||||
android:title="@string/pref_title_lower_button_function_long" />
|
android:title="@string/pref_title_lower_button_function_long" />
|
||||||
<Preference
|
<Preference
|
||||||
android:selectable="false"
|
android:selectable="false"
|
||||||
|
@ -57,6 +57,11 @@
|
|||||||
android:key="pref_hybridhr_watchface_power_saving_hands"
|
android:key="pref_hybridhr_watchface_power_saving_hands"
|
||||||
android:title="@string/watchface_setting_power_saving_hands"
|
android:title="@string/watchface_setting_power_saving_hands"
|
||||||
android:singleLineTitle="false" />
|
android:singleLineTitle="false" />
|
||||||
|
<SwitchPreference
|
||||||
|
android:persistent="false"
|
||||||
|
android:key="pref_hybridhr_watchface_light_up_on_notification"
|
||||||
|
android:title="@string/watchface_setting_light_up_on_notification"
|
||||||
|
android:singleLineTitle="false" />
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
@ -3,6 +3,10 @@
|
|||||||
android:key="pref_key_notifications"
|
android:key="pref_key_notifications"
|
||||||
android:title="@string/pref_header_notifications">
|
android:title="@string/pref_header_notifications">
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="notifications_settings"
|
||||||
|
android:title="@string/pref_title_notifications_generic_settings" />
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
android:key="notifications_generic"
|
android:key="notifications_generic"
|
||||||
android:title="@string/pref_title_notifications_generic" />
|
android:title="@string/pref_title_notifications_generic" />
|
||||||
|
@ -141,6 +141,10 @@
|
|||||||
android:layout="@layout/preference_checkbox"
|
android:layout="@layout/preference_checkbox"
|
||||||
android:summary="@string/pref_summary_location_keep_uptodate"
|
android:summary="@string/pref_summary_location_keep_uptodate"
|
||||||
android:title="@string/pref_title_location_keep_uptodate" />
|
android:title="@string/pref_title_location_keep_uptodate" />
|
||||||
|
<Preference
|
||||||
|
android:key="pref_key_opentracks_packagename"
|
||||||
|
android:summary="@string/pref_summary_opentracks_packagename"
|
||||||
|
android:title="@string/pref_title_opentracks_packagename" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
<PreferenceCategory android:title="@string/preferences_category_device_specific_settings">
|
<PreferenceCategory android:title="@string/preferences_category_device_specific_settings">
|
||||||
|
|
||||||
|
4
app/src/nightly/res/values/ic_launcher_background.xml
Normal file
4
app/src/nightly/res/values/ic_launcher_background.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="ic_launcher_background">#000000</color>
|
||||||
|
</resources>
|
4
app/src/nopebble/res/values/ic_launcher_background.xml
Normal file
4
app/src/nopebble/res/values/ic_launcher_background.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="ic_launcher_background">#ff3d00</color>
|
||||||
|
</resources>
|
2
external/fossil-hr-watchface
vendored
2
external/fossil-hr-watchface
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 44a70cf7c3a783d07d0fdab8b4b15e677da63af2
|
Subproject commit aad2a141cb2e151431f8354e52d9b74f6829855a
|
19
fastlane/metadata/android/en-US/changelogs/210.txt
Normal file
19
fastlane/metadata/android/en-US/changelogs/210.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
* Add basic support for Casio GBD-H1000
|
||||||
|
* Add support for Hama Fit Track 1900 - via FitPro device support
|
||||||
|
* Add OpenTracksController for interactions with OpenTracks
|
||||||
|
* Fossil Hybrid HR: Start/stop track in OpenTracks from GPS workout on watch
|
||||||
|
* Fossil Hybrid HR: Try guessing new widget position
|
||||||
|
* Fossil Hybrid HR: Allow assigning no function to a button
|
||||||
|
* Add Huami button/device action to control fitness tracking via OpenTracksController
|
||||||
|
* Mi Band 6: Sync alarms set on the watch like on Amazfit Bip U and others
|
||||||
|
* Bangle.js: Handle battery charging status and fix battery chart.
|
||||||
|
* Bangle.js: Prevent exception in case UART RX line is empty
|
||||||
|
* Bangle.js: Add repetitions in alarm JSON
|
||||||
|
* WaspOS: Fix battery chart.
|
||||||
|
* WaspOS: Add condition code to weather JSON
|
||||||
|
* XWatch: Add notifications and calls support
|
||||||
|
* UM-25: Make cumulative values resettable
|
||||||
|
* VESC: Fixed crash when loading a saved value
|
||||||
|
* Allow to open Android notification settings from Notification settings
|
||||||
|
* AutoExporter changes for better operation and troubleshooting
|
||||||
|
* Change Nightly icons background color
|
Loading…
Reference in New Issue
Block a user