mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-27 12:26:48 +01:00
Merge branch 'master' into zetime
This commit is contained in:
commit
1b152c86ea
11
.travis.yml
11
.travis.yml
@ -16,10 +16,10 @@ android:
|
|||||||
- tools
|
- tools
|
||||||
|
|
||||||
# The BuildTools version used by your project
|
# The BuildTools version used by your project
|
||||||
- build-tools-26.0.2
|
- build-tools-27.0.3
|
||||||
|
|
||||||
# The SDK version used to compile your project
|
# The SDK version used to compile your project
|
||||||
- android-25
|
- android-27
|
||||||
|
|
||||||
# Additional components
|
# Additional components
|
||||||
- extra-android-m2repository
|
- extra-android-m2repository
|
||||||
@ -30,4 +30,9 @@ android:
|
|||||||
#- sys-img-armeabi-v7a-android-19
|
#- sys-img-armeabi-v7a-android-19
|
||||||
#- sys-img-x86-android-17
|
#- sys-img-x86-android-17
|
||||||
|
|
||||||
script: ./gradlew build connectedCheck --stacktrace
|
before_install:
|
||||||
|
- yes | sdkmanager "platforms;android-27"
|
||||||
|
|
||||||
|
script:
|
||||||
|
- ./gradlew build connectedCheck --stacktrace
|
||||||
|
- bash config/travis/validate_fastlane_metadata.sh
|
||||||
|
98
CHANGELOG.md
98
CHANGELOG.md
@ -1,5 +1,77 @@
|
|||||||
### Changelog
|
### Changelog
|
||||||
|
|
||||||
|
#### Version 0.27.0
|
||||||
|
* Initial support for Mi Band 3 (largely untested, needs to be connected to Mi Fit once)
|
||||||
|
* Option for automatic activity sync after screen unlock
|
||||||
|
* Allow hiding activity transfer notification on Android Oreo and above
|
||||||
|
* Allow blacklisting of pebblekit notifications for individual apps
|
||||||
|
* Allow blacklisting all application at once
|
||||||
|
* Forward Skype notifications to wearable even if "local only" flag is set
|
||||||
|
* Show Gadgetbridge logo behind cards in main activity
|
||||||
|
* Always stop BT/BTLE discovery when exiting the discovery activity
|
||||||
|
* Amazfit Bip/Cor: Fix scheduled setting for "display on lift wrist" preference
|
||||||
|
* Amazfit Bip/Cor: add recent firmwares to whitelist
|
||||||
|
* Pebble: Fix a rare crash in webview
|
||||||
|
|
||||||
|
#### Version 0.26.5
|
||||||
|
* Fix autoreconnect at boot on recent Android versions
|
||||||
|
* Bluetooth connection is more stable on Oreo
|
||||||
|
* Potentially fix the watch continuously vibrating after call pickup
|
||||||
|
* Amazfit Bip: Add setting to configure shortcuts (swipe to right from watchface)
|
||||||
|
* Recognize Q8 as a HPlus device
|
||||||
|
|
||||||
|
#### Version 0.26.4
|
||||||
|
* Fix a bug with Toasts appearing every time a notification arrives when bluetooth is disabled
|
||||||
|
* Pebble 2: Add optional GATT client only mode that might help with connection stability
|
||||||
|
* Amazfit Cor: Fix detection of newer firmwares
|
||||||
|
* Mi Band 2: Fix text notifcations not appearing with short vibration patterns
|
||||||
|
|
||||||
|
#### Version 0.26.3
|
||||||
|
* Amazfit Bip: Add proper mime type to shared gpx files
|
||||||
|
* Amazfit Bip: allow to set displayed menu items
|
||||||
|
* Amazfit Bip: fix fetching logs from device via debug menu
|
||||||
|
* Amazfit Bip: Raise .res limit to 700000 bytes for modded files
|
||||||
|
|
||||||
|
#### Version 0.26.2
|
||||||
|
* Amazfit Bip: Time and timezone fixes for Android <=6 when exporting GPX
|
||||||
|
|
||||||
|
#### Version 0.26.1
|
||||||
|
* Fix crashes and connection problems on Android 6 and lower
|
||||||
|
|
||||||
|
#### Version 0.26.0
|
||||||
|
* Amazfit Bip: Initial support for GPS tracks
|
||||||
|
* Pebble: Wind speed/direction support and bugfixes for weather when using background javascript
|
||||||
|
|
||||||
|
#### Version 0.25.1
|
||||||
|
* Amazfit Cor: Try to send weather location instead of AQI
|
||||||
|
* Amazfit Bip: Support setting start end end time for background light when lifting the arm
|
||||||
|
* Pebble: various fixes and improvements for background javascript
|
||||||
|
* Explicitly ask for RECEIVE_SMS permission to fix problems with Android 8
|
||||||
|
|
||||||
|
#### Version 0.25.0
|
||||||
|
* Initial support for Xwatch
|
||||||
|
* Move the connected device to top in control center
|
||||||
|
* Add adaptive launcher icon for Android 8.x
|
||||||
|
* No longer plot heart rate graph when device was detected as not worn
|
||||||
|
* Pebble: Small fixes for background js (e.g. Pebble-Casio-WV58DE)
|
||||||
|
* Pebble: native (non bg js) support for weather in Simply Light watchface
|
||||||
|
|
||||||
|
#### Version 0.24.6
|
||||||
|
* Display the chat icon for notifications coming from Kontalk and Antox
|
||||||
|
* Pebble: Fix for background js which try to send floats (e.g. TrekVolle)
|
||||||
|
* Mi Band 2: Change the way vibration patterns work, also fixes problems with missing text on newer firmwares
|
||||||
|
|
||||||
|
#### Version 0.24.5
|
||||||
|
* Fix crash in settings activity with export location
|
||||||
|
* Fix notification deletion regression
|
||||||
|
* Add 'Ł' and 'ł' to transliteration map
|
||||||
|
* Omnijaws Weather: correctly pick today's min and max temperature
|
||||||
|
* Fix alarm details activity on small screen
|
||||||
|
* Pebble: mimic online check of TrekVolle when using background js
|
||||||
|
|
||||||
|
#### Version 0.24.4
|
||||||
|
* Amazfit Bip: Fix language setting on new firmwares
|
||||||
|
|
||||||
#### Version 0.24.3
|
#### Version 0.24.3
|
||||||
* Charts: Try to fix another crash
|
* Charts: Try to fix another crash
|
||||||
* Pebble: Fix weather for some watchfaces when using background JS
|
* Pebble: Fix weather for some watchfaces when using background JS
|
||||||
@ -52,7 +124,7 @@
|
|||||||
* Mi Band 2/Bip/Cor: Whole day HR support
|
* Mi Band 2/Bip/Cor: Whole day HR support
|
||||||
* Mi Band 2/Bip/Cor: Prevent writing a lot of HR samples to the database when not using the live activity feature
|
* Mi Band 2/Bip/Cor: Prevent writing a lot of HR samples to the database when not using the live activity feature
|
||||||
* Pebble: Fix some nasty crashes which occur since 0.22.0
|
* Pebble: Fix some nasty crashes which occur since 0.22.0
|
||||||
* Workround for non-working notifcations from wechat and outlook
|
* Workaround for non-working notifications from wechat and outlook
|
||||||
|
|
||||||
#### Version 0.22.3
|
#### Version 0.22.3
|
||||||
* Amazfit Bip: Allow flashing watchfaces
|
* Amazfit Bip: Allow flashing watchfaces
|
||||||
@ -74,7 +146,7 @@
|
|||||||
* Add experimental support for Amazfit Cor and Mi Band HRX (no firmware update on the latter)
|
* Add experimental support for Amazfit Cor and Mi Band HRX (no firmware update on the latter)
|
||||||
* Mi Band 2: Support more icons and textual notifications for more apps
|
* Mi Band 2: Support more icons and textual notifications for more apps
|
||||||
* Add some quick action buttons to Gadgetbridge's notification
|
* Add some quick action buttons to Gadgetbridge's notification
|
||||||
* Add transliteration support for ukranian cyrillic charaters
|
* Add transliteration support for ukrainian cyrillic characters
|
||||||
* Fix annoying toast in Mi Band settings
|
* Fix annoying toast in Mi Band settings
|
||||||
|
|
||||||
#### Version 0.21.6
|
#### Version 0.21.6
|
||||||
@ -121,7 +193,7 @@
|
|||||||
* Amazfit Bip: Fix call notification with unknown caller
|
* Amazfit Bip: Fix call notification with unknown caller
|
||||||
* Amazfit Bip: Fix crash when weather is updated and device reconnecting
|
* Amazfit Bip: Fix crash when weather is updated and device reconnecting
|
||||||
* Mi2/Bip: Fix crash when synchronizing calendar to alarms
|
* Mi2/Bip: Fix crash when synchronizing calendar to alarms
|
||||||
* Pebble: Fix crash when takeing screenshots on Android 8.0 (Oreo)
|
* Pebble: Fix crash when taking screenshots on Android 8.0 (Oreo)
|
||||||
* Pebble: Support some google app icons
|
* Pebble: Support some google app icons
|
||||||
* Pebble: try to support spotify
|
* Pebble: try to support spotify
|
||||||
* Mi Band 2: Support configurable button actions
|
* Mi Band 2: Support configurable button actions
|
||||||
@ -140,7 +212,7 @@
|
|||||||
* Mi Band: Fix setting smart alarms
|
* Mi Band: Fix setting smart alarms
|
||||||
|
|
||||||
#### Version 0.20.0
|
#### Version 0.20.0
|
||||||
* Inital Amazfit Bip support (WIP)
|
* Initial Amazfit Bip support (WIP)
|
||||||
* Various theming fixes
|
* Various theming fixes
|
||||||
* Add workaround for blacklist not properly persisting
|
* Add workaround for blacklist not properly persisting
|
||||||
* Handle resetting language to default properly
|
* Handle resetting language to default properly
|
||||||
@ -211,7 +283,7 @@
|
|||||||
* Mi Band 2: Fix crash on "chat" or "social network" text notification (#603)
|
* Mi Band 2: Fix crash on "chat" or "social network" text notification (#603)
|
||||||
|
|
||||||
#### Version 0.18.1
|
#### Version 0.18.1
|
||||||
* Pebble: Fix Firmware insstallation on Pebble Time Round (broken since 0.16.0)
|
* Pebble: Fix Firmware installation on Pebble Time Round (broken since 0.16.0)
|
||||||
* Start VibrationActivity when using "find device" button with Vibratissimo
|
* Start VibrationActivity when using "find device" button with Vibratissimo
|
||||||
* Support material fork of K9
|
* Support material fork of K9
|
||||||
|
|
||||||
@ -253,9 +325,9 @@
|
|||||||
#### Version 0.17.3
|
#### Version 0.17.3
|
||||||
* HPlus: Improve display of new messages and phone calls
|
* HPlus: Improve display of new messages and phone calls
|
||||||
* HPlus: Fix bug related to steps and heart rate
|
* HPlus: Fix bug related to steps and heart rate
|
||||||
* Pebble: Support dynamic keys for natively supported watchfaces and watchapps (more stability accross versions)
|
* Pebble: Support dynamic keys for natively supported watchfaces and watchapps (more stability across versions)
|
||||||
* Pebble: Fix error Toast being displayed when TimeStyle watchface is not installed
|
* Pebble: Fix error Toast being displayed when TimeStyle watchface is not installed
|
||||||
* Mi Band 1+2: Support for connecting wihout BT pairing (workaround for certain connection problems)
|
* Mi Band 1+2: Support for connecting without BT pairing (workaround for certain connection problems)
|
||||||
|
|
||||||
#### Version 0.17.2
|
#### Version 0.17.2
|
||||||
* Pebble: Fix temperature unit in Timestyle Pebble watchface
|
* Pebble: Fix temperature unit in Timestyle Pebble watchface
|
||||||
@ -275,7 +347,7 @@
|
|||||||
* Pebble: Add option to disable call display
|
* Pebble: Add option to disable call display
|
||||||
* Pebble: Add option to automatically delete notifications that got dismissed on the phone
|
* Pebble: Add option to automatically delete notifications that got dismissed on the phone
|
||||||
* Pebble: Bugfix for some PebbleKit enabled 3rd party apps (TCW and maybe other)
|
* Pebble: Bugfix for some PebbleKit enabled 3rd party apps (TCW and maybe other)
|
||||||
* Pebble 2/LE: Improve reliablitly and transfer speed
|
* Pebble 2/LE: Improve reliability and transfer speed
|
||||||
* HPlus: Improved discovery and pairing
|
* HPlus: Improved discovery and pairing
|
||||||
* HPlus: Improved notifications (display + vibration)
|
* HPlus: Improved notifications (display + vibration)
|
||||||
* HPlus: Synchronize time and date
|
* HPlus: Synchronize time and date
|
||||||
@ -352,7 +424,7 @@
|
|||||||
|
|
||||||
#### Version 0.13.7
|
#### Version 0.13.7
|
||||||
* Pebble: Fix configuration of certain pebble apps (eg. QR Generator, Squared 4.0)
|
* Pebble: Fix configuration of certain pebble apps (eg. QR Generator, Squared 4.0)
|
||||||
* Pebble: Add context menu option in app manager to search a watchapp in the pebble appstore
|
* Pebble: Add context menu option in app manager to search a watchapp in the pebble app store
|
||||||
* Mi Band: allow to delete Mi Band address from development settings
|
* Mi Band: allow to delete Mi Band address from development settings
|
||||||
* Mi Band 2: Initial support for heart rate readings (Debug activity only)
|
* Mi Band 2: Initial support for heart rate readings (Debug activity only)
|
||||||
* Mi Band 2: Support disabled alarms
|
* Mi Band 2: Support disabled alarms
|
||||||
@ -523,7 +595,7 @@
|
|||||||
* Fix enabling log file writing #261
|
* Fix enabling log file writing #261
|
||||||
|
|
||||||
#### Version 0.9.0
|
#### Version 0.9.0
|
||||||
* Pebble: Support for configuring watchfaces/apps locally (clay) or though webbrowser (some do not work)
|
* Pebble: Support for configuring watchfaces/apps locally (clay) or though web browser (some do not work)
|
||||||
* Pebble: hide the alarm management activity as it's unsupported
|
* Pebble: hide the alarm management activity as it's unsupported
|
||||||
* Mi Band: Improve firmware detection and updates, including 1S support
|
* Mi Band: Improve firmware detection and updates, including 1S support
|
||||||
* Mi Band: Display HR FW for 1S
|
* Mi Band: Display HR FW for 1S
|
||||||
@ -671,7 +743,7 @@
|
|||||||
* Pebble: Allow to treat K9 notifications as generic notifications (if notification mode is set to never)
|
* Pebble: Allow to treat K9 notifications as generic notifications (if notification mode is set to never)
|
||||||
* Ignore QKSMS notifications to avoid double notification for incoming SMS
|
* Ignore QKSMS notifications to avoid double notification for incoming SMS
|
||||||
* Improved UI of Firmware/App installer
|
* Improved UI of Firmware/App installer
|
||||||
* Device state again visible on lockscreen
|
* Device state again visible on lock screen
|
||||||
* Date display and navigation now working properly for all charts
|
* Date display and navigation now working properly for all charts
|
||||||
|
|
||||||
#### Version 0.5.2
|
#### Version 0.5.2
|
||||||
@ -714,7 +786,7 @@
|
|||||||
* Fixed crash when synchronizing activity data in the graphs activity and changing device orientation
|
* Fixed crash when synchronizing activity data in the graphs activity and changing device orientation
|
||||||
|
|
||||||
#### Version 0.4.4
|
#### Version 0.4.4
|
||||||
* Set Gadgetbridge notification visibility to public, to show the connection status on the lockscreen
|
* Set Gadgetbridge notification visibility to public, to show the connection status on the lock screen
|
||||||
* Support for backup up and restoring of the activity database (via Debug activity)
|
* Support for backup up and restoring of the activity database (via Debug activity)
|
||||||
* Support for graceful upgrades and downgrades, keeping your activity database intact
|
* Support for graceful upgrades and downgrades, keeping your activity database intact
|
||||||
* Enhancement to activity graphs: new graphs for sleep data (only last night) accessible swiping right from the main graph
|
* Enhancement to activity graphs: new graphs for sleep data (only last night) accessible swiping right from the main graph
|
||||||
@ -804,7 +876,7 @@
|
|||||||
|
|
||||||
#### Version 0.1.4
|
#### Version 0.1.4
|
||||||
* New AppManager shows installed Apps/Watchfaces (removal possible via context menu)
|
* New AppManager shows installed Apps/Watchfaces (removal possible via context menu)
|
||||||
* Allow back navigation in ActionBar (Debug and AppMananger Activities)
|
* Allow back navigation in ActionBar (Debug and AppManager Activities)
|
||||||
* Make sure Intent broadcasts do not leave Gadgetbridge
|
* Make sure Intent broadcasts do not leave Gadgetbridge
|
||||||
* Show hint in the Main Activity (tap to connect etc)
|
* Show hint in the Main Activity (tap to connect etc)
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
names ()
|
names ()
|
||||||
{
|
{
|
||||||
echo -e "\n exit;\n**Contributors (sorted by number of commits):**\n";
|
echo -e "\n exit;\n**Contributors (sorted by number of commits):**\n";
|
||||||
git log --format='%aN:%ae' origin/master | grep -Ev "FYG_.*_bot_ignore_me" | sed 's/@users.github.com/@users.noreply.github.com/g' | awk 'BEGIN{FS=":"}{ct[$1]+=1;if (length($2) > length(e[$1])) {e[$1]=$2}}END{for (i in e) { n[i]=e[i];c[i]+=ct[i] }; for (a in e) print c[a]"\t* "a" <"n[a]">";}' | sort -n -r | cut -f 2-
|
git log --format='%aN:%aE' origin/master | grep -Ev "(anonymous:|FYG_.*_bot_ignore_me)" | sed 's/@users.github.com/@users.noreply.github.com/g' | awk 'BEGIN{FS=":"}{ct[$1]+=1;e[$1]=$2}END{for (i in e) { n[i]=e[i];c[i]+=ct[i] }; for (a in e) print c[a]"\t* "a" <"n[a]">";}' | sort -n -r | cut -f 2-
|
||||||
}
|
}
|
||||||
quine ()
|
quine ()
|
||||||
{
|
{
|
||||||
@ -12,7 +12,7 @@
|
|||||||
declare -f quine | sed -e 's/^[[:space:]]*/ /';
|
declare -f quine | sed -e 's/^[[:space:]]*/ /';
|
||||||
echo -e " quine\n";
|
echo -e " quine\n";
|
||||||
names;
|
names;
|
||||||
echo -e "\nAnd all the Transifex translators, which I cannot automatically list, at the moment.\n\n*To update the contributors list just run this file with bash*"
|
echo -e "\nAnd all the Transifex translators, which I cannot automatically list, at the moment.\n\n*To update the contributors list just run this file with bash. Prefix a name with % in .mailmap to set a contact as preferred*"
|
||||||
} > CONTRIBUTORS.rst;
|
} > CONTRIBUTORS.rst;
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
@ -26,47 +26,124 @@
|
|||||||
* Carsten Pfeiffer <cpfeiffer@users.noreply.github.com>
|
* Carsten Pfeiffer <cpfeiffer@users.noreply.github.com>
|
||||||
* Daniele Gobbetti <daniele+github@gobbetti.name>
|
* Daniele Gobbetti <daniele+github@gobbetti.name>
|
||||||
* João Paulo Barraca <jpbarraca@gmail.com>
|
* João Paulo Barraca <jpbarraca@gmail.com>
|
||||||
* ivanovlev <lion.ivanov@gmal.com>
|
* Jonas <jonasdcdm@posteo.net>
|
||||||
|
* Yaron Shahrabani <sh.yaron@gmail.com>
|
||||||
|
* postsorino <postsorino@krutt.org>
|
||||||
|
* protomors <protomors@gmail.com>
|
||||||
|
* Allan Nordhøy <epost@anotheragency.no>
|
||||||
|
* mueller-ma <mueller-ma@users.noreply.github.com>
|
||||||
|
* ivanovlev <ivanovlev@mail.ru>
|
||||||
|
* naofum <naofum@gmail.com>
|
||||||
|
* youzhiran <2668760098@qq.com>
|
||||||
|
* Tijl Schepens <tijl.schepens@hotmail.com>
|
||||||
|
* TaaviE <taavi.eomae+weblate@gmail.com>
|
||||||
* Julien Pivotto <roidelapluie@inuits.eu>
|
* Julien Pivotto <roidelapluie@inuits.eu>
|
||||||
|
* Taavi Eomäe <taavi.eomae+github@gmail.com>
|
||||||
* Steffen Liebergeld <perl@gmx.org>
|
* Steffen Liebergeld <perl@gmx.org>
|
||||||
* Lem Dulfo <lemuel.dulfo@gmail.com>
|
* Lem Dulfo <lemuel.dulfo@gmail.com>
|
||||||
|
* Hadrián Candela <hadrian.candela@gmail.com>
|
||||||
|
* Felix Konstantin Maurer <maufl@maufl.de>
|
||||||
* Sergey Trofimov <sarg@sarg.org.ru>
|
* Sergey Trofimov <sarg@sarg.org.ru>
|
||||||
|
* Robert Barat <rbarat07@gmail.com>
|
||||||
|
* José Rebelo <joserebelo@outlook.com>
|
||||||
* JohnnySun <bmy001@gmail.com>
|
* JohnnySun <bmy001@gmail.com>
|
||||||
* Uwe Hermann <uwe@hermann-uwe.de>
|
* Uwe Hermann <uwe@hermann-uwe.de>
|
||||||
|
* Edoardo Rosa <edoardo.rosa90@gmail.com>
|
||||||
* Alberto <albertsal83@gmail.com>
|
* Alberto <albertsal83@gmail.com>
|
||||||
* 0nse <0nse@users.noreply.github.com>
|
* Vladislav Serkov <vladserkoff@protonmail.com>
|
||||||
|
* Vebryn <vebryn@gmail.com>
|
||||||
|
* Gilles Émilien MOREL <contact@gilles-morel.fr>
|
||||||
* Gergely Peidl <gergely@peidl.net>
|
* Gergely Peidl <gergely@peidl.net>
|
||||||
|
* Bożydar <trening302@o2.pl>
|
||||||
|
* 0nse <0nse@users.noreply.github.com>
|
||||||
|
* Максим Якимчук <xpinovo@gmail.com>
|
||||||
|
* Rimas Raguliūnas <rarimas@gmail.com>
|
||||||
|
* masakoodaa <masakoodaa@protonmail.com>
|
||||||
|
* Lukas Veneziano <fs@venezilu.de>
|
||||||
|
* Kompact <joaorafael123@hotmail.com>
|
||||||
|
* Jasper <jespiex456@hotmail.com>
|
||||||
* Christian Fischer <sw-dev@computerlyrik.de>
|
* Christian Fischer <sw-dev@computerlyrik.de>
|
||||||
|
* c4ndel4 <hadrian.candela@gmail.com>
|
||||||
* 6arms1leg <m.brnsfld@googlemail.com>
|
* 6arms1leg <m.brnsfld@googlemail.com>
|
||||||
|
* Zhong Jianxin <azuwis@gmail.com>
|
||||||
* walkjivefly <mark@walkjivefly.com>
|
* walkjivefly <mark@walkjivefly.com>
|
||||||
|
* Ted Stein <me@tedstein.net>
|
||||||
|
* NotAFIle <nota@notafile.com>
|
||||||
* Normano64 <per.bergqwist@gmail.com>
|
* Normano64 <per.bergqwist@gmail.com>
|
||||||
|
* NicoBuntu <nicolas__du95@hotmail.fr>
|
||||||
|
* nautilusx <mail.ka@mailbox.org>
|
||||||
|
* Minori Hiraoka (미노리) <minori@mnetwork.co.kr>
|
||||||
|
* Michal Novotny <mignov@gmail.com>
|
||||||
|
* mesnevi <shams@airpost.net>
|
||||||
|
* LL <lu.lecocq@free.fr>
|
||||||
|
* Jesús <zaagur@gmail.com>
|
||||||
|
* exit-failure <hakrala@web.de>
|
||||||
* Avamander <Avamander@users.noreply.github.com>
|
* Avamander <Avamander@users.noreply.github.com>
|
||||||
|
* AnthonyDiGirolamo <anthony.digirolamo@gmail.com>
|
||||||
|
* Andreas Kromke <Andreas.Kromke@web.de>
|
||||||
* Ⲇⲁⲛⲓ Φi <daniphii@outlook.com>
|
* Ⲇⲁⲛⲓ Φi <daniphii@outlook.com>
|
||||||
* Yar <yaroslav.isakov@gmail.com>
|
* Yar <yaroslav.isakov@gmail.com>
|
||||||
* Yaron Shahrabani <sh.yaron@gmail.com>
|
|
||||||
* xzovy <caleb@caleb-cooper.net>
|
* xzovy <caleb@caleb-cooper.net>
|
||||||
* xphnx <xphnx@users.noreply.github.com>
|
* xphnx <xphnx@users.noreply.github.com>
|
||||||
|
* Vitaliy Shuruta <vshuruta@gmail.com>
|
||||||
|
* Tomer Rosenfeld <tomerosenfeld007@gmail.com>
|
||||||
|
* Tomas Radej <tradej@redhat.com>
|
||||||
|
* tiparega <11555126+tiparega@users.noreply.github.com>
|
||||||
* Tarik Sekmen <tarik@ilixi.org>
|
* Tarik Sekmen <tarik@ilixi.org>
|
||||||
* Szymon Tomasz Stefanek <s.stefanek@gmail.com>
|
* Szymon Tomasz Stefanek <s.stefanek@gmail.com>
|
||||||
|
* Sergio Lopez <slp@sinrega.org>
|
||||||
|
* Sami Alaoui <4ndroidgeek@gmail.com>
|
||||||
* Roman Plevka <rplevka@redhat.com>
|
* Roman Plevka <rplevka@redhat.com>
|
||||||
* rober <rober@prtl.nodomain.net>
|
* rober <rober@prtl.nodomain.net>
|
||||||
|
* redking <redking974@gmail.com>
|
||||||
|
* Quallenauge <Hamsi2k@freenet.de>
|
||||||
|
* Pavel Motyrev <legioner.r@gmail.com>
|
||||||
|
* Pascal <pascal.tannich@gmail.com>
|
||||||
|
* Olexandr Nesterenko <olexn@ukr.net>
|
||||||
* Nicolò Balzarotti <anothersms@gmail.com>
|
* Nicolò Balzarotti <anothersms@gmail.com>
|
||||||
* Natanael Arndt <arndtn@gmail.com>
|
* Natanael Arndt <arndtn@gmail.com>
|
||||||
|
* Moarc <aldwulf@gmail.com>
|
||||||
|
* Michal Novak <michal.novak@post.cz>
|
||||||
|
* michaelneu <git@michaeln.eu>
|
||||||
|
* McSym28 <McSym28@users.noreply.github.com>
|
||||||
|
* MaxL <z60loa8qw3umzu3@my10minutemail.com>
|
||||||
|
* Martin <ritualz@users.noreply.github.com>
|
||||||
|
* Martin Piatka <chachacha2323@gmail.com>
|
||||||
* Marc Schlaich <marc.schlaich@googlemail.com>
|
* Marc Schlaich <marc.schlaich@googlemail.com>
|
||||||
|
* Manuel Soler <vg8020@gmail.com>
|
||||||
|
* Luiz Felipe das Neves Lopes <androidfelipe23@gmail.com>
|
||||||
|
* Leonardo Amaral <contato@leonardoamaral.com.br>
|
||||||
|
* lazarosfs <lazarosfs@csd.auth.gr>
|
||||||
|
* ladbsoft <30509719+ladbsoft@users.noreply.github.com>
|
||||||
|
* Kristjan Räts <kristjanrats@gmail.com>
|
||||||
* kevlarcade <kevlarcade@gmail.com>
|
* kevlarcade <kevlarcade@gmail.com>
|
||||||
* Kevin Richter <me@kevinrichter.nl>
|
* Kevin Richter <me@kevinrichter.nl>
|
||||||
|
* Kaz Wolfe <root@kazwolfe.io>
|
||||||
* Kasha <kasha_malaga@hotmail.com>
|
* Kasha <kasha_malaga@hotmail.com>
|
||||||
|
* Joseph Kim <official.jkim@gmail.com>
|
||||||
|
* Jan Lolek <janlolek@seznam.cz>
|
||||||
|
* Jakub Jelínek <jakub.jelinek@gmail.com>
|
||||||
* Ivan <ivan_tizhanin@mail.ru>
|
* Ivan <ivan_tizhanin@mail.ru>
|
||||||
* Hasan Ammar <ammarh@gmail.com>
|
* Hasan Ammar <ammarh@gmail.com>
|
||||||
* Gilles MOREL <contact@gilles-morel.fr>
|
* Gilles MOREL <contact@gilles-morel.fr>
|
||||||
* Gilles Émilien MOREL <Almtesh@users.noreply.github.com>
|
* Gideão Gomes Ferreira <trjctr@gmail.com>
|
||||||
|
* Gabe Schrecker <gabe@pbrb.co.uk>
|
||||||
|
* freezed-or-frozen <freezed.or.frozen@gmail.com>
|
||||||
|
* Frank Slezak <KazWolfe@users.noreply.github.com>
|
||||||
|
* Davis Mosenkovs <davikovs@gmail.com>
|
||||||
* Daniel Hauck <maill@dhauck.eu>
|
* Daniel Hauck <maill@dhauck.eu>
|
||||||
|
* criogenic <criogenic@gmail.com>
|
||||||
* Chris Perelstein <chris.perelstein@gmail.com>
|
* Chris Perelstein <chris.perelstein@gmail.com>
|
||||||
|
* chabotsi <chabotsi+github@chabotsi.fr>
|
||||||
* Carlos Ferreira <calbertoferreira@gmail.com>
|
* Carlos Ferreira <calbertoferreira@gmail.com>
|
||||||
|
* bucala <marcel.bucala@gmail.com>
|
||||||
|
* batataspt@gmail.com <batataspt@gmail.com>
|
||||||
* atkyritsis <at.kyritsis@gmail.com>
|
* atkyritsis <at.kyritsis@gmail.com>
|
||||||
|
* AndrewH <36428679+andrewheadricke@users.noreply.github.com>
|
||||||
* andre <andre.buesgen@yahoo.de>
|
* andre <andre.buesgen@yahoo.de>
|
||||||
|
* Allen B <28495335+Allen-B1@users.noreply.github.com>
|
||||||
* Alexey Afanasev <avafanasiev@gmail.com>
|
* Alexey Afanasev <avafanasiev@gmail.com>
|
||||||
|
|
||||||
And all the Transifex translators, which I cannot automatically list, at the moment.
|
And all the Transifex translators, which I cannot automatically list, at the moment.
|
||||||
|
|
||||||
*To update the contributors list just run this file with bash*
|
*To update the contributors list just run this file with bash. Prefix a name with % in .mailmap to set a contact as preferred*
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
|Realtime Activity Tracking | NO | NO | YES | YES | YES |
|
|Realtime Activity Tracking | NO | NO | YES | YES | YES |
|
||||||
|Music Control | YES | YES | NO | NO | NO |
|
|Music Control | YES | YES | NO | NO | NO |
|
||||||
|Watchapp/face Installation | YES | YES | NO | NO | YES |
|
|Watchapp/face Installation | YES | YES | NO | NO | YES |
|
||||||
|Firmware Installaton | YES | YES | YES | YES | YES |
|
|Firmware Installation | YES | YES | YES | YES | YES |
|
||||||
|Taking Screenshots | YES | YES | NO | NO | NO |
|
|Taking Screenshots | YES | YES | NO | NO | NO |
|
||||||
|Support Android Companion Apps | YES | YES | NO | NO | NO |
|
|Support Android Companion Apps | YES | YES | NO | NO | NO |
|
||||||
|
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package nodomain.freeyourgadget.gadgetbridge.daogen;
|
package nodomain.freeyourgadget.gadgetbridge.daogen;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
import de.greenrobot.daogenerator.DaoGenerator;
|
import de.greenrobot.daogenerator.DaoGenerator;
|
||||||
import de.greenrobot.daogenerator.Entity;
|
import de.greenrobot.daogenerator.Entity;
|
||||||
import de.greenrobot.daogenerator.Index;
|
import de.greenrobot.daogenerator.Index;
|
||||||
@ -32,6 +34,7 @@ public class GBDaoGenerator {
|
|||||||
private static final String MAIN_PACKAGE = "nodomain.freeyourgadget.gadgetbridge";
|
private static final String MAIN_PACKAGE = "nodomain.freeyourgadget.gadgetbridge";
|
||||||
private static final String MODEL_PACKAGE = MAIN_PACKAGE + ".model";
|
private static final String MODEL_PACKAGE = MAIN_PACKAGE + ".model";
|
||||||
private static final String VALID_BY_DATE = MODEL_PACKAGE + ".ValidByDate";
|
private static final String VALID_BY_DATE = MODEL_PACKAGE + ".ValidByDate";
|
||||||
|
private static final String ACTIVITY_SUMMARY = MODEL_PACKAGE + ".ActivitySummary";
|
||||||
private static final String OVERRIDE = "@Override";
|
private static final String OVERRIDE = "@Override";
|
||||||
private static final String SAMPLE_RAW_INTENSITY = "rawIntensity";
|
private static final String SAMPLE_RAW_INTENSITY = "rawIntensity";
|
||||||
private static final String SAMPLE_STEPS = "steps";
|
private static final String SAMPLE_STEPS = "steps";
|
||||||
@ -42,7 +45,7 @@ public class GBDaoGenerator {
|
|||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
Schema schema = new Schema(17, MAIN_PACKAGE + ".entities");
|
Schema schema = new Schema(18, MAIN_PACKAGE + ".entities");
|
||||||
|
|
||||||
Entity userAttributes = addUserAttributes(schema);
|
Entity userAttributes = addUserAttributes(schema);
|
||||||
Entity user = addUserInfo(schema, userAttributes);
|
Entity user = addUserInfo(schema, userAttributes);
|
||||||
@ -65,10 +68,13 @@ public class GBDaoGenerator {
|
|||||||
addHPlusHealthActivityKindOverlay(schema, user, device);
|
addHPlusHealthActivityKindOverlay(schema, user, device);
|
||||||
addHPlusHealthActivitySample(schema, user, device);
|
addHPlusHealthActivitySample(schema, user, device);
|
||||||
addNo1F1ActivitySample(schema, user, device);
|
addNo1F1ActivitySample(schema, user, device);
|
||||||
|
addXWatchActivitySample(schema, user, device);
|
||||||
addZeTimeActivitySample(schema, user, device);
|
addZeTimeActivitySample(schema, user, device);
|
||||||
|
|
||||||
addCalendarSyncState(schema, device);
|
addCalendarSyncState(schema, device);
|
||||||
|
|
||||||
|
addBipActivitySummary(schema, user, device);
|
||||||
|
|
||||||
new DaoGenerator().generateAll(schema, "app/src/main/java");
|
new DaoGenerator().generateAll(schema, "app/src/main/java");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,6 +276,17 @@ public class GBDaoGenerator {
|
|||||||
return activitySample;
|
return activitySample;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Entity addXWatchActivitySample(Schema schema, Entity user, Entity device) {
|
||||||
|
Entity activitySample = addEntity(schema, "XWatchActivitySample");
|
||||||
|
activitySample.implementsSerializable();
|
||||||
|
addCommonActivitySampleProperties("AbstractActivitySample", activitySample, user, device);
|
||||||
|
activitySample.addIntProperty(SAMPLE_STEPS).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||||
|
activitySample.addIntProperty(SAMPLE_RAW_KIND).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||||
|
activitySample.addIntProperty(SAMPLE_RAW_INTENSITY).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||||
|
addHeartRateProperties(activitySample);
|
||||||
|
return activitySample;
|
||||||
|
}
|
||||||
|
|
||||||
private static Entity addZeTimeActivitySample(Schema schema, Entity user, Entity device) {
|
private static Entity addZeTimeActivitySample(Schema schema, Entity user, Entity device) {
|
||||||
Entity activitySample = addEntity(schema, "ZeTimeActivitySample");
|
Entity activitySample = addEntity(schema, "ZeTimeActivitySample");
|
||||||
activitySample.implementsSerializable();
|
activitySample.implementsSerializable();
|
||||||
@ -309,6 +326,31 @@ public class GBDaoGenerator {
|
|||||||
calendarSyncState.addIntProperty("hash").notNull();
|
calendarSyncState.addIntProperty("hash").notNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void addBipActivitySummary(Schema schema, Entity user, Entity device) {
|
||||||
|
Entity summary = addEntity(schema, "BaseActivitySummary");
|
||||||
|
summary.implementsInterface(ACTIVITY_SUMMARY);
|
||||||
|
summary.addIdProperty();
|
||||||
|
|
||||||
|
summary.setJavaDoc(
|
||||||
|
"This class represents the summary of a user's activity event. I.e. a walk, hike, a bicycle tour, etc.");
|
||||||
|
|
||||||
|
summary.addStringProperty("name").codeBeforeGetter(OVERRIDE);
|
||||||
|
summary.addDateProperty("startTime").notNull().codeBeforeGetter(OVERRIDE);
|
||||||
|
summary.addDateProperty("endTime").notNull().codeBeforeGetter(OVERRIDE);
|
||||||
|
summary.addIntProperty("activityKind").notNull().codeBeforeGetter(OVERRIDE);
|
||||||
|
|
||||||
|
summary.addIntProperty("baseLongitude").javaDocGetterAndSetter("Temporary, bip-specific");
|
||||||
|
summary.addIntProperty("baseLatitude").javaDocGetterAndSetter("Temporary, bip-specific");
|
||||||
|
summary.addIntProperty("baseAltitude").javaDocGetterAndSetter("Temporary, bip-specific");
|
||||||
|
|
||||||
|
summary.addStringProperty("gpxTrack").codeBeforeGetter(OVERRIDE);
|
||||||
|
|
||||||
|
Property deviceId = summary.addLongProperty("deviceId").notNull().codeBeforeGetter(OVERRIDE).getProperty();
|
||||||
|
summary.addToOne(device, deviceId);
|
||||||
|
Property userId = summary.addLongProperty("userId").notNull().codeBeforeGetter(OVERRIDE).getProperty();
|
||||||
|
summary.addToOne(user, userId);
|
||||||
|
}
|
||||||
|
|
||||||
private static Property findProperty(Entity entity, String propertyName) {
|
private static Property findProperty(Entity entity, String propertyName) {
|
||||||
for (Property prop : entity.getProperties()) {
|
for (Property prop : entity.getProperties()) {
|
||||||
if (propertyName.equals(prop.getPropertyName())) {
|
if (propertyName.equals(prop.getPropertyName())) {
|
||||||
|
@ -0,0 +1,365 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 Markus Junginger, greenrobot (http://greenrobot.de)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.daogen;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import de.greenrobot.daogenerator.DaoGenerator;
|
||||||
|
import de.greenrobot.daogenerator.Entity;
|
||||||
|
import de.greenrobot.daogenerator.Index;
|
||||||
|
import de.greenrobot.daogenerator.Property;
|
||||||
|
import de.greenrobot.daogenerator.Schema;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates entities and DAOs for the example project DaoExample.
|
||||||
|
* Automatically run during build.
|
||||||
|
*/
|
||||||
|
public class GBDaoGenerator {
|
||||||
|
|
||||||
|
private static final String VALID_FROM_UTC = "validFromUTC";
|
||||||
|
private static final String VALID_TO_UTC = "validToUTC";
|
||||||
|
private static final String MAIN_PACKAGE = "nodomain.freeyourgadget.gadgetbridge";
|
||||||
|
private static final String MODEL_PACKAGE = MAIN_PACKAGE + ".model";
|
||||||
|
private static final String VALID_BY_DATE = MODEL_PACKAGE + ".ValidByDate";
|
||||||
|
private static final String ACTIVITY_SUMMARY = MODEL_PACKAGE + ".ActivitySummary";
|
||||||
|
private static final String OVERRIDE = "@Override";
|
||||||
|
private static final String SAMPLE_RAW_INTENSITY = "rawIntensity";
|
||||||
|
private static final String SAMPLE_STEPS = "steps";
|
||||||
|
private static final String SAMPLE_RAW_KIND = "rawKind";
|
||||||
|
private static final String SAMPLE_HEART_RATE = "heartRate";
|
||||||
|
private static final String TIMESTAMP_FROM = "timestampFrom";
|
||||||
|
private static final String TIMESTAMP_TO = "timestampTo";
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
Schema schema = new Schema(18, MAIN_PACKAGE + ".entities");
|
||||||
|
|
||||||
|
Entity userAttributes = addUserAttributes(schema);
|
||||||
|
Entity user = addUserInfo(schema, userAttributes);
|
||||||
|
|
||||||
|
Entity deviceAttributes = addDeviceAttributes(schema);
|
||||||
|
Entity device = addDevice(schema, deviceAttributes);
|
||||||
|
|
||||||
|
// yeah deep shit, has to be here (after device) for db upgrade and column order
|
||||||
|
// because addDevice adds a property to deviceAttributes also....
|
||||||
|
deviceAttributes.addStringProperty("volatileIdentifier");
|
||||||
|
|
||||||
|
Entity tag = addTag(schema);
|
||||||
|
Entity userDefinedActivityOverlay = addActivityDescription(schema, tag, user);
|
||||||
|
|
||||||
|
addMiBandActivitySample(schema, user, device);
|
||||||
|
addPebbleHealthActivitySample(schema, user, device);
|
||||||
|
addPebbleHealthActivityKindOverlay(schema, user, device);
|
||||||
|
addPebbleMisfitActivitySample(schema, user, device);
|
||||||
|
addPebbleMorpheuzActivitySample(schema, user, device);
|
||||||
|
addHPlusHealthActivityKindOverlay(schema, user, device);
|
||||||
|
addHPlusHealthActivitySample(schema, user, device);
|
||||||
|
addNo1F1ActivitySample(schema, user, device);
|
||||||
|
<<<<<<< HEAD
|
||||||
|
addZeTimeActivitySample(schema, user, device);
|
||||||
|
=======
|
||||||
|
addXWatchActivitySample(schema, user, device);
|
||||||
|
>>>>>>> master
|
||||||
|
|
||||||
|
addCalendarSyncState(schema, device);
|
||||||
|
|
||||||
|
addBipActivitySummary(schema, user, device);
|
||||||
|
|
||||||
|
new DaoGenerator().generateAll(schema, "app/src/main/java");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Entity addTag(Schema schema) {
|
||||||
|
Entity tag = addEntity(schema, "Tag");
|
||||||
|
tag.addIdProperty();
|
||||||
|
tag.addStringProperty("name").notNull();
|
||||||
|
tag.addStringProperty("description").javaDocGetterAndSetter("An optional description of this tag.");
|
||||||
|
tag.addLongProperty("userId").notNull();
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Entity addActivityDescription(Schema schema, Entity tag, Entity user) {
|
||||||
|
Entity activityDesc = addEntity(schema, "ActivityDescription");
|
||||||
|
activityDesc.setJavaDoc("A user may further specify his activity with a detailed description and the help of tags.\nOne or more tags can be added to a given activity range.");
|
||||||
|
activityDesc.addIdProperty();
|
||||||
|
activityDesc.addIntProperty(TIMESTAMP_FROM).notNull();
|
||||||
|
activityDesc.addIntProperty(TIMESTAMP_TO).notNull();
|
||||||
|
activityDesc.addStringProperty("details").javaDocGetterAndSetter("An optional detailed description, specific to this very activity occurrence.");
|
||||||
|
|
||||||
|
Property userId = activityDesc.addLongProperty("userId").notNull().getProperty();
|
||||||
|
activityDesc.addToOne(user, userId);
|
||||||
|
|
||||||
|
Entity activityDescTagLink = addEntity(schema, "ActivityDescTagLink");
|
||||||
|
activityDescTagLink.addIdProperty();
|
||||||
|
Property sourceId = activityDescTagLink.addLongProperty("activityDescriptionId").notNull().getProperty();
|
||||||
|
Property targetId = activityDescTagLink.addLongProperty("tagId").notNull().getProperty();
|
||||||
|
|
||||||
|
activityDesc.addToMany(tag, activityDescTagLink, sourceId, targetId);
|
||||||
|
|
||||||
|
return activityDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Entity addUserInfo(Schema schema, Entity userAttributes) {
|
||||||
|
Entity user = addEntity(schema, "User");
|
||||||
|
user.addIdProperty();
|
||||||
|
user.addStringProperty("name").notNull();
|
||||||
|
user.addDateProperty("birthday").notNull();
|
||||||
|
user.addIntProperty("gender").notNull();
|
||||||
|
Property userId = userAttributes.addLongProperty("userId").notNull().getProperty();
|
||||||
|
|
||||||
|
// sorted by the from-date, newest first
|
||||||
|
Property userAttributesSortProperty = getPropertyByName(userAttributes, VALID_FROM_UTC);
|
||||||
|
user.addToMany(userAttributes, userId).orderDesc(userAttributesSortProperty);
|
||||||
|
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Property getPropertyByName(Entity entity, String propertyName) {
|
||||||
|
for (Property prop : entity.getProperties()) {
|
||||||
|
if (propertyName.equals(prop.getPropertyName())) {
|
||||||
|
return prop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Could not find property " + propertyName + " in entity " + entity.getClassName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Entity addUserAttributes(Schema schema) {
|
||||||
|
// additional properties of a user, which may change during the lifetime of a user
|
||||||
|
// this allows changing attributes while preserving user identity
|
||||||
|
Entity userAttributes = addEntity(schema, "UserAttributes");
|
||||||
|
userAttributes.addIdProperty();
|
||||||
|
userAttributes.addIntProperty("heightCM").notNull();
|
||||||
|
userAttributes.addIntProperty("weightKG").notNull();
|
||||||
|
userAttributes.addIntProperty("sleepGoalHPD").javaDocGetterAndSetter("Desired number of hours of sleep per day.");
|
||||||
|
userAttributes.addIntProperty("stepsGoalSPD").javaDocGetterAndSetter("Desired number of steps per day.");
|
||||||
|
addDateValidityTo(userAttributes);
|
||||||
|
|
||||||
|
return userAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addDateValidityTo(Entity entity) {
|
||||||
|
entity.addDateProperty(VALID_FROM_UTC).codeBeforeGetter(OVERRIDE);
|
||||||
|
entity.addDateProperty(VALID_TO_UTC).codeBeforeGetter(OVERRIDE);
|
||||||
|
|
||||||
|
entity.implementsInterface(VALID_BY_DATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Entity addDevice(Schema schema, Entity deviceAttributes) {
|
||||||
|
Entity device = addEntity(schema, "Device");
|
||||||
|
device.addIdProperty();
|
||||||
|
device.addStringProperty("name").notNull();
|
||||||
|
device.addStringProperty("manufacturer").notNull();
|
||||||
|
device.addStringProperty("identifier").notNull().unique().javaDocGetterAndSetter("The fixed identifier, i.e. MAC address of the device.");
|
||||||
|
device.addIntProperty("type").notNull().javaDocGetterAndSetter("The DeviceType key, i.e. the GBDevice's type.");
|
||||||
|
device.addStringProperty("model").javaDocGetterAndSetter("An optional model, further specifying the kind of device-");
|
||||||
|
Property deviceId = deviceAttributes.addLongProperty("deviceId").notNull().getProperty();
|
||||||
|
// sorted by the from-date, newest first
|
||||||
|
Property deviceAttributesSortProperty = getPropertyByName(deviceAttributes, VALID_FROM_UTC);
|
||||||
|
device.addToMany(deviceAttributes, deviceId).orderDesc(deviceAttributesSortProperty);
|
||||||
|
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Entity addDeviceAttributes(Schema schema) {
|
||||||
|
Entity deviceAttributes = addEntity(schema, "DeviceAttributes");
|
||||||
|
deviceAttributes.addIdProperty();
|
||||||
|
deviceAttributes.addStringProperty("firmwareVersion1").notNull();
|
||||||
|
deviceAttributes.addStringProperty("firmwareVersion2");
|
||||||
|
addDateValidityTo(deviceAttributes);
|
||||||
|
|
||||||
|
return deviceAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Entity addMiBandActivitySample(Schema schema, Entity user, Entity device) {
|
||||||
|
Entity activitySample = addEntity(schema, "MiBandActivitySample");
|
||||||
|
activitySample.implementsSerializable();
|
||||||
|
addCommonActivitySampleProperties("AbstractActivitySample", activitySample, user, device);
|
||||||
|
activitySample.addIntProperty(SAMPLE_RAW_INTENSITY).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||||
|
activitySample.addIntProperty(SAMPLE_STEPS).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||||
|
activitySample.addIntProperty(SAMPLE_RAW_KIND).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||||
|
addHeartRateProperties(activitySample);
|
||||||
|
return activitySample;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addHeartRateProperties(Entity activitySample) {
|
||||||
|
activitySample.addIntProperty(SAMPLE_HEART_RATE).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Entity addPebbleHealthActivitySample(Schema schema, Entity user, Entity device) {
|
||||||
|
Entity activitySample = addEntity(schema, "PebbleHealthActivitySample");
|
||||||
|
addCommonActivitySampleProperties("AbstractPebbleHealthActivitySample", activitySample, user, device);
|
||||||
|
activitySample.addByteArrayProperty("rawPebbleHealthData").codeBeforeGetter(OVERRIDE);
|
||||||
|
activitySample.addIntProperty(SAMPLE_RAW_INTENSITY).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||||
|
activitySample.addIntProperty(SAMPLE_STEPS).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||||
|
addHeartRateProperties(activitySample);
|
||||||
|
return activitySample;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Entity addPebbleHealthActivityKindOverlay(Schema schema, Entity user, Entity device) {
|
||||||
|
Entity activityOverlay = addEntity(schema, "PebbleHealthActivityOverlay");
|
||||||
|
|
||||||
|
activityOverlay.addIntProperty(TIMESTAMP_FROM).notNull().primaryKey();
|
||||||
|
activityOverlay.addIntProperty(TIMESTAMP_TO).notNull().primaryKey();
|
||||||
|
activityOverlay.addIntProperty(SAMPLE_RAW_KIND).notNull().primaryKey();
|
||||||
|
Property deviceId = activityOverlay.addLongProperty("deviceId").primaryKey().notNull().getProperty();
|
||||||
|
activityOverlay.addToOne(device, deviceId);
|
||||||
|
|
||||||
|
Property userId = activityOverlay.addLongProperty("userId").notNull().getProperty();
|
||||||
|
activityOverlay.addToOne(user, userId);
|
||||||
|
activityOverlay.addByteArrayProperty("rawPebbleHealthData");
|
||||||
|
|
||||||
|
return activityOverlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Entity addPebbleMisfitActivitySample(Schema schema, Entity user, Entity device) {
|
||||||
|
Entity activitySample = addEntity(schema, "PebbleMisfitSample");
|
||||||
|
addCommonActivitySampleProperties("AbstractPebbleMisfitActivitySample", activitySample, user, device);
|
||||||
|
activitySample.addIntProperty("rawPebbleMisfitSample").notNull().codeBeforeGetter(OVERRIDE);
|
||||||
|
return activitySample;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Entity addPebbleMorpheuzActivitySample(Schema schema, Entity user, Entity device) {
|
||||||
|
Entity activitySample = addEntity(schema, "PebbleMorpheuzSample");
|
||||||
|
addCommonActivitySampleProperties("AbstractPebbleMorpheuzActivitySample", activitySample, user, device);
|
||||||
|
activitySample.addIntProperty(SAMPLE_RAW_INTENSITY).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||||
|
return activitySample;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Entity addHPlusHealthActivitySample(Schema schema, Entity user, Entity device) {
|
||||||
|
Entity activitySample = addEntity(schema, "HPlusHealthActivitySample");
|
||||||
|
activitySample.implementsSerializable();
|
||||||
|
addCommonActivitySampleProperties("AbstractActivitySample", activitySample, user, device);
|
||||||
|
activitySample.addByteArrayProperty("rawHPlusHealthData");
|
||||||
|
activitySample.addIntProperty(SAMPLE_RAW_KIND).notNull().primaryKey();
|
||||||
|
activitySample.addIntProperty(SAMPLE_RAW_INTENSITY).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||||
|
activitySample.addIntProperty(SAMPLE_STEPS).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||||
|
addHeartRateProperties(activitySample);
|
||||||
|
activitySample.addIntProperty("distance");
|
||||||
|
activitySample.addIntProperty("calories");
|
||||||
|
|
||||||
|
return activitySample;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Entity addHPlusHealthActivityKindOverlay(Schema schema, Entity user, Entity device) {
|
||||||
|
Entity activityOverlay = addEntity(schema, "HPlusHealthActivityOverlay");
|
||||||
|
|
||||||
|
activityOverlay.addIntProperty(TIMESTAMP_FROM).notNull().primaryKey();
|
||||||
|
activityOverlay.addIntProperty(TIMESTAMP_TO).notNull().primaryKey();
|
||||||
|
activityOverlay.addIntProperty(SAMPLE_RAW_KIND).notNull().primaryKey();
|
||||||
|
Property deviceId = activityOverlay.addLongProperty("deviceId").primaryKey().notNull().getProperty();
|
||||||
|
activityOverlay.addToOne(device, deviceId);
|
||||||
|
|
||||||
|
Property userId = activityOverlay.addLongProperty("userId").notNull().getProperty();
|
||||||
|
activityOverlay.addToOne(user, userId);
|
||||||
|
activityOverlay.addByteArrayProperty("rawHPlusHealthData");
|
||||||
|
return activityOverlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Entity addNo1F1ActivitySample(Schema schema, Entity user, Entity device) {
|
||||||
|
Entity activitySample = addEntity(schema, "No1F1ActivitySample");
|
||||||
|
activitySample.implementsSerializable();
|
||||||
|
addCommonActivitySampleProperties("AbstractActivitySample", activitySample, user, device);
|
||||||
|
activitySample.addIntProperty(SAMPLE_STEPS).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||||
|
activitySample.addIntProperty(SAMPLE_RAW_KIND).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||||
|
activitySample.addIntProperty(SAMPLE_RAW_INTENSITY).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||||
|
addHeartRateProperties(activitySample);
|
||||||
|
return activitySample;
|
||||||
|
}
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
|
private static Entity addZeTimeActivitySample(Schema schema, Entity user, Entity device) {
|
||||||
|
Entity activitySample = addEntity(schema, "ZeTimeActivitySample");
|
||||||
|
=======
|
||||||
|
private static Entity addXWatchActivitySample(Schema schema, Entity user, Entity device) {
|
||||||
|
Entity activitySample = addEntity(schema, "XWatchActivitySample");
|
||||||
|
>>>>>>> master
|
||||||
|
activitySample.implementsSerializable();
|
||||||
|
addCommonActivitySampleProperties("AbstractActivitySample", activitySample, user, device);
|
||||||
|
activitySample.addIntProperty(SAMPLE_STEPS).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||||
|
activitySample.addIntProperty(SAMPLE_RAW_KIND).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||||
|
activitySample.addIntProperty(SAMPLE_RAW_INTENSITY).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||||
|
addHeartRateProperties(activitySample);
|
||||||
|
return activitySample;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addCommonActivitySampleProperties(String superClass, Entity activitySample, Entity user, Entity device) {
|
||||||
|
activitySample.setSuperclass(superClass);
|
||||||
|
activitySample.addImport(MAIN_PACKAGE + ".devices.SampleProvider");
|
||||||
|
activitySample.setJavaDoc(
|
||||||
|
"This class represents a sample specific to the device. Values like activity kind or\n" +
|
||||||
|
"intensity, are device specific. Normalized values can be retrieved through the\n" +
|
||||||
|
"corresponding {@link SampleProvider}.");
|
||||||
|
activitySample.addIntProperty("timestamp").notNull().codeBeforeGetterAndSetter(OVERRIDE).primaryKey();
|
||||||
|
Property deviceId = activitySample.addLongProperty("deviceId").primaryKey().notNull().codeBeforeGetterAndSetter(OVERRIDE).getProperty();
|
||||||
|
activitySample.addToOne(device, deviceId);
|
||||||
|
Property userId = activitySample.addLongProperty("userId").notNull().codeBeforeGetterAndSetter(OVERRIDE).getProperty();
|
||||||
|
activitySample.addToOne(user, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addCalendarSyncState(Schema schema, Entity device) {
|
||||||
|
Entity calendarSyncState = addEntity(schema, "CalendarSyncState");
|
||||||
|
calendarSyncState.addIdProperty();
|
||||||
|
Property deviceId = calendarSyncState.addLongProperty("deviceId").notNull().getProperty();
|
||||||
|
Property calendarEntryId = calendarSyncState.addLongProperty("calendarEntryId").notNull().getProperty();
|
||||||
|
Index indexUnique = new Index();
|
||||||
|
indexUnique.addProperty(deviceId);
|
||||||
|
indexUnique.addProperty(calendarEntryId);
|
||||||
|
indexUnique.makeUnique();
|
||||||
|
calendarSyncState.addIndex(indexUnique);
|
||||||
|
calendarSyncState.addToOne(device, deviceId);
|
||||||
|
calendarSyncState.addIntProperty("hash").notNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addBipActivitySummary(Schema schema, Entity user, Entity device) {
|
||||||
|
Entity summary = addEntity(schema, "BaseActivitySummary");
|
||||||
|
summary.implementsInterface(ACTIVITY_SUMMARY);
|
||||||
|
summary.addIdProperty();
|
||||||
|
|
||||||
|
summary.setJavaDoc(
|
||||||
|
"This class represents the summary of a user's activity event. I.e. a walk, hike, a bicycle tour, etc.");
|
||||||
|
|
||||||
|
summary.addStringProperty("name").codeBeforeGetter(OVERRIDE);
|
||||||
|
summary.addDateProperty("startTime").notNull().codeBeforeGetter(OVERRIDE);
|
||||||
|
summary.addDateProperty("endTime").notNull().codeBeforeGetter(OVERRIDE);
|
||||||
|
summary.addIntProperty("activityKind").notNull().codeBeforeGetter(OVERRIDE);
|
||||||
|
|
||||||
|
summary.addIntProperty("baseLongitude").javaDocGetterAndSetter("Temporary, bip-specific");
|
||||||
|
summary.addIntProperty("baseLatitude").javaDocGetterAndSetter("Temporary, bip-specific");
|
||||||
|
summary.addIntProperty("baseAltitude").javaDocGetterAndSetter("Temporary, bip-specific");
|
||||||
|
|
||||||
|
summary.addStringProperty("gpxTrack").codeBeforeGetter(OVERRIDE);
|
||||||
|
|
||||||
|
Property deviceId = summary.addLongProperty("deviceId").notNull().codeBeforeGetter(OVERRIDE).getProperty();
|
||||||
|
summary.addToOne(device, deviceId);
|
||||||
|
Property userId = summary.addLongProperty("userId").notNull().codeBeforeGetter(OVERRIDE).getProperty();
|
||||||
|
summary.addToOne(user, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Property findProperty(Entity entity, String propertyName) {
|
||||||
|
for (Property prop : entity.getProperties()) {
|
||||||
|
if (propertyName.equals(prop.getPropertyName())) {
|
||||||
|
return prop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Property " + propertyName + " not found in Entity " + entity.getClassName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Entity addEntity(Schema schema, String className) {
|
||||||
|
Entity entity = schema.addEntity(className);
|
||||||
|
entity.addImport("de.greenrobot.dao.AbstractDao");
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
}
|
@ -9,7 +9,7 @@ vendor's servers.
|
|||||||
|
|
||||||
[Homepage](https://gadgetbridge.org)
|
[Homepage](https://gadgetbridge.org)
|
||||||
|
|
||||||
[Blog](https://blog.gadgetbridge.org)
|
[Blog](https://blog.freeyourgadget.org)
|
||||||
|
|
||||||
[![Donate](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/Gadgetbridge/donate)
|
[![Donate](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/Gadgetbridge/donate)
|
||||||
|
|
||||||
@ -33,6 +33,7 @@ vendor's servers.
|
|||||||
* NO.1 F1 (WIP)
|
* NO.1 F1 (WIP)
|
||||||
* Liveview
|
* Liveview
|
||||||
* Vibratissimo (experimental)
|
* Vibratissimo (experimental)
|
||||||
|
* XWatch (Affordable Chinese Casio-like smartwatches)
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
@ -94,7 +95,7 @@ For more information read [this wiki article](https://github.com/Freeyourgadget/
|
|||||||
|
|
||||||
## Contribute
|
## Contribute
|
||||||
|
|
||||||
Contributions are welcome, be it feedback, bugreports, documentation, translation, research or code. Feel free to work
|
Contributions are welcome, be it feedback, bug reports, documentation, translation, research or code. Feel free to work
|
||||||
on any of the open [issues](https://github.com/Freeyourgadget/Gadgetbridge/issues?q=is%3Aopen+is%3Aissue);
|
on any of the open [issues](https://github.com/Freeyourgadget/Gadgetbridge/issues?q=is%3Aopen+is%3Aissue);
|
||||||
just leave a comment that you're working on one to avoid duplicated work.
|
just leave a comment that you're working on one to avoid duplicated work.
|
||||||
|
|
||||||
|
138
app/build.gradle
138
app/build.gradle
@ -1,14 +1,13 @@
|
|||||||
|
apply plugin: "com.android.application"
|
||||||
|
apply plugin: "findbugs"
|
||||||
|
apply plugin: "pmd"
|
||||||
|
|
||||||
apply plugin: 'com.android.application'
|
def ABORT_ON_CHECK_FAILURE = false
|
||||||
apply plugin: 'findbugs'
|
|
||||||
apply plugin: 'pmd'
|
|
||||||
|
|
||||||
def ABORT_ON_CHECK_FAILURE=false
|
|
||||||
|
|
||||||
tasks.withType(Test) {
|
tasks.withType(Test) {
|
||||||
systemProperty 'MiFirmwareDir', System.getProperty('MiFirmwareDir', null)
|
systemProperty "MiFirmwareDir", System.getProperty("MiFirmwareDir", null)
|
||||||
systemProperty 'logback.configurationFile', System.getProperty('user.dir', null) + '/app/src/main/assets/logback.xml'
|
systemProperty "logback.configurationFile", System.getProperty("user.dir", null) + "/app/src/main/assets/logback.xml"
|
||||||
systemProperty 'GB_LOGFILES_DIR', java.nio.file.Files.createTempDirectory('gblog').toString();
|
systemProperty "GB_LOGFILES_DIR", java.nio.file.Files.createTempDirectory("gblog").toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
@ -17,112 +16,115 @@ android {
|
|||||||
sourceCompatibility JavaVersion.VERSION_1_7
|
sourceCompatibility JavaVersion.VERSION_1_7
|
||||||
targetCompatibility JavaVersion.VERSION_1_7
|
targetCompatibility JavaVersion.VERSION_1_7
|
||||||
}
|
}
|
||||||
compileSdkVersion 25
|
compileSdkVersion 27
|
||||||
buildToolsVersion '26.0.2'
|
buildToolsVersion "27.0.3"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "nodomain.freeyourgadget.gadgetbridge"
|
applicationId "nodomain.freeyourgadget.gadgetbridge"
|
||||||
minSdkVersion 19
|
minSdkVersion 19
|
||||||
targetSdkVersion 25
|
targetSdkVersion 27
|
||||||
|
|
||||||
// note: always bump BOTH versionCode and versionName!
|
// Note: always bump BOTH versionCode and versionName!
|
||||||
versionName "0.24.3"
|
versionName "0.27.0"
|
||||||
versionCode 120
|
versionCode 132
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
minifyEnabled false
|
minifyEnabled false
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lintOptions {
|
lintOptions {
|
||||||
abortOnError ABORT_ON_CHECK_FAILURE
|
abortOnError ABORT_ON_CHECK_FAILURE
|
||||||
lintConfig file("${project.rootDir}/config/lint/lint.xml")
|
lintConfig file("${project.rootDir}/config/lint/lint.xml")
|
||||||
|
// If true, generate an HTML report (with issue explanations, sourcecode, etc)
|
||||||
// if true, generate an HTML report (with issue explanations, sourcecode, etc)
|
|
||||||
htmlReport true
|
htmlReport true
|
||||||
// optional path to report (default will be lint-results.html in the builddir)
|
// Optional path to report (default will be lint-results.html in the builddir)
|
||||||
htmlOutput file("$project.buildDir/reports/lint/lint.html")
|
htmlOutput file("$project.buildDir/reports/lint/lint.html")
|
||||||
}
|
}
|
||||||
|
|
||||||
testOptions {
|
testOptions {
|
||||||
unitTests.returnDefaultValues = true
|
unitTests {
|
||||||
|
returnDefaultValues = true
|
||||||
|
includeAndroidResources = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pmd {
|
pmd {
|
||||||
toolVersion = '5.5.5'
|
toolVersion = "5.5.5"
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// testCompile 'ch.qos.logback:logback-classic:1.1.3'
|
// testImplementation "ch.qos.logback:logback-classic:1.1.3"
|
||||||
// testCompile 'ch.qos.logback:logback-core:1.1.3'
|
// testImplementation "ch.qos.logback:logback-core:1.1.3"
|
||||||
testCompile 'junit:junit:4.12'
|
testImplementation "junit:junit:4.12"
|
||||||
testCompile "org.mockito:mockito-core:1.10.19"
|
testImplementation "org.mockito:mockito-core:1.10.19"
|
||||||
testCompile "org.robolectric:robolectric:3.5.1"
|
testImplementation "org.robolectric:robolectric:3.6.1"
|
||||||
|
|
||||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||||
compile 'com.android.support:appcompat-v7:25.4.0'
|
implementation "com.android.support:appcompat-v7:27.1.1"
|
||||||
compile 'com.android.support:cardview-v7:25.4.0'
|
implementation "com.android.support:cardview-v7:27.1.1"
|
||||||
compile 'com.android.support:recyclerview-v7:25.4.0'
|
implementation "com.android.support:recyclerview-v7:27.1.1"
|
||||||
compile 'com.android.support:support-v4:25.4.0'
|
implementation "com.android.support:support-v4:27.1.1"
|
||||||
compile 'com.android.support:gridlayout-v7:25.4.0'
|
implementation "com.android.support:gridlayout-v7:27.1.1"
|
||||||
compile 'com.android.support:design:25.4.0'
|
implementation "com.android.support:design:27.1.1"
|
||||||
compile 'com.android.support:palette-v7:25.4.0'
|
implementation "com.android.support:palette-v7:27.1.1"
|
||||||
compile('com.github.tony19:logback-android-classic:1.1.1-6') {
|
implementation("com.github.tony19:logback-android-classic:1.1.1-6") {
|
||||||
exclude group: 'com.google.android', module: 'android'
|
exclude group: "com.google.android", module: "android"
|
||||||
}
|
}
|
||||||
compile 'org.slf4j:slf4j-api:1.7.12'
|
implementation "org.slf4j:slf4j-api:1.7.12"
|
||||||
compile 'com.github.Freeyourgadget:MPAndroidChart:5e5bd6c1d3e95c515d4853647ae554e48ee1d593'
|
implementation "com.github.Freeyourgadget:MPAndroidChart:5e5bd6c1d3e95c515d4853647ae554e48ee1d593"
|
||||||
compile 'com.github.pfichtner:durationformatter:0.1.1'
|
implementation "com.github.pfichtner:durationformatter:0.1.1"
|
||||||
compile 'de.cketti.library.changelog:ckchangelog:1.2.2'
|
implementation "de.cketti.library.changelog:ckchangelog:1.2.2"
|
||||||
compile 'net.e175.klaus:solarpositioning:0.0.9'
|
implementation "net.e175.klaus:solarpositioning:0.0.9"
|
||||||
// use pristine greendao instead of our custom version, since our custom jitpack-packaged
|
// use pristine greendao instead of our custom version, since our custom jitpack-packaged
|
||||||
// version contains way too much and our custom patches are in the generator only.
|
// version contains way too much and our custom patches are in the generator only.
|
||||||
compile 'org.greenrobot:greendao:2.2.1'
|
implementation "org.greenrobot:greendao:2.2.1"
|
||||||
compile 'org.apache.commons:commons-lang3:3.5'
|
implementation "org.apache.commons:commons-lang3:3.5"
|
||||||
compile 'org.cyanogenmod:platform.sdk:6.0'
|
implementation "org.cyanogenmod:platform.sdk:6.0"
|
||||||
|
|
||||||
// compile project(":DaoCore")
|
// implementation project(":DaoCore")
|
||||||
}
|
}
|
||||||
|
|
||||||
preBuild.dependsOn(":GBDaoGenerator:genSources")
|
preBuild.dependsOn(":GBDaoGenerator:genSources")
|
||||||
|
|
||||||
gradle.beforeProject {
|
gradle.beforeProject {
|
||||||
preBuild.dependsOn(":GBDaoGenerator:genSources")
|
preBuild.dependsOn(":GBDaoGenerator:genSources")
|
||||||
}
|
}
|
||||||
|
|
||||||
check.dependsOn 'findbugs', 'pmd', 'lint'
|
check.dependsOn "findbugs", "pmd", "lint"
|
||||||
|
|
||||||
task pmd(type: Pmd) {
|
task pmd(type: Pmd) {
|
||||||
ruleSetFiles = files("${project.rootDir}/config/pmd/pmd-ruleset.xml")
|
ruleSetFiles = files("${project.rootDir}/config/pmd/pmd-ruleset.xml")
|
||||||
ignoreFailures = !ABORT_ON_CHECK_FAILURE
|
ignoreFailures = !ABORT_ON_CHECK_FAILURE
|
||||||
ruleSets = [
|
ruleSets = [
|
||||||
'java-android',
|
"java-android",
|
||||||
'java-basic',
|
"java-basic",
|
||||||
'java-braces',
|
"java-braces",
|
||||||
'java-clone',
|
"java-clone",
|
||||||
'java-codesize',
|
"java-codesize",
|
||||||
'java-controversial',
|
"java-controversial",
|
||||||
'java-coupling',
|
"java-coupling",
|
||||||
'java-design',
|
"java-design",
|
||||||
'java-empty',
|
"java-empty",
|
||||||
'java-finalizers',
|
"java-finalizers",
|
||||||
'java-imports',
|
"java-imports",
|
||||||
'java-junit',
|
"java-junit",
|
||||||
'java-optimizations',
|
"java-optimizations",
|
||||||
'java-strictexception',
|
"java-strictexception",
|
||||||
'java-strings',
|
"java-strings",
|
||||||
'java-sunsecure',
|
"java-sunsecure",
|
||||||
'java-typeresolution',
|
"java-typeresolution",
|
||||||
'java-unnecessary',
|
"java-unnecessary",
|
||||||
'java-unusedcode'
|
"java-unusedcode"
|
||||||
]
|
]
|
||||||
|
|
||||||
source 'src'
|
source "src"
|
||||||
include '**/*.java'
|
include "**/*.java"
|
||||||
exclude '**/gen/**'
|
exclude "**/gen/**"
|
||||||
|
|
||||||
reports {
|
reports {
|
||||||
xml.enabled = false
|
xml.enabled = false
|
||||||
@ -142,7 +144,7 @@ task findbugs(type: FindBugs) {
|
|||||||
reportLevel = "medium"
|
reportLevel = "medium"
|
||||||
excludeFilter = new File("${project.rootDir}/config/findbugs/findbugs-filter.xml")
|
excludeFilter = new File("${project.rootDir}/config/findbugs/findbugs-filter.xml")
|
||||||
classes = files("${project.rootDir}/app/build/intermediates/classes")
|
classes = files("${project.rootDir}/app/build/intermediates/classes")
|
||||||
source = fileTree('src/main/java/')
|
source = fileTree("src/main/java/")
|
||||||
classpath = files()
|
classpath = files()
|
||||||
reports {
|
reports {
|
||||||
xml.enabled = false
|
xml.enabled = false
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.READ_CALENDAR" />
|
<uses-permission android:name="android.permission.READ_CALENDAR" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
|
|
||||||
<uses-permission android:name="cyanogenmod.permission.ACCESS_WEATHER_MANAGER" />
|
<uses-permission android:name="cyanogenmod.permission.ACCESS_WEATHER_MANAGER" />
|
||||||
@ -37,7 +38,8 @@
|
|||||||
android:name=".GBApplication"
|
android:name=".GBApplication"
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
android:fullBackupContent="false"
|
android:fullBackupContent="false"
|
||||||
android:icon="@drawable/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/GadgetbridgeTheme">
|
android:theme="@style/GadgetbridgeTheme">
|
||||||
<activity
|
<activity
|
||||||
@ -58,6 +60,10 @@
|
|||||||
android:name=".devices.miband.MiBandPreferencesActivity"
|
android:name=".devices.miband.MiBandPreferencesActivity"
|
||||||
android:label="@string/preferences_miband_settings"
|
android:label="@string/preferences_miband_settings"
|
||||||
android:parentActivityName=".activities.SettingsActivity" />
|
android:parentActivityName=".activities.SettingsActivity" />
|
||||||
|
<activity
|
||||||
|
android:name=".activities.ActivitySummariesActivity"
|
||||||
|
android:label="@string/activity_summaries"
|
||||||
|
android:parentActivityName=".activities.ControlCenterv2" />
|
||||||
<activity
|
<activity
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:name=".activities.appmanager.AppManagerActivity"
|
android:name=".activities.appmanager.AppManagerActivity"
|
||||||
@ -414,7 +420,7 @@
|
|||||||
android:grantUriPermissions="true">
|
android:grantUriPermissions="true">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
android:resource="@xml/screenshot_provider_paths"/>
|
android:resource="@xml/shared_paths" />
|
||||||
</provider>
|
</provider>
|
||||||
|
|
||||||
<receiver android:name=".SleepAlarmWidget">
|
<receiver android:name=".SleepAlarmWidget">
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
Gobbetti, Normano64
|
Gobbetti, Martin, Normano64, Taavi Eomäe
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
@ -19,11 +19,17 @@ package nodomain.freeyourgadget.gadgetbridge;
|
|||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
|
import android.app.NotificationChannel;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.app.NotificationManager.Policy;
|
import android.app.NotificationManager.Policy;
|
||||||
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
@ -52,6 +58,7 @@ import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.database.DBOpenHelper;
|
import nodomain.freeyourgadget.gadgetbridge.database.DBOpenHelper;
|
||||||
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.externalevents.BluetoothStateChangeReceiver;
|
||||||
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;
|
||||||
@ -64,6 +71,8 @@ import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue;
|
import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||||
|
|
||||||
|
import static nodomain.freeyourgadget.gadgetbridge.util.GB.NOTIFICATION_CHANNEL_ID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main Application class that initializes and provides access to certain things like
|
* Main Application class that initializes and provides access to certain things like
|
||||||
* logging and DB access.
|
* logging and DB access.
|
||||||
@ -109,6 +118,7 @@ public class GBApplication extends Application {
|
|||||||
private static Locale language;
|
private static Locale language;
|
||||||
|
|
||||||
private DeviceManager deviceManager;
|
private DeviceManager deviceManager;
|
||||||
|
private BluetoothStateChangeReceiver bluetoothStateChangeReceiver;
|
||||||
|
|
||||||
public static void quit() {
|
public static void quit() {
|
||||||
GB.log("Quitting Gadgetbridge...", GB.INFO, null);
|
GB.log("Quitting Gadgetbridge...", GB.INFO, null);
|
||||||
@ -166,12 +176,25 @@ public class GBApplication extends Application {
|
|||||||
setLanguage(language);
|
setLanguage(language);
|
||||||
|
|
||||||
deviceService = createDeviceService();
|
deviceService = createDeviceService();
|
||||||
loadAppsBlackList();
|
loadAppsNotifBlackList();
|
||||||
|
loadAppsPebbleBlackList();
|
||||||
loadCalendarsBlackList();
|
loadCalendarsBlackList();
|
||||||
|
|
||||||
if (isRunningMarshmallowOrLater()) {
|
if (isRunningMarshmallowOrLater()) {
|
||||||
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
//the following will ensure the notification manager is kept alive
|
//the following will ensure the notification manager is kept alive
|
||||||
|
if(isRunningOreoOrLater()) {
|
||||||
|
NotificationChannel channel = notificationManager.getNotificationChannel(NOTIFICATION_CHANNEL_ID);
|
||||||
|
if(channel == null) {
|
||||||
|
channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID,
|
||||||
|
getString(R.string.notification_channel_name),
|
||||||
|
NotificationManager.IMPORTANCE_LOW);
|
||||||
|
notificationManager.createNotificationChannel(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
bluetoothStateChangeReceiver = new BluetoothStateChangeReceiver();
|
||||||
|
registerReceiver(bluetoothStateChangeReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
|
||||||
|
}
|
||||||
startService(new Intent(this, NotificationCollectorMonitorService.class));
|
startService(new Intent(this, NotificationCollectorMonitorService.class));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -289,6 +312,13 @@ public class GBApplication extends Application {
|
|||||||
public static boolean isRunningMarshmallowOrLater() {
|
public static boolean isRunningMarshmallowOrLater() {
|
||||||
return VERSION.SDK_INT >= Build.VERSION_CODES.M;
|
return VERSION.SDK_INT >= Build.VERSION_CODES.M;
|
||||||
}
|
}
|
||||||
|
public static boolean isRunningNougatOrLater() {
|
||||||
|
return VERSION.SDK_INT >= Build.VERSION_CODES.N;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isRunningOreoOrLater(){
|
||||||
|
return VERSION.SDK_INT >= Build.VERSION_CODES.O;
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isPrioritySender(int prioritySenders, String number) {
|
private static boolean isPrioritySender(int prioritySenders, String number) {
|
||||||
if (prioritySenders == Policy.PRIORITY_SENDERS_ANY) {
|
if (prioritySenders == Policy.PRIORITY_SENDERS_ANY) {
|
||||||
@ -343,58 +373,119 @@ public class GBApplication extends Application {
|
|||||||
return NotificationManager.INTERRUPTION_FILTER_ALL;
|
return NotificationManager.INTERRUPTION_FILTER_ALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HashSet<String> apps_blacklist = null;
|
private static HashSet<String> apps_notification_blacklist = null;
|
||||||
|
|
||||||
public static boolean appIsBlacklisted(String packageName) {
|
public static boolean appIsNotifBlacklisted(String packageName) {
|
||||||
if (apps_blacklist == null) {
|
if (apps_notification_blacklist == null) {
|
||||||
GB.log("appIsBlacklisted: apps_blacklist is null!", GB.INFO, null);
|
GB.log("appIsNotifBlacklisted: apps_notification_blacklist is null!", GB.INFO, null);
|
||||||
}
|
}
|
||||||
return apps_blacklist != null && apps_blacklist.contains(packageName);
|
return apps_notification_blacklist != null && apps_notification_blacklist.contains(packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setAppsBlackList(Set<String> packageNames) {
|
public static void setAppsNotifBlackList(Set<String> packageNames) {
|
||||||
if (packageNames == null) {
|
if (packageNames == null) {
|
||||||
GB.log("Set null apps_blacklist", GB.INFO, null);
|
GB.log("Set null apps_notification_blacklist", GB.INFO, null);
|
||||||
apps_blacklist = new HashSet<>();
|
apps_notification_blacklist = new HashSet<>();
|
||||||
} else {
|
} else {
|
||||||
apps_blacklist = new HashSet<>(packageNames);
|
apps_notification_blacklist = new HashSet<>(packageNames);
|
||||||
}
|
}
|
||||||
GB.log("New apps_blacklist has " + apps_blacklist.size() + " entries", GB.INFO, null);
|
GB.log("New apps_notification_blacklist has " + apps_notification_blacklist.size() + " entries", GB.INFO, null);
|
||||||
saveAppsBlackList();
|
saveAppsNotifBlackList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void loadAppsBlackList() {
|
private static void loadAppsNotifBlackList() {
|
||||||
GB.log("Loading apps_blacklist", GB.INFO, null);
|
GB.log("Loading apps_notification_blacklist", GB.INFO, null);
|
||||||
apps_blacklist = (HashSet<String>) sharedPrefs.getStringSet(GBPrefs.PACKAGE_BLACKLIST, null);
|
apps_notification_blacklist = (HashSet<String>) sharedPrefs.getStringSet(GBPrefs.PACKAGE_BLACKLIST, null);
|
||||||
if (apps_blacklist == null) {
|
if (apps_notification_blacklist == null) {
|
||||||
apps_blacklist = new HashSet<>();
|
apps_notification_blacklist = new HashSet<>();
|
||||||
}
|
}
|
||||||
GB.log("Loaded apps_blacklist has " + apps_blacklist.size() + " entries", GB.INFO, null);
|
GB.log("Loaded apps_notification_blacklist has " + apps_notification_blacklist.size() + " entries", GB.INFO, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void saveAppsBlackList() {
|
private static void saveAppsNotifBlackList() {
|
||||||
GB.log("Saving apps_blacklist with " + apps_blacklist.size() + " entries", GB.INFO, null);
|
GB.log("Saving apps_notification_blacklist with " + apps_notification_blacklist.size() + " entries", GB.INFO, null);
|
||||||
SharedPreferences.Editor editor = sharedPrefs.edit();
|
SharedPreferences.Editor editor = sharedPrefs.edit();
|
||||||
if (apps_blacklist.isEmpty()) {
|
if (apps_notification_blacklist.isEmpty()) {
|
||||||
editor.putStringSet(GBPrefs.PACKAGE_BLACKLIST, null);
|
editor.putStringSet(GBPrefs.PACKAGE_BLACKLIST, null);
|
||||||
} else {
|
} else {
|
||||||
Prefs.putStringSet(editor, GBPrefs.PACKAGE_BLACKLIST, apps_blacklist);
|
Prefs.putStringSet(editor, GBPrefs.PACKAGE_BLACKLIST, apps_notification_blacklist);
|
||||||
}
|
}
|
||||||
editor.apply();
|
editor.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addAppToBlacklist(String packageName) {
|
public static void addAppToNotifBlacklist(String packageName) {
|
||||||
if (apps_blacklist.add(packageName)) {
|
if (apps_notification_blacklist.add(packageName)) {
|
||||||
saveAppsBlackList();
|
saveAppsNotifBlackList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static synchronized void removeFromAppsBlacklist(String packageName) {
|
public static synchronized void removeFromAppsNotifBlacklist(String packageName) {
|
||||||
GB.log("Removing from apps_blacklist: " + packageName, GB.INFO, null);
|
GB.log("Removing from apps_notification_blacklist: " + packageName, GB.INFO, null);
|
||||||
apps_blacklist.remove(packageName);
|
apps_notification_blacklist.remove(packageName);
|
||||||
saveAppsBlackList();
|
saveAppsNotifBlackList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static HashSet<String> apps_pebblemsg_blacklist = null;
|
||||||
|
|
||||||
|
public static boolean appIsPebbleBlacklisted(String sender) {
|
||||||
|
if (apps_pebblemsg_blacklist == null) {
|
||||||
|
GB.log("appIsPebbleBlacklisted: apps_pebblemsg_blacklist is null!", GB.INFO, null);
|
||||||
|
}
|
||||||
|
return apps_pebblemsg_blacklist != null && apps_pebblemsg_blacklist.contains(sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setAppsPebbleBlackList(Set<String> packageNames) {
|
||||||
|
if (packageNames == null) {
|
||||||
|
GB.log("Set null apps_pebblemsg_blacklist", GB.INFO, null);
|
||||||
|
apps_pebblemsg_blacklist = new HashSet<>();
|
||||||
|
} else {
|
||||||
|
apps_pebblemsg_blacklist = new HashSet<>(packageNames);
|
||||||
|
}
|
||||||
|
GB.log("New apps_pebblemsg_blacklist has " + apps_pebblemsg_blacklist.size() + " entries", GB.INFO, null);
|
||||||
|
saveAppsPebbleBlackList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void loadAppsPebbleBlackList() {
|
||||||
|
GB.log("Loading apps_pebblemsg_blacklist", GB.INFO, null);
|
||||||
|
apps_pebblemsg_blacklist = (HashSet<String>) sharedPrefs.getStringSet(GBPrefs.PACKAGE_PEBBLEMSG_BLACKLIST, null);
|
||||||
|
if (apps_pebblemsg_blacklist == null) {
|
||||||
|
apps_pebblemsg_blacklist = new HashSet<>();
|
||||||
|
}
|
||||||
|
GB.log("Loaded apps_pebblemsg_blacklist has " + apps_pebblemsg_blacklist.size() + " entries", GB.INFO, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void saveAppsPebbleBlackList() {
|
||||||
|
GB.log("Saving apps_pebblemsg_blacklist with " + apps_pebblemsg_blacklist.size() + " entries", GB.INFO, null);
|
||||||
|
SharedPreferences.Editor editor = sharedPrefs.edit();
|
||||||
|
if (apps_pebblemsg_blacklist.isEmpty()) {
|
||||||
|
editor.putStringSet(GBPrefs.PACKAGE_PEBBLEMSG_BLACKLIST, null);
|
||||||
|
} else {
|
||||||
|
Prefs.putStringSet(editor, GBPrefs.PACKAGE_PEBBLEMSG_BLACKLIST, apps_pebblemsg_blacklist);
|
||||||
|
}
|
||||||
|
editor.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addAppToPebbleBlacklist(String packageName) {
|
||||||
|
if (apps_pebblemsg_blacklist.add(packageNameToPebbleMsgSender(packageName))) {
|
||||||
|
saveAppsPebbleBlackList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized void removeFromAppsPebbleBlacklist(String packageName) {
|
||||||
|
GB.log("Removing from apps_pebblemsg_blacklist: " + packageName, GB.INFO, null);
|
||||||
|
apps_pebblemsg_blacklist.remove(packageNameToPebbleMsgSender(packageName));
|
||||||
|
saveAppsPebbleBlackList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String packageNameToPebbleMsgSender(String packageName) {
|
||||||
|
if ("eu.siacs.conversations".equals(packageName)){
|
||||||
|
return("Conversations");
|
||||||
|
} else if ("net.osmand.plus".equals(packageName)) {
|
||||||
|
return("OsmAnd");
|
||||||
|
}
|
||||||
|
return packageName;
|
||||||
|
}
|
||||||
|
|
||||||
private static HashSet<String> calendars_blacklist = null;
|
private static HashSet<String> calendars_blacklist = null;
|
||||||
|
|
||||||
public static boolean calendarIsBlacklisted(String calendarDisplayName) {
|
public static boolean calendarIsBlacklisted(String calendarDisplayName) {
|
||||||
@ -406,7 +497,7 @@ public class GBApplication extends Application {
|
|||||||
|
|
||||||
public static void setCalendarsBlackList(Set<String> calendarNames) {
|
public static void setCalendarsBlackList(Set<String> calendarNames) {
|
||||||
if (calendarNames == null) {
|
if (calendarNames == null) {
|
||||||
GB.log("Set null apps_blacklist", GB.INFO, null);
|
GB.log("Set null apps_notification_blacklist", GB.INFO, null);
|
||||||
calendars_blacklist = new HashSet<>();
|
calendars_blacklist = new HashSet<>();
|
||||||
} else {
|
} else {
|
||||||
calendars_blacklist = new HashSet<>(calendarNames);
|
calendars_blacklist = new HashSet<>(calendarNames);
|
||||||
@ -490,7 +581,7 @@ public class GBApplication extends Application {
|
|||||||
case 0:
|
case 0:
|
||||||
String legacyGender = sharedPrefs.getString("mi_user_gender", null);
|
String legacyGender = sharedPrefs.getString("mi_user_gender", null);
|
||||||
String legacyHeight = sharedPrefs.getString("mi_user_height_cm", null);
|
String legacyHeight = sharedPrefs.getString("mi_user_height_cm", null);
|
||||||
String legacyWeigth = sharedPrefs.getString("mi_user_weight_kg", null);
|
String legacyWeight = sharedPrefs.getString("mi_user_weight_kg", null);
|
||||||
String legacyYOB = sharedPrefs.getString("mi_user_year_of_birth", null);
|
String legacyYOB = sharedPrefs.getString("mi_user_year_of_birth", null);
|
||||||
if (legacyGender != null) {
|
if (legacyGender != null) {
|
||||||
int gender = "male".equals(legacyGender) ? 1 : "female".equals(legacyGender) ? 0 : 2;
|
int gender = "male".equals(legacyGender) ? 1 : "female".equals(legacyGender) ? 0 : 2;
|
||||||
@ -501,8 +592,8 @@ public class GBApplication extends Application {
|
|||||||
editor.putString(ActivityUser.PREF_USER_HEIGHT_CM, legacyHeight);
|
editor.putString(ActivityUser.PREF_USER_HEIGHT_CM, legacyHeight);
|
||||||
editor.remove("mi_user_height_cm");
|
editor.remove("mi_user_height_cm");
|
||||||
}
|
}
|
||||||
if (legacyWeigth != null) {
|
if (legacyWeight != null) {
|
||||||
editor.putString(ActivityUser.PREF_USER_WEIGHT_KG, legacyWeigth);
|
editor.putString(ActivityUser.PREF_USER_WEIGHT_KG, legacyWeight);
|
||||||
editor.remove("mi_user_weight_kg");
|
editor.remove("mi_user_weight_kg");
|
||||||
}
|
}
|
||||||
if (legacyYOB != null) {
|
if (legacyYOB != null) {
|
||||||
@ -591,4 +682,24 @@ public class GBApplication extends Application {
|
|||||||
public static Locale getLanguage() {
|
public static Locale getLanguage() {
|
||||||
return language;
|
return language;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getVersion() {
|
||||||
|
try {
|
||||||
|
return getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_META_DATA).versionName;
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
GB.log("Unable to determine Gadgetbridge's version", GB.WARN, e);
|
||||||
|
return "0.0.0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNameAndVersion() {
|
||||||
|
try {
|
||||||
|
ApplicationInfo appInfo = getPackageManager().getApplicationInfo(getContext().getPackageName(), PackageManager.GET_META_DATA);
|
||||||
|
PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_META_DATA);
|
||||||
|
return String.format("%s %s", appInfo.name, packageInfo.versionName);
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
GB.log("Unable to determine Gadgetbridge's name/version", GB.WARN, e);
|
||||||
|
return "Gadgetbridge";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2016-2017 Andreas Shimokawa, Carsten Pfeiffer
|
/* Copyright (C) 2016-2018 Andreas Shimokawa, Carsten Pfeiffer, Taavi Eomäe
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ import nodomain.freeyourgadget.gadgetbridge.entities.DaoMaster;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides lowlevel access to the database.
|
* Provides low-level access to the database.
|
||||||
*/
|
*/
|
||||||
public class LockHandler implements DBHandler {
|
public class LockHandler implements DBHandler {
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2016-2017 Carsten Pfeiffer
|
/* Copyright (C) 2016-2018 Carsten Pfeiffer, Daniele Gobbetti
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
@ -30,6 +30,7 @@ import ch.qos.logback.core.FileAppender;
|
|||||||
import ch.qos.logback.core.encoder.Encoder;
|
import ch.qos.logback.core.encoder.Encoder;
|
||||||
import ch.qos.logback.core.encoder.LayoutWrappingEncoder;
|
import ch.qos.logback.core.encoder.LayoutWrappingEncoder;
|
||||||
import ch.qos.logback.core.util.StatusPrinter;
|
import ch.qos.logback.core.util.StatusPrinter;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
|
||||||
public abstract class Logging {
|
public abstract class Logging {
|
||||||
public static final String PROP_LOGFILES_DIR = "GB_LOGFILES_DIR";
|
public static final String PROP_LOGFILES_DIR = "GB_LOGFILES_DIR";
|
||||||
@ -148,7 +149,7 @@ public abstract class Logging {
|
|||||||
}
|
}
|
||||||
StringBuilder builder = new StringBuilder(bytes.length * 5);
|
StringBuilder builder = new StringBuilder(bytes.length * 5);
|
||||||
for (byte b : bytes) {
|
for (byte b : bytes) {
|
||||||
builder.append(String.format("0x%2x", b));
|
builder.append(String.format("0x%02x", b));
|
||||||
builder.append(" ");
|
builder.append(" ");
|
||||||
}
|
}
|
||||||
return builder.toString().trim();
|
return builder.toString().trim();
|
||||||
@ -156,9 +157,7 @@ public abstract class Logging {
|
|||||||
|
|
||||||
public static void logBytes(Logger logger, byte[] value) {
|
public static void logBytes(Logger logger, byte[] value) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
for (byte b : value) {
|
logger.warn("DATA: " + GB.hexdump(value, 0, value.length));
|
||||||
logger.warn("DATA: " + String.format("0x%2x", b));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Carsten Pfeiffer
|
/* Copyright (C) 2015-2018 Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2016-2017 0nse, Carsten Pfeiffer
|
/* Copyright (C) 2016-2018 0nse, Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Carsten Pfeiffer
|
/* Copyright (C) 2015-2018 Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Lem Dulfo
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer, Lem Dulfo
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
Gobbetti, walkjivefly
|
Gobbetti, walkjivefly
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -0,0 +1,53 @@
|
|||||||
|
/* Copyright (C) 2017-2018 Andreas Shimokawa, Carsten Pfeiffer
|
||||||
|
|
||||||
|
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.activities;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.widget.ListView;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.adapter.AbstractItemAdapter;
|
||||||
|
|
||||||
|
public abstract class AbstractListActivity<T> extends AbstractGBActivity {
|
||||||
|
private AbstractItemAdapter<T> itemAdapter;
|
||||||
|
private ListView itemListView;
|
||||||
|
|
||||||
|
public void setItemAdapter(AbstractItemAdapter<T> itemAdapter) {
|
||||||
|
this.itemAdapter = itemAdapter;
|
||||||
|
itemListView.setAdapter(itemAdapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void refresh() {
|
||||||
|
this.itemAdapter.loadItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractItemAdapter<T> getItemAdapter() {
|
||||||
|
return itemAdapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ListView getItemListView() {
|
||||||
|
return itemListView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
setContentView(R.layout.activity_list);
|
||||||
|
itemListView = findViewById(R.id.itemListView);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Christian
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer, Christian
|
||||||
Fischer, Daniele Gobbetti, Lem Dulfo
|
Fischer, Daniele Gobbetti, Lem Dulfo
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
@ -0,0 +1,301 @@
|
|||||||
|
/* Copyright (C) 2017-2018 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
|
||||||
|
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.activities;
|
||||||
|
|
||||||
|
import android.app.DatePickerDialog;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.design.widget.FloatingActionButton;
|
||||||
|
import android.support.v4.content.FileProvider;
|
||||||
|
import android.support.v4.content.LocalBroadcastManager;
|
||||||
|
import android.support.v4.widget.SwipeRefreshLayout;
|
||||||
|
import android.util.SparseBooleanArray;
|
||||||
|
import android.view.ActionMode;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.AbsListView;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.DatePicker;
|
||||||
|
import android.widget.ListView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.adapter.ActivitySummariesAdapter;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummary;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.RecordedDataTypes;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.AndroidUtils;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
|
||||||
|
public class ActivitySummariesActivity extends AbstractListActivity<BaseActivitySummary> {
|
||||||
|
|
||||||
|
private GBDevice mGBDevice;
|
||||||
|
private SwipeRefreshLayout swipeLayout;
|
||||||
|
|
||||||
|
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
String action = intent.getAction();
|
||||||
|
switch (Objects.requireNonNull(action)) {
|
||||||
|
case GBDevice.ACTION_DEVICE_CHANGED:
|
||||||
|
GBDevice device = intent.getParcelableExtra(GBDevice.EXTRA_DEVICE);
|
||||||
|
mGBDevice = device;
|
||||||
|
if (device.isBusy()) {
|
||||||
|
swipeLayout.setRefreshing(true);
|
||||||
|
} else {
|
||||||
|
boolean wasBusy = swipeLayout.isRefreshing();
|
||||||
|
swipeLayout.setRefreshing(false);
|
||||||
|
if (wasBusy) {
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
super.onCreateOptionsMenu(menu);
|
||||||
|
|
||||||
|
getMenuInflater().inflate(R.menu.activity_list_menu, menu);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
boolean processed = false;
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case R.id.activity_action_manage_timestamp:
|
||||||
|
resetFetchTimestampToChosenDate();
|
||||||
|
processed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return processed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
Bundle extras = getIntent().getExtras();
|
||||||
|
if (extras != null) {
|
||||||
|
mGBDevice = extras.getParcelable(GBDevice.EXTRA_DEVICE);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Must provide a device when invoking this activity");
|
||||||
|
}
|
||||||
|
|
||||||
|
IntentFilter filterLocal = new IntentFilter();
|
||||||
|
filterLocal.addAction(GBDevice.ACTION_DEVICE_CHANGED);
|
||||||
|
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filterLocal);
|
||||||
|
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setItemAdapter(new ActivitySummariesAdapter(this, mGBDevice));
|
||||||
|
|
||||||
|
getItemListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||||
|
Object item = parent.getItemAtPosition(position);
|
||||||
|
if (item != null) {
|
||||||
|
ActivitySummary summary = (ActivitySummary) item;
|
||||||
|
|
||||||
|
String gpxTrack = summary.getGpxTrack();
|
||||||
|
if (gpxTrack != null) {
|
||||||
|
showTrack(gpxTrack);
|
||||||
|
} else {
|
||||||
|
GB.toast("This activity does not contain GPX tracks.", Toast.LENGTH_LONG, GB.INFO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
getItemListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
|
||||||
|
|
||||||
|
getItemListView().setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
|
||||||
|
@Override
|
||||||
|
public void onItemCheckedStateChanged(ActionMode actionMode, int position, long id, boolean checked) {
|
||||||
|
final int selectedItems = getItemListView().getCheckedItemCount();
|
||||||
|
actionMode.setTitle(selectedItems + " selected");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
|
||||||
|
getMenuInflater().inflate(R.menu.activity_list_context_menu, menu);
|
||||||
|
findViewById(R.id.fab).setVisibility(View.INVISIBLE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
|
||||||
|
boolean processed = false;
|
||||||
|
SparseBooleanArray checked = getItemListView().getCheckedItemPositions();
|
||||||
|
switch (menuItem.getItemId()) {
|
||||||
|
case R.id.activity_action_delete:
|
||||||
|
List<BaseActivitySummary> toDelete = new ArrayList<>();
|
||||||
|
for(int i = 0; i< checked.size(); i++) {
|
||||||
|
if (checked.valueAt(i)) {
|
||||||
|
toDelete.add(getItemAdapter().getItem(checked.keyAt(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deleteItems(toDelete);
|
||||||
|
processed = true;
|
||||||
|
break;
|
||||||
|
case R.id.activity_action_export:
|
||||||
|
List<String> paths = new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
|
for(int i = 0; i< checked.size(); i++) {
|
||||||
|
if (checked.valueAt(i)) {
|
||||||
|
|
||||||
|
BaseActivitySummary item = getItemAdapter().getItem(checked.keyAt(i));
|
||||||
|
if (item != null) {
|
||||||
|
ActivitySummary summary = (ActivitySummary) item;
|
||||||
|
|
||||||
|
String gpxTrack = summary.getGpxTrack();
|
||||||
|
if (gpxTrack != null) {
|
||||||
|
paths.add(gpxTrack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shareMultiple(paths);
|
||||||
|
processed = true;
|
||||||
|
break;
|
||||||
|
case R.id.activity_action_select_all:
|
||||||
|
for ( int i=0; i < getItemListView().getCount(); i++) {
|
||||||
|
getItemListView().setItemChecked(i, true);
|
||||||
|
}
|
||||||
|
return true; //don't finish actionmode in this case!
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
actionMode.finish();
|
||||||
|
return processed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroyActionMode(ActionMode actionMode) {
|
||||||
|
findViewById(R.id.fab).setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
swipeLayout = findViewById(R.id.list_activity_swipe_layout);
|
||||||
|
swipeLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
|
||||||
|
@Override
|
||||||
|
public void onRefresh() {
|
||||||
|
fetchTrackData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
FloatingActionButton fab = findViewById(R.id.fab);
|
||||||
|
fab.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
fetchTrackData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetFetchTimestampToChosenDate() {
|
||||||
|
final Calendar currentDate = Calendar.getInstance();
|
||||||
|
new DatePickerDialog(this, new DatePickerDialog.OnDateSetListener() {
|
||||||
|
@Override
|
||||||
|
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
|
||||||
|
Calendar date = Calendar.getInstance();
|
||||||
|
date.set(year, monthOfYear, dayOfMonth);
|
||||||
|
|
||||||
|
Long timestamp = date.getTimeInMillis() - 1000;
|
||||||
|
SharedPreferences.Editor editor = GBApplication.getPrefs().getPreferences().edit();
|
||||||
|
editor.remove(mGBDevice.getAddress() + "_" + "lastSportsActivityTimeMillis"); //FIXME: key reconstruction is BAD
|
||||||
|
editor.putLong(mGBDevice.getAddress() + "_" + "lastSportsActivityTimeMillis", timestamp);
|
||||||
|
editor.commit();
|
||||||
|
}
|
||||||
|
}, currentDate.get(Calendar.YEAR), currentDate.get(Calendar.MONTH), currentDate.get(Calendar.DATE)).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteItems(List<BaseActivitySummary> items) {
|
||||||
|
for(BaseActivitySummary item : items) {
|
||||||
|
item.delete();
|
||||||
|
getItemAdapter().remove(item);
|
||||||
|
}
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showTrack(String gpxTrack) {
|
||||||
|
try {
|
||||||
|
AndroidUtils.viewFile(gpxTrack, Intent.ACTION_VIEW, this);
|
||||||
|
} catch (IOException e) {
|
||||||
|
GB.toast(this, "Unable to display GPX track: " + e.getMessage(), Toast.LENGTH_LONG, GB.ERROR, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fetchTrackData() {
|
||||||
|
if (mGBDevice.isInitialized() && !mGBDevice.isBusy()) {
|
||||||
|
GBApplication.deviceService().onFetchRecordedData(RecordedDataTypes.TYPE_GPS_TRACKS);
|
||||||
|
} else {
|
||||||
|
swipeLayout.setRefreshing(false);
|
||||||
|
if (!mGBDevice.isInitialized()) {
|
||||||
|
GB.toast(this, getString(R.string.device_not_connected), Toast.LENGTH_SHORT, GB.ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void shareMultiple(List<String> paths){
|
||||||
|
|
||||||
|
ArrayList<Uri> uris = new ArrayList<>();
|
||||||
|
for(String path: paths){
|
||||||
|
File file = new File(path);
|
||||||
|
uris.add(FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".screenshot_provider", file));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(uris.size() > 0) {
|
||||||
|
final Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
|
||||||
|
intent.setType("application/gpx+xml");
|
||||||
|
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
|
||||||
|
startActivity(Intent.createChooser(intent, "SHARE"));
|
||||||
|
} else {
|
||||||
|
GB.toast(this, "No selected activity contains a GPX track to share", Toast.LENGTH_SHORT, GB.ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
Gobbetti, Lem Dulfo
|
Gobbetti, Lem Dulfo
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Lem Dulfo
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer, Lem Dulfo
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
Gobbetti, Lem Dulfo
|
Gobbetti, Lem Dulfo
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
@ -22,6 +22,8 @@ import android.support.v4.app.NavUtils;
|
|||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.support.v7.widget.SearchView;
|
import android.support.v7.widget.SearchView;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -64,12 +66,25 @@ public class AppBlacklistActivity extends AbstractGBActivity {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
MenuInflater inflater = getMenuInflater();
|
||||||
|
inflater.inflate(R.menu.app_blacklist_menu, menu);
|
||||||
|
return super.onCreateOptionsMenu(menu);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case android.R.id.home:
|
case android.R.id.home:
|
||||||
NavUtils.navigateUpFromSameTask(this);
|
NavUtils.navigateUpFromSameTask(this);
|
||||||
return true;
|
return true;
|
||||||
|
case R.id.blacklist_all_notif:
|
||||||
|
appBlacklistAdapter.blacklistAllNotif();
|
||||||
|
return true;
|
||||||
|
case R.id.whitelist_all_notif:
|
||||||
|
appBlacklistAdapter.whitelistAllNotif();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2017 Carsten Pfeiffer, Daniele Gobbetti
|
/* Copyright (C) 2017-2018 Carsten Pfeiffer, Daniele Gobbetti
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
Gobbetti, Lem Dulfo
|
Gobbetti, Lem Dulfo
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Copyright (C) 2016-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
/* Copyright (C) 2016-2018 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
Gobbetti
|
Gobbetti, Taavi Eomäe
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
@ -24,7 +24,6 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@ -42,15 +41,13 @@ import android.support.v7.app.AppCompatDelegate;
|
|||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import de.cketti.library.changelog.ChangeLog;
|
import de.cketti.library.changelog.ChangeLog;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
@ -72,9 +69,7 @@ public class ControlCenterv2 extends AppCompatActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private DeviceManager deviceManager;
|
private DeviceManager deviceManager;
|
||||||
private ImageView background;
|
|
||||||
|
|
||||||
private List<GBDevice> deviceList;
|
|
||||||
private GBDeviceAdapterv2 mGBDeviceAdapter;
|
private GBDeviceAdapterv2 mGBDeviceAdapter;
|
||||||
private RecyclerView deviceListView;
|
private RecyclerView deviceListView;
|
||||||
|
|
||||||
@ -84,7 +79,7 @@ public class ControlCenterv2 extends AppCompatActivity
|
|||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
String action = intent.getAction();
|
String action = intent.getAction();
|
||||||
switch (action) {
|
switch (Objects.requireNonNull(action)) {
|
||||||
case GBApplication.ACTION_LANGUAGE_CHANGE:
|
case GBApplication.ACTION_LANGUAGE_CHANGE:
|
||||||
setLanguage(GBApplication.getLanguage(), true);
|
setLanguage(GBApplication.getLanguage(), true);
|
||||||
break;
|
break;
|
||||||
@ -104,10 +99,10 @@ public class ControlCenterv2 extends AppCompatActivity
|
|||||||
|
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_controlcenterv2);
|
setContentView(R.layout.activity_controlcenterv2);
|
||||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||||
setSupportActionBar(toolbar);
|
setSupportActionBar(toolbar);
|
||||||
|
|
||||||
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
|
FloatingActionButton fab = findViewById(R.id.fab);
|
||||||
fab.setOnClickListener(new View.OnClickListener() {
|
fab.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
@ -115,28 +110,29 @@ public class ControlCenterv2 extends AppCompatActivity
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
|
DrawerLayout drawer = findViewById(R.id.drawer_layout);
|
||||||
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
|
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
|
||||||
this, drawer, toolbar, R.string.controlcenter_navigation_drawer_open, R.string.controlcenter_navigation_drawer_close);
|
this, drawer, toolbar, R.string.controlcenter_navigation_drawer_open, R.string.controlcenter_navigation_drawer_close);
|
||||||
drawer.setDrawerListener(toggle);
|
drawer.setDrawerListener(toggle);
|
||||||
toggle.syncState();
|
toggle.syncState();
|
||||||
|
|
||||||
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
|
NavigationView navigationView = findViewById(R.id.nav_view);
|
||||||
navigationView.setNavigationItemSelectedListener(this);
|
navigationView.setNavigationItemSelectedListener(this);
|
||||||
|
|
||||||
//end of material design boilerplate
|
//end of material design boilerplate
|
||||||
deviceManager = ((GBApplication) getApplication()).getDeviceManager();
|
deviceManager = ((GBApplication) getApplication()).getDeviceManager();
|
||||||
|
|
||||||
deviceListView = (RecyclerView) findViewById(R.id.deviceListView);
|
deviceListView = findViewById(R.id.deviceListView);
|
||||||
deviceListView.setHasFixedSize(true);
|
deviceListView.setHasFixedSize(true);
|
||||||
deviceListView.setLayoutManager(new LinearLayoutManager(this));
|
deviceListView.setLayoutManager(new LinearLayoutManager(this));
|
||||||
background = (ImageView) findViewById(R.id.no_items_bg);
|
|
||||||
|
|
||||||
deviceList = deviceManager.getDevices();
|
List<GBDevice> deviceList = deviceManager.getDevices();
|
||||||
mGBDeviceAdapter = new GBDeviceAdapterv2(this, deviceList);
|
mGBDeviceAdapter = new GBDeviceAdapterv2(this, deviceList);
|
||||||
|
|
||||||
deviceListView.setAdapter(this.mGBDeviceAdapter);
|
deviceListView.setAdapter(this.mGBDeviceAdapter);
|
||||||
|
|
||||||
|
/* uncomment to enable fixed-swipe to reveal more actions
|
||||||
|
|
||||||
ItemTouchHelper swipeToDismissTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(
|
ItemTouchHelper swipeToDismissTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(
|
||||||
ItemTouchHelper.LEFT , ItemTouchHelper.RIGHT) {
|
ItemTouchHelper.LEFT , ItemTouchHelper.RIGHT) {
|
||||||
@Override
|
@Override
|
||||||
@ -167,9 +163,8 @@ public class ControlCenterv2 extends AppCompatActivity
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//uncomment to enable fixed-swipe to reveal more actions
|
swipeToDismissTouchHelper.attachToRecyclerView(deviceListView);
|
||||||
//swipeToDismissTouchHelper.attachToRecyclerView(deviceListView);
|
*/
|
||||||
|
|
||||||
|
|
||||||
registerForContextMenu(deviceListView);
|
registerForContextMenu(deviceListView);
|
||||||
|
|
||||||
@ -226,7 +221,7 @@ public class ControlCenterv2 extends AppCompatActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
|
DrawerLayout drawer = findViewById(R.id.drawer_layout);
|
||||||
if (drawer.isDrawerOpen(GravityCompat.START)) {
|
if (drawer.isDrawerOpen(GravityCompat.START)) {
|
||||||
drawer.closeDrawer(GravityCompat.START);
|
drawer.closeDrawer(GravityCompat.START);
|
||||||
} else {
|
} else {
|
||||||
@ -237,7 +232,7 @@ public class ControlCenterv2 extends AppCompatActivity
|
|||||||
@Override
|
@Override
|
||||||
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
|
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
|
||||||
|
|
||||||
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
|
DrawerLayout drawer = findViewById(R.id.drawer_layout);
|
||||||
drawer.closeDrawer(GravityCompat.START);
|
drawer.closeDrawer(GravityCompat.START);
|
||||||
|
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
@ -253,6 +248,10 @@ public class ControlCenterv2 extends AppCompatActivity
|
|||||||
Intent dbIntent = new Intent(this, DbManagementActivity.class);
|
Intent dbIntent = new Intent(this, DbManagementActivity.class);
|
||||||
startActivity(dbIntent);
|
startActivity(dbIntent);
|
||||||
return true;
|
return true;
|
||||||
|
case R.id.action_blacklist:
|
||||||
|
Intent blIntent = new Intent(this, AppBlacklistActivity.class);
|
||||||
|
startActivity(blIntent);
|
||||||
|
return true;
|
||||||
case R.id.action_quit:
|
case R.id.action_quit:
|
||||||
GBApplication.quit();
|
GBApplication.quit();
|
||||||
return true;
|
return true;
|
||||||
@ -283,13 +282,6 @@ public class ControlCenterv2 extends AppCompatActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void refreshPairedDevices() {
|
private void refreshPairedDevices() {
|
||||||
List<GBDevice> deviceList = deviceManager.getDevices();
|
|
||||||
if (deviceList.isEmpty()) {
|
|
||||||
background.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
background.setVisibility(View.INVISIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
mGBDeviceAdapter.notifyDataSetChanged();
|
mGBDeviceAdapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,6 +301,8 @@ public class ControlCenterv2 extends AppCompatActivity
|
|||||||
wantedPermissions.add(Manifest.permission.READ_PHONE_STATE);
|
wantedPermissions.add(Manifest.permission.READ_PHONE_STATE);
|
||||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.PROCESS_OUTGOING_CALLS) == PackageManager.PERMISSION_DENIED)
|
if (ContextCompat.checkSelfPermission(this, Manifest.permission.PROCESS_OUTGOING_CALLS) == PackageManager.PERMISSION_DENIED)
|
||||||
wantedPermissions.add(Manifest.permission.PROCESS_OUTGOING_CALLS);
|
wantedPermissions.add(Manifest.permission.PROCESS_OUTGOING_CALLS);
|
||||||
|
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECEIVE_SMS) == PackageManager.PERMISSION_DENIED)
|
||||||
|
wantedPermissions.add(Manifest.permission.RECEIVE_SMS);
|
||||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_SMS) == PackageManager.PERMISSION_DENIED)
|
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_SMS) == PackageManager.PERMISSION_DENIED)
|
||||||
wantedPermissions.add(Manifest.permission.READ_SMS);
|
wantedPermissions.add(Manifest.permission.READ_SMS);
|
||||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.SEND_SMS) == PackageManager.PERMISSION_DENIED)
|
if (ContextCompat.checkSelfPermission(this, Manifest.permission.SEND_SMS) == PackageManager.PERMISSION_DENIED)
|
||||||
@ -317,6 +311,11 @@ public class ControlCenterv2 extends AppCompatActivity
|
|||||||
wantedPermissions.add(Manifest.permission.READ_EXTERNAL_STORAGE);
|
wantedPermissions.add(Manifest.permission.READ_EXTERNAL_STORAGE);
|
||||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_DENIED)
|
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_DENIED)
|
||||||
wantedPermissions.add(Manifest.permission.READ_CALENDAR);
|
wantedPermissions.add(Manifest.permission.READ_CALENDAR);
|
||||||
|
try {
|
||||||
|
if (ContextCompat.checkSelfPermission(this, Manifest.permission.MEDIA_CONTENT_CONTROL) == PackageManager.PERMISSION_DENIED)
|
||||||
|
wantedPermissions.add(Manifest.permission.MEDIA_CONTENT_CONTROL);
|
||||||
|
} catch (Exception ignored){
|
||||||
|
}
|
||||||
|
|
||||||
if (!wantedPermissions.isEmpty())
|
if (!wantedPermissions.isEmpty())
|
||||||
ActivityCompat.requestPermissions(this, wantedPermissions.toArray(new String[wantedPermissions.size()]), 0);
|
ActivityCompat.requestPermissions(this, wantedPermissions.toArray(new String[wantedPermissions.size()]), 0);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2016-2017 Alberto, Andreas Shimokawa, Carsten Pfeiffer,
|
/* Copyright (C) 2016-2018 Alberto, Andreas Shimokawa, Carsten Pfeiffer,
|
||||||
Daniele Gobbetti
|
Daniele Gobbetti
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
Gobbetti, Frank Slezak, ivanovlev, Kasha, Lem Dulfo, Steffen Liebergeld
|
Gobbetti, Frank Slezak, ivanovlev, Kasha, Lem Dulfo, Steffen Liebergeld
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
@ -40,18 +40,21 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
|
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.RecordedDataTypes;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
|
||||||
|
import static nodomain.freeyourgadget.gadgetbridge.util.GB.NOTIFICATION_CHANNEL_ID;
|
||||||
|
|
||||||
|
|
||||||
public class DebugActivity extends AbstractGBActivity {
|
public class DebugActivity extends AbstractGBActivity {
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(DebugActivity.class);
|
private static final Logger LOG = LoggerFactory.getLogger(DebugActivity.class);
|
||||||
@ -61,23 +64,12 @@ public class DebugActivity extends AbstractGBActivity {
|
|||||||
= "nodomain.freeyourgadget.gadgetbridge.DebugActivity.action.reply";
|
= "nodomain.freeyourgadget.gadgetbridge.DebugActivity.action.reply";
|
||||||
|
|
||||||
private Spinner sendTypeSpinner;
|
private Spinner sendTypeSpinner;
|
||||||
private Button sendButton;
|
|
||||||
private Button incomingCallButton;
|
|
||||||
private Button outgoingCallButton;
|
|
||||||
private Button startCallButton;
|
|
||||||
private Button endCallButton;
|
|
||||||
private Button testNotificationButton;
|
|
||||||
private Button setMusicInfoButton;
|
|
||||||
private Button setTimeButton;
|
|
||||||
private Button rebootButton;
|
|
||||||
private Button HeartRateButton;
|
|
||||||
private Button testNewFunctionalityButton;
|
|
||||||
|
|
||||||
private EditText editContent;
|
private EditText editContent;
|
||||||
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
switch (intent.getAction()) {
|
switch (Objects.requireNonNull(intent.getAction())) {
|
||||||
case ACTION_REPLY: {
|
case ACTION_REPLY: {
|
||||||
Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
|
Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
|
||||||
CharSequence reply = remoteInput.getCharSequence(EXTRA_REPLY);
|
CharSequence reply = remoteInput.getCharSequence(EXTRA_REPLY);
|
||||||
@ -85,11 +77,9 @@ public class DebugActivity extends AbstractGBActivity {
|
|||||||
GB.toast(context, "got wearable reply: " + reply, Toast.LENGTH_SHORT, GB.INFO);
|
GB.toast(context, "got wearable reply: " + reply, Toast.LENGTH_SHORT, GB.INFO);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DeviceService.ACTION_HEARTRATE_MEASUREMENT: {
|
default:
|
||||||
int hrValue = intent.getIntExtra(DeviceService.EXTRA_HEART_RATE_VALUE, -1);
|
LOG.info("ignoring intent action " + intent.getAction());
|
||||||
GB.toast(DebugActivity.this, "Heart Rate measured: " + hrValue, Toast.LENGTH_LONG, GB.INFO);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -105,17 +95,17 @@ public class DebugActivity extends AbstractGBActivity {
|
|||||||
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filter);
|
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filter);
|
||||||
registerReceiver(mReceiver, filter); // for ACTION_REPLY
|
registerReceiver(mReceiver, filter); // for ACTION_REPLY
|
||||||
|
|
||||||
editContent = (EditText) findViewById(R.id.editContent);
|
editContent = findViewById(R.id.editContent);
|
||||||
|
|
||||||
ArrayList<String> spinnerArray = new ArrayList<>();
|
ArrayList<String> spinnerArray = new ArrayList<>();
|
||||||
for (NotificationType notificationType : NotificationType.values()) {
|
for (NotificationType notificationType : NotificationType.values()) {
|
||||||
spinnerArray.add(notificationType.name());
|
spinnerArray.add(notificationType.name());
|
||||||
}
|
}
|
||||||
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, spinnerArray);
|
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, spinnerArray);
|
||||||
sendTypeSpinner = (Spinner) findViewById(R.id.sendTypeSpinner);
|
sendTypeSpinner = findViewById(R.id.sendTypeSpinner);
|
||||||
sendTypeSpinner.setAdapter(spinnerArrayAdapter);
|
sendTypeSpinner.setAdapter(spinnerArrayAdapter);
|
||||||
|
|
||||||
sendButton = (Button) findViewById(R.id.sendButton);
|
Button sendButton = findViewById(R.id.sendButton);
|
||||||
sendButton.setOnClickListener(new View.OnClickListener() {
|
sendButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
@ -132,7 +122,7 @@ public class DebugActivity extends AbstractGBActivity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
incomingCallButton = (Button) findViewById(R.id.incomingCallButton);
|
Button incomingCallButton = findViewById(R.id.incomingCallButton);
|
||||||
incomingCallButton.setOnClickListener(new View.OnClickListener() {
|
incomingCallButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
@ -142,7 +132,7 @@ public class DebugActivity extends AbstractGBActivity {
|
|||||||
GBApplication.deviceService().onSetCallState(callSpec);
|
GBApplication.deviceService().onSetCallState(callSpec);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
outgoingCallButton = (Button) findViewById(R.id.outgoingCallButton);
|
Button outgoingCallButton = findViewById(R.id.outgoingCallButton);
|
||||||
outgoingCallButton.setOnClickListener(new View.OnClickListener() {
|
outgoingCallButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
@ -153,7 +143,7 @@ public class DebugActivity extends AbstractGBActivity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
startCallButton = (Button) findViewById(R.id.startCallButton);
|
Button startCallButton = findViewById(R.id.startCallButton);
|
||||||
startCallButton.setOnClickListener(new View.OnClickListener() {
|
startCallButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
@ -162,7 +152,7 @@ public class DebugActivity extends AbstractGBActivity {
|
|||||||
GBApplication.deviceService().onSetCallState(callSpec);
|
GBApplication.deviceService().onSetCallState(callSpec);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
endCallButton = (Button) findViewById(R.id.endCallButton);
|
Button endCallButton = findViewById(R.id.endCallButton);
|
||||||
endCallButton.setOnClickListener(new View.OnClickListener() {
|
endCallButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
@ -172,15 +162,15 @@ public class DebugActivity extends AbstractGBActivity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
rebootButton = (Button) findViewById(R.id.rebootButton);
|
Button rebootButton = findViewById(R.id.rebootButton);
|
||||||
rebootButton.setOnClickListener(new View.OnClickListener() {
|
rebootButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
GBApplication.deviceService().onReboot();
|
GBApplication.deviceService().onReboot();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
HeartRateButton = (Button) findViewById(R.id.HearRateButton);
|
Button heartRateButton = findViewById(R.id.HeartRateButton);
|
||||||
HeartRateButton.setOnClickListener(new View.OnClickListener() {
|
heartRateButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
GB.toast("Measuring heart rate, please wait...", Toast.LENGTH_LONG, GB.INFO);
|
GB.toast("Measuring heart rate, please wait...", Toast.LENGTH_LONG, GB.INFO);
|
||||||
@ -188,7 +178,7 @@ public class DebugActivity extends AbstractGBActivity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setMusicInfoButton = (Button) findViewById(R.id.setMusicInfoButton);
|
Button setMusicInfoButton = findViewById(R.id.setMusicInfoButton);
|
||||||
setMusicInfoButton.setOnClickListener(new View.OnClickListener() {
|
setMusicInfoButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
@ -214,7 +204,7 @@ public class DebugActivity extends AbstractGBActivity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setTimeButton = (Button) findViewById(R.id.setTimeButton);
|
Button setTimeButton = findViewById(R.id.setTimeButton);
|
||||||
setTimeButton.setOnClickListener(new View.OnClickListener() {
|
setTimeButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
@ -222,7 +212,7 @@ public class DebugActivity extends AbstractGBActivity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
testNotificationButton = (Button) findViewById(R.id.testNotificationButton);
|
Button testNotificationButton = findViewById(R.id.testNotificationButton);
|
||||||
testNotificationButton.setOnClickListener(new View.OnClickListener() {
|
testNotificationButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
@ -230,7 +220,15 @@ public class DebugActivity extends AbstractGBActivity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
testNewFunctionalityButton = (Button) findViewById(R.id.testNewFunctionality);
|
Button fetchDebugLogsButton = findViewById(R.id.fetchDebugLogsButton);
|
||||||
|
fetchDebugLogsButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
GBApplication.deviceService().onFetchRecordedData(RecordedDataTypes.TYPE_DEBUGLOGS);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Button testNewFunctionalityButton = findViewById(R.id.testNewFunctionality);
|
||||||
testNewFunctionalityButton.setOnClickListener(new View.OnClickListener() {
|
testNewFunctionalityButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
@ -266,7 +264,7 @@ public class DebugActivity extends AbstractGBActivity {
|
|||||||
|
|
||||||
NotificationCompat.WearableExtender wearableExtender = new NotificationCompat.WearableExtender().addAction(action);
|
NotificationCompat.WearableExtender wearableExtender = new NotificationCompat.WearableExtender().addAction(action);
|
||||||
|
|
||||||
NotificationCompat.Builder ncomp = new NotificationCompat.Builder(this)
|
NotificationCompat.Builder ncomp = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
|
||||||
.setContentTitle(getString(R.string.test_notification))
|
.setContentTitle(getString(R.string.test_notification))
|
||||||
.setContentText(getString(R.string.this_is_a_test_notification_from_gadgetbridge))
|
.setContentText(getString(R.string.this_is_a_test_notification_from_gadgetbridge))
|
||||||
.setTicker(getString(R.string.this_is_a_test_notification_from_gadgetbridge))
|
.setTicker(getString(R.string.this_is_a_test_notification_from_gadgetbridge))
|
||||||
@ -275,7 +273,9 @@ public class DebugActivity extends AbstractGBActivity {
|
|||||||
.setContentIntent(pendingIntent)
|
.setContentIntent(pendingIntent)
|
||||||
.extend(wearableExtender);
|
.extend(wearableExtender);
|
||||||
|
|
||||||
nManager.notify((int) System.currentTimeMillis(), ncomp.build());
|
if (nManager != null) {
|
||||||
|
nManager.notify((int) System.currentTimeMillis(), ncomp.build());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -295,7 +295,4 @@ public class DebugActivity extends AbstractGBActivity {
|
|||||||
unregisterReceiver(mReceiver);
|
unregisterReceiver(mReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface DeviceSelectionCallback {
|
|
||||||
void invoke(GBDevice device);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
Gobbetti, JohnnySun, Lem Dulfo, Uwe Hermann
|
Gobbetti, JohnnySun, Lem Dulfo, Taavi Eomäe, Uwe Hermann
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
@ -24,6 +24,7 @@ import android.app.AlertDialog;
|
|||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothManager;
|
import android.bluetooth.BluetoothManager;
|
||||||
|
import android.bluetooth.le.BluetoothLeScanner;
|
||||||
import android.bluetooth.le.ScanCallback;
|
import android.bluetooth.le.ScanCallback;
|
||||||
import android.bluetooth.le.ScanFilter;
|
import android.bluetooth.le.ScanFilter;
|
||||||
import android.bluetooth.le.ScanRecord;
|
import android.bluetooth.le.ScanRecord;
|
||||||
@ -54,6 +55,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
@ -66,8 +68,6 @@ import nodomain.freeyourgadget.gadgetbridge.util.AndroidUtils;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
|
||||||
import static android.bluetooth.le.ScanSettings.MATCH_MODE_STICKY;
|
|
||||||
import static android.bluetooth.le.ScanSettings.SCAN_MODE_LOW_LATENCY;
|
|
||||||
|
|
||||||
public class DiscoveryActivity extends AbstractGBActivity implements AdapterView.OnItemClickListener {
|
public class DiscoveryActivity extends AbstractGBActivity implements AdapterView.OnItemClickListener {
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(DiscoveryActivity.class);
|
private static final Logger LOG = LoggerFactory.getLogger(DiscoveryActivity.class);
|
||||||
@ -80,7 +80,7 @@ public class DiscoveryActivity extends AbstractGBActivity implements AdapterView
|
|||||||
private final BroadcastReceiver bluetoothReceiver = new BroadcastReceiver() {
|
private final BroadcastReceiver bluetoothReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
switch (intent.getAction()) {
|
switch (Objects.requireNonNull(intent.getAction())) {
|
||||||
case BluetoothAdapter.ACTION_DISCOVERY_STARTED:
|
case BluetoothAdapter.ACTION_DISCOVERY_STARTED:
|
||||||
if (isScanning != Scanning.SCANNING_BTLE && isScanning != Scanning.SCANNING_NEW_BTLE) {
|
if (isScanning != Scanning.SCANNING_BTLE && isScanning != Scanning.SCANNING_NEW_BTLE) {
|
||||||
discoveryStarted(Scanning.SCANNING_BT);
|
discoveryStarted(Scanning.SCANNING_BT);
|
||||||
@ -105,9 +105,8 @@ public class DiscoveryActivity extends AbstractGBActivity implements AdapterView
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case BluetoothAdapter.ACTION_STATE_CHANGED:
|
case BluetoothAdapter.ACTION_STATE_CHANGED:
|
||||||
int oldState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, BluetoothAdapter.STATE_OFF);
|
|
||||||
int newState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF);
|
int newState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF);
|
||||||
bluetoothStateChanged(oldState, newState);
|
bluetoothStateChanged(newState);
|
||||||
break;
|
break;
|
||||||
case BluetoothDevice.ACTION_FOUND: {
|
case BluetoothDevice.ACTION_FOUND: {
|
||||||
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
|
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
|
||||||
@ -119,7 +118,7 @@ public class DiscoveryActivity extends AbstractGBActivity implements AdapterView
|
|||||||
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
|
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
|
||||||
short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, GBDevice.RSSI_UNKNOWN);
|
short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, GBDevice.RSSI_UNKNOWN);
|
||||||
Parcelable[] uuids = intent.getParcelableArrayExtra(BluetoothDevice.EXTRA_UUID);
|
Parcelable[] uuids = intent.getParcelableArrayExtra(BluetoothDevice.EXTRA_UUID);
|
||||||
ParcelUuid[] uuids2 = AndroidUtils.toParcelUUids(uuids);
|
ParcelUuid[] uuids2 = AndroidUtils.toParcelUuids(uuids);
|
||||||
handleDeviceFound(device, rssi, uuids2);
|
handleDeviceFound(device, rssi, uuids2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -265,7 +264,7 @@ public class DiscoveryActivity extends AbstractGBActivity implements AdapterView
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
setContentView(R.layout.activity_discovery);
|
setContentView(R.layout.activity_discovery);
|
||||||
startButton = (Button) findViewById(R.id.discovery_start);
|
startButton = findViewById(R.id.discovery_start);
|
||||||
startButton.setOnClickListener(new View.OnClickListener() {
|
startButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
@ -273,11 +272,11 @@ public class DiscoveryActivity extends AbstractGBActivity implements AdapterView
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
progressView = (ProgressBar) findViewById(R.id.discovery_progressbar);
|
progressView = findViewById(R.id.discovery_progressbar);
|
||||||
progressView.setProgress(0);
|
progressView.setProgress(0);
|
||||||
progressView.setIndeterminate(true);
|
progressView.setIndeterminate(true);
|
||||||
progressView.setVisibility(View.GONE);
|
progressView.setVisibility(View.GONE);
|
||||||
ListView deviceCandidatesView = (ListView) findViewById(R.id.discovery_deviceCandidatesView);
|
ListView deviceCandidatesView = findViewById(R.id.discovery_deviceCandidatesView);
|
||||||
|
|
||||||
cadidateListAdapter = new DeviceCandidateAdapter(this, deviceCandidates);
|
cadidateListAdapter = new DeviceCandidateAdapter(this, deviceCandidates);
|
||||||
deviceCandidatesView.setAdapter(cadidateListAdapter);
|
deviceCandidatesView.setAdapter(cadidateListAdapter);
|
||||||
@ -443,10 +442,15 @@ public class DiscoveryActivity extends AbstractGBActivity implements AdapterView
|
|||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
private void stopNewBTLEDiscovery() {
|
private void stopNewBTLEDiscovery() {
|
||||||
adapter.getBluetoothLeScanner().stopScan(newLeScanCallback);
|
BluetoothLeScanner bluetoothLeScanner = adapter.getBluetoothLeScanner();
|
||||||
|
if (bluetoothLeScanner == null) {
|
||||||
|
LOG.warn("could not get BluetoothLeScanner()!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bluetoothLeScanner.stopScan(newLeScanCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bluetoothStateChanged(int oldState, int newState) {
|
private void bluetoothStateChanged(int newState) {
|
||||||
discoveryFinished();
|
discoveryFinished();
|
||||||
if (newState == BluetoothAdapter.STATE_ON) {
|
if (newState == BluetoothAdapter.STATE_ON) {
|
||||||
this.adapter = BluetoothAdapter.getDefaultAdapter();
|
this.adapter = BluetoothAdapter.getDefaultAdapter();
|
||||||
@ -530,12 +534,12 @@ public class DiscoveryActivity extends AbstractGBActivity implements AdapterView
|
|||||||
private ScanSettings getScanSettings() {
|
private ScanSettings getScanSettings() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
return new ScanSettings.Builder()
|
return new ScanSettings.Builder()
|
||||||
.setScanMode(SCAN_MODE_LOW_LATENCY)
|
.setScanMode(android.bluetooth.le.ScanSettings.SCAN_MODE_LOW_LATENCY)
|
||||||
.setMatchMode(MATCH_MODE_STICKY)
|
.setMatchMode(android.bluetooth.le.ScanSettings.MATCH_MODE_STICKY)
|
||||||
.build();
|
.build();
|
||||||
} else {
|
} else {
|
||||||
return new ScanSettings.Builder()
|
return new ScanSettings.Builder()
|
||||||
.setScanMode(SCAN_MODE_LOW_LATENCY)
|
.setScanMode(android.bluetooth.le.ScanSettings.SCAN_MODE_LOW_LATENCY)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -611,4 +615,14 @@ public class DiscoveryActivity extends AbstractGBActivity implements AdapterView
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
stopBTDiscovery();
|
||||||
|
stopBTLEDiscovery();
|
||||||
|
if (GB.supportsBluetoothLE()) {
|
||||||
|
stopNewBTLEDiscovery();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2016-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
/* Copyright (C) 2016-2018 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
Gobbetti, Lem Dulfo, Uwe Hermann
|
Gobbetti, Lem Dulfo, Uwe Hermann
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
@ -34,19 +34,26 @@ import android.widget.Toast;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
|
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.webview.GBChromeClient;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.webview.GBChromeClient;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.webview.GBWebClient;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.webview.GBWebClient;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.webview.JSInterface;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.webview.JSInterface;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.WebViewSingleton;
|
import nodomain.freeyourgadget.gadgetbridge.util.WebViewSingleton;
|
||||||
|
|
||||||
|
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_CONNECT;
|
||||||
|
|
||||||
public class ExternalPebbleJSActivity extends AbstractGBActivity {
|
public class ExternalPebbleJSActivity extends AbstractGBActivity {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(ExternalPebbleJSActivity.class);
|
private static final Logger LOG = LoggerFactory.getLogger(ExternalPebbleJSActivity.class);
|
||||||
@ -64,24 +71,69 @@ public class ExternalPebbleJSActivity extends AbstractGBActivity {
|
|||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
Bundle extras = getIntent().getExtras();
|
Bundle extras = getIntent().getExtras();
|
||||||
|
|
||||||
|
boolean showConfig = false;
|
||||||
|
|
||||||
|
UUID currentUUID = null;
|
||||||
|
GBDevice currentDevice = null;
|
||||||
|
|
||||||
if (extras == null) {
|
if (extras == null) {
|
||||||
throw new IllegalArgumentException("Must provide device and uuid in extras when invoking this activity");
|
confUri = getIntent().getData();
|
||||||
}
|
if(confUri.getScheme().equals("gadgetbridge")) {
|
||||||
|
try {
|
||||||
|
currentUUID = UUID.fromString(confUri.getHost());
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
LOG.error("UUID in incoming configuration is not a valid UUID: " +confUri.toString());
|
||||||
|
}
|
||||||
|
|
||||||
if (extras.getBoolean(START_BG_WEBVIEW, false)) {
|
//first check if we are still connected to a pebble
|
||||||
startBackgroundWebViewAndFinish();
|
DeviceManager deviceManager = ((GBApplication) getApplication()).getDeviceManager();
|
||||||
return;
|
List<GBDevice> deviceList = deviceManager.getDevices();
|
||||||
}
|
for (GBDevice device : deviceList) {
|
||||||
|
if (device.getState() == GBDevice.State.INITIALIZED) {
|
||||||
|
if (device.getType().equals(DeviceType.PEBBLE)) {
|
||||||
|
currentDevice = device;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
LOG.error("attempting to load pebble configuration but a different device type is connected!!!");
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentDevice == null) {
|
||||||
|
//then try to reconnect to last connected device
|
||||||
|
String btDeviceAddress = GBApplication.getPrefs().getPreferences().getString("last_device_address", null);
|
||||||
|
if (btDeviceAddress != null) {
|
||||||
|
GBDevice candidate = DeviceHelper.getInstance().findAvailableDevice(btDeviceAddress, this);
|
||||||
|
if(!candidate.isConnected() && candidate.getType() == DeviceType.PEBBLE){
|
||||||
|
Intent intent = new Intent(this, DeviceCommunicationService.class)
|
||||||
|
.setAction(ACTION_CONNECT)
|
||||||
|
.putExtra(GBDevice.EXTRA_DEVICE, currentDevice);
|
||||||
|
this.startService(intent);
|
||||||
|
currentDevice = candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GBDevice currentDevice = extras.getParcelable(GBDevice.EXTRA_DEVICE);
|
showConfig = true; //we are getting incoming configuration data
|
||||||
UUID currentUUID = (UUID) extras.getSerializable(DeviceService.EXTRA_APP_UUID);
|
}
|
||||||
|
} else {
|
||||||
|
currentDevice = extras.getParcelable(GBDevice.EXTRA_DEVICE);
|
||||||
|
currentUUID = (UUID) extras.getSerializable(DeviceService.EXTRA_APP_UUID);
|
||||||
|
|
||||||
|
if (extras.getBoolean(START_BG_WEBVIEW, false)) {
|
||||||
|
startBackgroundWebViewAndFinish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
showConfig = extras.getBoolean(SHOW_CONFIG, false);
|
||||||
|
}
|
||||||
|
|
||||||
if (GBApplication.getGBPrefs().isBackgroundJsEnabled()) {
|
if (GBApplication.getGBPrefs().isBackgroundJsEnabled()) {
|
||||||
if (extras.getBoolean(SHOW_CONFIG, false)) {
|
if (showConfig) {
|
||||||
Objects.requireNonNull(currentDevice, "Must provide a device when invoking this activity");
|
Objects.requireNonNull(currentDevice, "Must provide a device when invoking this activity");
|
||||||
Objects.requireNonNull(currentUUID, "Must provide a uuid when invoking this activity");
|
Objects.requireNonNull(currentUUID, "Must provide a uuid when invoking this activity");
|
||||||
|
WebViewSingleton.getInstance().runJavascriptInterface(this, currentDevice, currentUUID);
|
||||||
WebViewSingleton.runJavascriptInterface(currentDevice, currentUUID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: is this really supposed to be outside the check for SHOW_CONFIG?
|
// FIXME: is this really supposed to be outside the check for SHOW_CONFIG?
|
||||||
@ -104,7 +156,7 @@ public class ExternalPebbleJSActivity extends AbstractGBActivity {
|
|||||||
|
|
||||||
private void setupBGWebView() {
|
private void setupBGWebView() {
|
||||||
setContentView(R.layout.activity_external_pebble_js);
|
setContentView(R.layout.activity_external_pebble_js);
|
||||||
myWebView = WebViewSingleton.getWebView(this);
|
myWebView = WebViewSingleton.getInstance().getWebView(this);
|
||||||
if (myWebView.getParent() != null) {
|
if (myWebView.getParent() != null) {
|
||||||
((ViewGroup) myWebView.getParent()).removeView(myWebView);
|
((ViewGroup) myWebView.getParent()).removeView(myWebView);
|
||||||
}
|
}
|
||||||
@ -161,6 +213,7 @@ public class ExternalPebbleJSActivity extends AbstractGBActivity {
|
|||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
GB.toast("returned uri: " + confUri.toString(), Toast.LENGTH_LONG, GB.ERROR);
|
GB.toast("returned uri: " + confUri.toString(), Toast.LENGTH_LONG, GB.ERROR);
|
||||||
}
|
}
|
||||||
|
myWebView.stopLoading();
|
||||||
myWebView.loadUrl("file:///android_asset/app_config/configure.html?" + queryString);
|
myWebView.loadUrl("file:///android_asset/app_config/configure.html?" + queryString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2017 Andreas Shimokawa
|
/* Copyright (C) 2018 Andreas Shimokawa
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
Gobbetti, Lem Dulfo
|
Gobbetti, Lem Dulfo
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Lem Dulfo
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer, Lem Dulfo
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2016-2017 Carsten Pfeiffer
|
/* Copyright (C) 2016-2018 Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
@ -27,4 +27,8 @@ public class HeartRateUtils {
|
|||||||
* Value is in minutes
|
* Value is in minutes
|
||||||
*/
|
*/
|
||||||
public static final int MAX_HR_MEASUREMENTS_GAP_MINUTES = 10;
|
public static final int MAX_HR_MEASUREMENTS_GAP_MINUTES = 10;
|
||||||
|
|
||||||
|
public static boolean isValidHeartRateValue(int value) {
|
||||||
|
return value > HeartRateUtils.MIN_HEART_RATE_VALUE && value < HeartRateUtils.MAX_HEART_RATE_VALUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Copyright (C) 2015-2017 0nse, Andreas Shimokawa, Carsten Pfeiffer,
|
/* Copyright (C) 2015-2018 0nse, Andreas Shimokawa, Carsten Pfeiffer,
|
||||||
Daniele Gobbetti, Normano64
|
Daniele Gobbetti, Felix Konstantin Maurer, Normano64
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
@ -18,7 +18,6 @@
|
|||||||
package nodomain.freeyourgadget.gadgetbridge.activities;
|
package nodomain.freeyourgadget.gadgetbridge.activities;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.content.ContentUris;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
@ -29,16 +28,13 @@ import android.location.Location;
|
|||||||
import android.location.LocationListener;
|
import android.location.LocationListener;
|
||||||
import android.location.LocationManager;
|
import android.location.LocationManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
|
||||||
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.PreferenceCategory;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.provider.DocumentsContract;
|
import android.provider.DocumentsContract;
|
||||||
import android.provider.MediaStore;
|
|
||||||
import android.support.v4.app.ActivityCompat;
|
import android.support.v4.app.ActivityCompat;
|
||||||
import android.support.v4.content.LocalBroadcastManager;
|
import android.support.v4.content.LocalBroadcastManager;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
@ -47,7 +43,6 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@ -65,6 +60,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
|
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||||
|
|
||||||
|
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_DISPLAY_ITEMS;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivityUser.PREF_USER_HEIGHT_CM;
|
import static nodomain.freeyourgadget.gadgetbridge.model.ActivityUser.PREF_USER_HEIGHT_CM;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivityUser.PREF_USER_SLEEP_DURATION;
|
import static nodomain.freeyourgadget.gadgetbridge.model.ActivityUser.PREF_USER_SLEEP_DURATION;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivityUser.PREF_USER_STEPS_GOAL;
|
import static nodomain.freeyourgadget.gadgetbridge.model.ActivityUser.PREF_USER_STEPS_GOAL;
|
||||||
@ -330,6 +326,20 @@ public class SettingsActivity extends AbstractSettingsActivity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final Preference displayPages = findPreference("bip_display_items");
|
||||||
|
displayPages.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceChange(Preference preference, Object newVal) {
|
||||||
|
invokeLater(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
GBApplication.deviceService().onSendConfiguration(PREF_MI2_DISPLAY_ITEMS);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Get all receivers of Media Buttons
|
// Get all receivers of Media Buttons
|
||||||
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
|
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
|
||||||
|
|
||||||
@ -377,7 +387,7 @@ public class SettingsActivity extends AbstractSettingsActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Either returns the file path of the selected document, or the display name
|
Either returns the file path of the selected document, or the display name, or an empty string
|
||||||
*/
|
*/
|
||||||
private String getAutoExportLocationSummary() {
|
private String getAutoExportLocationSummary() {
|
||||||
String autoExportLocation = GBApplication.getPrefs().getString(GBPrefs.AUTO_EXPORT_LOCATION, null);
|
String autoExportLocation = GBApplication.getPrefs().getString(GBPrefs.AUTO_EXPORT_LOCATION, null);
|
||||||
@ -386,20 +396,21 @@ public class SettingsActivity extends AbstractSettingsActivity {
|
|||||||
}
|
}
|
||||||
Uri uri = Uri.parse(autoExportLocation);
|
Uri uri = Uri.parse(autoExportLocation);
|
||||||
try {
|
try {
|
||||||
String filePath = AndroidUtils.getFilePath(getApplicationContext(), uri);
|
return AndroidUtils.getFilePath(getApplicationContext(), uri);
|
||||||
if (filePath != null) {
|
} catch (IllegalArgumentException e) {
|
||||||
return filePath;
|
try {
|
||||||
|
Cursor cursor = getContentResolver().query(
|
||||||
|
uri,
|
||||||
|
new String[]{DocumentsContract.Document.COLUMN_DISPLAY_NAME},
|
||||||
|
null, null, null, null
|
||||||
|
);
|
||||||
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
return cursor.getString(cursor.getColumnIndex(DocumentsContract.Document.COLUMN_DISPLAY_NAME));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception fdfsdfds) {
|
||||||
|
LOG.warn("fuck");
|
||||||
}
|
}
|
||||||
} catch (URISyntaxException e) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
Cursor cursor = getContentResolver().query(
|
|
||||||
uri,
|
|
||||||
new String[] { DocumentsContract.Document.COLUMN_DISPLAY_NAME },
|
|
||||||
null, null, null, null
|
|
||||||
);
|
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
|
||||||
return cursor.getString(cursor.getColumnIndex(DocumentsContract.Document.COLUMN_DISPLAY_NAME));
|
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2016-2017 Andreas Shimokawa, Carsten Pfeiffer
|
/* Copyright (C) 2016-2018 Andreas Shimokawa, Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
Gobbetti, Lem Dulfo
|
Gobbetti, Lem Dulfo
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
@ -428,7 +428,7 @@ public abstract class AbstractAppManagerFragment extends Fragment {
|
|||||||
startActivity(startIntent);
|
startActivity(startIntent);
|
||||||
return true;
|
return true;
|
||||||
case R.id.appmanager_app_openinstore:
|
case R.id.appmanager_app_openinstore:
|
||||||
String url = "https://apps.getpebble.com/en_US/search/" + ((selectedApp.getType() == GBDeviceApp.Type.WATCHFACE) ? "watchfaces" : "watchapps") + "/1?query=" + selectedApp.getName() + "&dev_settings=true";
|
String url = "https://pebble-appstore.romanport.com/" + ((selectedApp.getType() == GBDeviceApp.Type.WATCHFACE) ? "watchfaces" : "watchapps") + "/0/?query=" + selectedApp.getName();
|
||||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||||
intent.setData(Uri.parse(url));
|
intent.setData(Uri.parse(url));
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2016-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
/* Copyright (C) 2016-2018 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
Gobbetti
|
Gobbetti
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2016-2017 Andreas Shimokawa
|
/* Copyright (C) 2016-2018 Andreas Shimokawa
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2016-2017 Andreas Shimokawa, Daniele Gobbetti
|
/* Copyright (C) 2016-2018 Andreas Shimokawa, Daniele Gobbetti
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2016-2017 Andreas Shimokawa
|
/* Copyright (C) 2016-2018 Andreas Shimokawa
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 0nse, Andreas Shimokawa, Carsten Pfeiffer,
|
/* Copyright (C) 2015-2018 0nse, Andreas Shimokawa, Carsten Pfeiffer,
|
||||||
Daniele Gobbetti, walkjivefly
|
Daniele Gobbetti, walkjivefly
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
@ -70,6 +70,8 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
||||||
|
|
||||||
|
import static nodomain.freeyourgadget.gadgetbridge.activities.HeartRateUtils.isValidHeartRateValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A base class fragment to be used with ChartsActivity. The fragment can supply
|
* A base class fragment to be used with ChartsActivity. The fragment can supply
|
||||||
* a title to be displayed in the activity by returning non-null in #getTitle()
|
* a title to be displayed in the activity by returning non-null in #getTitle()
|
||||||
@ -439,6 +441,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
|
|||||||
List<Entry> notWornEntries = new ArrayList<>(numEntries);
|
List<Entry> notWornEntries = new ArrayList<>(numEntries);
|
||||||
boolean hr = supportsHeartrate(gbDevice);
|
boolean hr = supportsHeartrate(gbDevice);
|
||||||
List<Entry> heartrateEntries = hr ? new ArrayList<Entry>(numEntries) : null;
|
List<Entry> heartrateEntries = hr ? new ArrayList<Entry>(numEntries) : null;
|
||||||
|
List<Integer> colors = new ArrayList<>(numEntries); // this is kinda inefficient...
|
||||||
int lastHrSampleIndex = -1;
|
int lastHrSampleIndex = -1;
|
||||||
|
|
||||||
for (int i = 0; i < numEntries; i++) {
|
for (int i = 0; i < numEntries; i++) {
|
||||||
@ -509,7 +512,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
|
|||||||
}
|
}
|
||||||
activityEntries.add(createLineEntry(value, ts));
|
activityEntries.add(createLineEntry(value, ts));
|
||||||
}
|
}
|
||||||
if (hr && isValidHeartRateValue(sample.getHeartRate())) {
|
if (hr && sample.getKind() != ActivityKind.TYPE_NOT_WORN && HeartRateUtils.isValidHeartRateValue(sample.getHeartRate())) {
|
||||||
if (lastHrSampleIndex > -1 && ts - lastHrSampleIndex > 1800*HeartRateUtils.MAX_HR_MEASUREMENTS_GAP_MINUTES) {
|
if (lastHrSampleIndex > -1 && ts - lastHrSampleIndex > 1800*HeartRateUtils.MAX_HR_MEASUREMENTS_GAP_MINUTES) {
|
||||||
heartrateEntries.add(createLineEntry(0, lastHrSampleIndex + 1));
|
heartrateEntries.add(createLineEntry(0, lastHrSampleIndex + 1));
|
||||||
heartrateEntries.add(createLineEntry(0, ts - 1));
|
heartrateEntries.add(createLineEntry(0, ts - 1));
|
||||||
@ -574,10 +577,6 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
|
|||||||
return new DefaultChartsData(lineData, xValueFormatter);
|
return new DefaultChartsData(lineData, xValueFormatter);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isValidHeartRateValue(int value) {
|
|
||||||
return value > HeartRateUtils.MIN_HEART_RATE_VALUE && value < HeartRateUtils.MAX_HEART_RATE_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implement this to supply the samples to be displayed.
|
* Implement this to supply the samples to be displayed.
|
||||||
*
|
*
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 0nse, Alberto, Andreas Shimokawa, Carsten Pfeiffer,
|
/* Copyright (C) 2015-2018 0nse, Alberto, Andreas Shimokawa, Carsten Pfeiffer,
|
||||||
Daniele Gobbetti
|
Daniele Gobbetti
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
Gobbetti, Vebryn
|
Gobbetti, Vebryn
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
Gobbetti
|
Gobbetti
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
Gobbetti, Vebryn
|
Gobbetti, Vebryn
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
@ -36,15 +36,12 @@ import android.view.MotionEvent;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
@ -52,6 +49,7 @@ import nodomain.freeyourgadget.gadgetbridge.activities.AbstractFragmentPagerAdap
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBFragmentActivity;
|
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBFragmentActivity;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
|
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.RecordedDataTypes;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
@ -59,16 +57,11 @@ import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue;
|
|||||||
|
|
||||||
public class ChartsActivity extends AbstractGBFragmentActivity implements ChartsHost {
|
public class ChartsActivity extends AbstractGBFragmentActivity implements ChartsHost {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(ChartsActivity.class);
|
|
||||||
|
|
||||||
private Button mPrevButton;
|
|
||||||
private Button mNextButton;
|
|
||||||
private TextView mDateControl;
|
private TextView mDateControl;
|
||||||
|
|
||||||
private Date mStartDate;
|
private Date mStartDate;
|
||||||
private Date mEndDate;
|
private Date mEndDate;
|
||||||
private SwipeRefreshLayout swipeLayout;
|
private SwipeRefreshLayout swipeLayout;
|
||||||
private NonSwipeableViewPager viewPager;
|
|
||||||
|
|
||||||
LimitedQueue mActivityAmountCache = new LimitedQueue(60);
|
LimitedQueue mActivityAmountCache = new LimitedQueue(60);
|
||||||
|
|
||||||
@ -86,7 +79,7 @@ public class ChartsActivity extends AbstractGBFragmentActivity implements Charts
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_charts_durationdialog);
|
setContentView(R.layout.activity_charts_durationdialog);
|
||||||
|
|
||||||
durationLabel = (TextView) findViewById(R.id.charts_duration_label);
|
durationLabel = findViewById(R.id.charts_duration_label);
|
||||||
setDuration(mDuration);
|
setDuration(mDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +96,7 @@ public class ChartsActivity extends AbstractGBFragmentActivity implements Charts
|
|||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
String action = intent.getAction();
|
String action = intent.getAction();
|
||||||
switch (action) {
|
switch (Objects.requireNonNull(action)) {
|
||||||
case GBDevice.ACTION_DEVICE_CHANGED:
|
case GBDevice.ACTION_DEVICE_CHANGED:
|
||||||
GBDevice dev = intent.getParcelableExtra(GBDevice.EXTRA_DEVICE);
|
GBDevice dev = intent.getParcelableExtra(GBDevice.EXTRA_DEVICE);
|
||||||
refreshBusyState(dev);
|
refreshBusyState(dev);
|
||||||
@ -145,7 +138,7 @@ public class ChartsActivity extends AbstractGBFragmentActivity implements Charts
|
|||||||
throw new IllegalArgumentException("Must provide a device when invoking this activity");
|
throw new IllegalArgumentException("Must provide a device when invoking this activity");
|
||||||
}
|
}
|
||||||
|
|
||||||
swipeLayout = (SwipeRefreshLayout) findViewById(R.id.activity_swipe_layout);
|
swipeLayout = findViewById(R.id.activity_swipe_layout);
|
||||||
swipeLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
|
swipeLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onRefresh() {
|
public void onRefresh() {
|
||||||
@ -155,7 +148,7 @@ public class ChartsActivity extends AbstractGBFragmentActivity implements Charts
|
|||||||
enableSwipeRefresh(true);
|
enableSwipeRefresh(true);
|
||||||
|
|
||||||
// Set up the ViewPager with the sections adapter.
|
// Set up the ViewPager with the sections adapter.
|
||||||
viewPager = (NonSwipeableViewPager) findViewById(R.id.charts_pager);
|
NonSwipeableViewPager viewPager = findViewById(R.id.charts_pager);
|
||||||
viewPager.setAdapter(getPagerAdapter());
|
viewPager.setAdapter(getPagerAdapter());
|
||||||
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
|
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
@ -172,8 +165,8 @@ public class ChartsActivity extends AbstractGBFragmentActivity implements Charts
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
dateBar = (ViewGroup) findViewById(R.id.charts_date_bar);
|
dateBar = findViewById(R.id.charts_date_bar);
|
||||||
mDateControl = (TextView) findViewById(R.id.charts_text_date);
|
mDateControl = findViewById(R.id.charts_text_date);
|
||||||
mDateControl.setOnClickListener(new View.OnClickListener() {
|
mDateControl.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
@ -182,22 +175,20 @@ public class ChartsActivity extends AbstractGBFragmentActivity implements Charts
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
mPrevButton = (Button) findViewById(R.id.charts_previous);
|
Button mPrevButton = findViewById(R.id.charts_previous);
|
||||||
mPrevButton.setOnClickListener(new View.OnClickListener() {
|
mPrevButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
handlePrevButtonClicked();
|
handlePrevButtonClicked();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mNextButton = (Button) findViewById(R.id.charts_next);
|
Button mNextButton = findViewById(R.id.charts_next);
|
||||||
mNextButton.setOnClickListener(new View.OnClickListener() {
|
mNextButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
handleNextButtonClicked();
|
handleNextButtonClicked();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
LinearLayout mainLayout = (LinearLayout) findViewById(R.id.charts_main_layout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String formatDetailedDuration() {
|
private String formatDetailedDuration() {
|
||||||
@ -284,7 +275,7 @@ public class ChartsActivity extends AbstractGBFragmentActivity implements Charts
|
|||||||
|
|
||||||
private void fetchActivityData() {
|
private void fetchActivityData() {
|
||||||
if (getDevice().isInitialized()) {
|
if (getDevice().isInitialized()) {
|
||||||
GBApplication.deviceService().onFetchActivityData();
|
GBApplication.deviceService().onFetchRecordedData(RecordedDataTypes.TYPE_ACTIVITY);
|
||||||
} else {
|
} else {
|
||||||
swipeLayout.setRefreshing(false);
|
swipeLayout.setRefreshing(false);
|
||||||
GB.toast(this, getString(R.string.device_not_connected), Toast.LENGTH_SHORT, GB.ERROR);
|
GB.toast(this, getString(R.string.device_not_connected), Toast.LENGTH_SHORT, GB.ERROR);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2016-2017 Carsten Pfeiffer
|
/* Copyright (C) 2016-2018 Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
@ -168,7 +168,7 @@ public class LiveActivityFragment extends AbstractChartFragment {
|
|||||||
private void addSample(ActivitySample sample) {
|
private void addSample(ActivitySample sample) {
|
||||||
int heartRate = sample.getHeartRate();
|
int heartRate = sample.getHeartRate();
|
||||||
int timestamp = tsTranslation.shorten(sample.getTimestamp());
|
int timestamp = tsTranslation.shorten(sample.getTimestamp());
|
||||||
if (isValidHeartRateValue(heartRate)) {
|
if (HeartRateUtils.isValidHeartRateValue(heartRate)) {
|
||||||
setCurrentHeartRate(heartRate, timestamp);
|
setCurrentHeartRate(heartRate, timestamp);
|
||||||
}
|
}
|
||||||
int steps = sample.getSteps();
|
int steps = sample.getSteps();
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Carsten Pfeiffer
|
/* Copyright (C) 2015-2018 Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 0nse, Andreas Shimokawa, Carsten Pfeiffer,
|
/* Copyright (C) 2015-2018 0nse, Andreas Shimokawa, Carsten Pfeiffer,
|
||||||
Daniele Gobbetti
|
Daniele Gobbetti
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 0nse, Andreas Shimokawa, Carsten Pfeiffer,
|
/* Copyright (C) 2015-2018 0nse, Andreas Shimokawa, Carsten Pfeiffer,
|
||||||
Daniele Gobbetti, Vebryn
|
Daniele Gobbetti, Vebryn
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2016-2017 Carsten Pfeiffer
|
/* Copyright (C) 2016-2018 Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2016-2017 Carsten Pfeiffer
|
/* Copyright (C) 2016-2018 Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2017 Andreas Shimokawa, Carsten Pfeiffer
|
/* Copyright (C) 2017-2018 Andreas Shimokawa, Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 0nse, Andreas Shimokawa, Carsten Pfeiffer,
|
/* Copyright (C) 2015-2018 0nse, Andreas Shimokawa, Carsten Pfeiffer,
|
||||||
Daniele Gobbetti
|
Daniele Gobbetti
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
@ -0,0 +1,122 @@
|
|||||||
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer
|
||||||
|
|
||||||
|
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.adapter;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.annotation.DrawableRes;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapter for displaying generic ItemWithDetails instances.
|
||||||
|
*/
|
||||||
|
public abstract class AbstractItemAdapter<T> extends ArrayAdapter<T> {
|
||||||
|
|
||||||
|
public static final int SIZE_SMALL = 1;
|
||||||
|
public static final int SIZE_MEDIUM = 2;
|
||||||
|
public static final int SIZE_LARGE = 3;
|
||||||
|
private final Context context;
|
||||||
|
private final List<T> items;
|
||||||
|
private boolean horizontalAlignment;
|
||||||
|
private int size = SIZE_MEDIUM;
|
||||||
|
|
||||||
|
public AbstractItemAdapter(Context context) {
|
||||||
|
this (context, new ArrayList<T>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractItemAdapter(Context context, List<T> items) {
|
||||||
|
super(context, 0, items);
|
||||||
|
|
||||||
|
this.context = context;
|
||||||
|
this.items = items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHorizontalAlignment(boolean horizontalAlignment) {
|
||||||
|
this.horizontalAlignment = horizontalAlignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int position, View view, ViewGroup parent) {
|
||||||
|
T item = getItem(position);
|
||||||
|
|
||||||
|
if (view == null) {
|
||||||
|
LayoutInflater inflater = (LayoutInflater) context
|
||||||
|
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
|
||||||
|
if (horizontalAlignment) {
|
||||||
|
view = inflater.inflate(R.layout.item_with_details_horizontal, parent, false);
|
||||||
|
} else {
|
||||||
|
switch (size) {
|
||||||
|
case SIZE_SMALL:
|
||||||
|
view = inflater.inflate(R.layout.item_with_details_small, parent, false);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
view = inflater.inflate(R.layout.item_with_details, parent, false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImageView iconView = (ImageView) view.findViewById(R.id.item_image);
|
||||||
|
TextView nameView = (TextView) view.findViewById(R.id.item_name);
|
||||||
|
TextView detailsView = (TextView) view.findViewById(R.id.item_details);
|
||||||
|
|
||||||
|
nameView.setText(getName(item));
|
||||||
|
detailsView.setText(getDetails(item));
|
||||||
|
iconView.setImageResource(getIcon(item));
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract String getName(T item);
|
||||||
|
|
||||||
|
protected abstract String getDetails(T item);
|
||||||
|
|
||||||
|
@DrawableRes
|
||||||
|
protected abstract int getIcon(T item);
|
||||||
|
|
||||||
|
public void setSize(int size) {
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSize() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<T> getItems() {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadItems() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setItems(List<T> items, boolean notify) {
|
||||||
|
this.items.clear();
|
||||||
|
this.items.addAll(items);
|
||||||
|
if (notify) {
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
/* Copyright (C) 2017-2018 Carsten Pfeiffer, Daniele Gobbetti
|
||||||
|
|
||||||
|
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.adapter;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import de.greenrobot.dao.query.QueryBuilder;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummaryDao;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
|
||||||
|
public class ActivitySummariesAdapter extends AbstractItemAdapter<BaseActivitySummary> {
|
||||||
|
private final GBDevice device;
|
||||||
|
|
||||||
|
public ActivitySummariesAdapter(Context context, GBDevice device) {
|
||||||
|
super(context);
|
||||||
|
this.device = device;
|
||||||
|
loadItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadItems() {
|
||||||
|
try (DBHandler handler = GBApplication.acquireDB()) {
|
||||||
|
BaseActivitySummaryDao summaryDao = handler.getDaoSession().getBaseActivitySummaryDao();
|
||||||
|
Device dbDevice = DBHelper.findDevice(device, handler.getDaoSession());
|
||||||
|
|
||||||
|
QueryBuilder<BaseActivitySummary> qb = summaryDao.queryBuilder();
|
||||||
|
qb.where(BaseActivitySummaryDao.Properties.DeviceId.eq(dbDevice.getId())).orderDesc(BaseActivitySummaryDao.Properties.StartTime);
|
||||||
|
List<BaseActivitySummary> allSummaries = qb.build().list();
|
||||||
|
setItems(allSummaries, true);
|
||||||
|
} catch (Exception e) {
|
||||||
|
GB.toast("Error loading activity summaries.", Toast.LENGTH_SHORT, GB.ERROR, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getName(BaseActivitySummary item) {
|
||||||
|
String name = item.getName();
|
||||||
|
if (name != null && name.length() > 0) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
Date startTime = item.getStartTime();
|
||||||
|
if (startTime != null) {
|
||||||
|
return DateTimeUtils.formatDateTime(startTime);
|
||||||
|
}
|
||||||
|
return "Unknown activity";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getDetails(BaseActivitySummary item) {
|
||||||
|
return ActivityKind.asString(item.getActivityKind(), getContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getIcon(BaseActivitySummary item) {
|
||||||
|
return ActivityKind.getIconId(item.getActivityKind());
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2017 Carsten Pfeiffer, Daniele Gobbetti
|
/* Copyright (C) 2017-2018 Carsten Pfeiffer, Daniele Gobbetti
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ import android.support.v7.widget.RecyclerView;
|
|||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.CheckBox;
|
import android.widget.CheckedTextView;
|
||||||
import android.widget.Filter;
|
import android.widget.Filter;
|
||||||
import android.widget.Filterable;
|
import android.widget.Filterable;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
@ -32,12 +32,16 @@ import android.widget.TextView;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.IdentityHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
|
|
||||||
|
import static nodomain.freeyourgadget.gadgetbridge.GBApplication.packageNameToPebbleMsgSender;
|
||||||
|
|
||||||
public class AppBlacklistAdapter extends RecyclerView.Adapter<AppBlacklistAdapter.AppBLViewHolder> implements Filterable {
|
public class AppBlacklistAdapter extends RecyclerView.Adapter<AppBlacklistAdapter.AppBLViewHolder> implements Filterable {
|
||||||
|
|
||||||
private List<ApplicationInfo> applicationInfoList;
|
private List<ApplicationInfo> applicationInfoList;
|
||||||
@ -62,7 +66,7 @@ public class AppBlacklistAdapter extends RecyclerView.Adapter<AppBlacklistAdapte
|
|||||||
if (name == null) {
|
if (name == null) {
|
||||||
name = ai.packageName;
|
name = ai.packageName;
|
||||||
}
|
}
|
||||||
if (GBApplication.appIsBlacklisted(ai.packageName)) {
|
if (GBApplication.appIsNotifBlacklisted(ai.packageName) || GBApplication.appIsPebbleBlacklisted(packageNameToPebbleMsgSender(ai.packageName))) {
|
||||||
// sort blacklisted first by prefixing with a '!'
|
// sort blacklisted first by prefixing with a '!'
|
||||||
name = "!" + name;
|
name = "!" + name;
|
||||||
}
|
}
|
||||||
@ -94,23 +98,52 @@ public class AppBlacklistAdapter extends RecyclerView.Adapter<AppBlacklistAdapte
|
|||||||
holder.deviceAppNameLabel.setText(mNameMap.get(appInfo));
|
holder.deviceAppNameLabel.setText(mNameMap.get(appInfo));
|
||||||
holder.deviceImageView.setImageDrawable(appInfo.loadIcon(mPm));
|
holder.deviceImageView.setImageDrawable(appInfo.loadIcon(mPm));
|
||||||
|
|
||||||
holder.checkbox.setChecked(GBApplication.appIsBlacklisted(appInfo.packageName));
|
holder.blacklist_checkbox.setChecked(GBApplication.appIsNotifBlacklisted(appInfo.packageName));
|
||||||
|
holder.blacklist_pebble_checkbox.setChecked(GBApplication.appIsPebbleBlacklisted(packageNameToPebbleMsgSender(appInfo.packageName)));
|
||||||
|
|
||||||
|
holder.blacklist_pebble_checkbox.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
((CheckedTextView) view).toggle();
|
||||||
|
if ( ((CheckedTextView)view).isChecked() ) {
|
||||||
|
GBApplication.addAppToPebbleBlacklist(appInfo.packageName);
|
||||||
|
} else {
|
||||||
|
GBApplication.removeFromAppsPebbleBlacklist(appInfo.packageName);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
holder.itemView.setOnClickListener(new View.OnClickListener() {
|
holder.itemView.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
CheckBox checkBox = ((CheckBox) v.findViewById(R.id.item_checkbox));
|
CheckedTextView checkBox = ((CheckedTextView) v.findViewById(R.id.item_checkbox));
|
||||||
checkBox.toggle();
|
checkBox.toggle();
|
||||||
if (checkBox.isChecked()) {
|
if (checkBox.isChecked()) {
|
||||||
GBApplication.addAppToBlacklist(appInfo.packageName);
|
GBApplication.addAppToNotifBlacklist(appInfo.packageName);
|
||||||
} else {
|
} else {
|
||||||
GBApplication.removeFromAppsBlacklist(appInfo.packageName);
|
GBApplication.removeFromAppsNotifBlacklist(appInfo.packageName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void blacklistAllNotif() {
|
||||||
|
Set<String> apps_blacklist = new HashSet<>();
|
||||||
|
List<ApplicationInfo> allApps = mPm.getInstalledApplications(PackageManager.GET_META_DATA);
|
||||||
|
for (ApplicationInfo ai : allApps) {
|
||||||
|
apps_blacklist.add(ai.packageName);
|
||||||
|
}
|
||||||
|
GBApplication.setAppsNotifBlackList(apps_blacklist);
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void whitelistAllNotif() {
|
||||||
|
Set<String> apps_blacklist = new HashSet<>();
|
||||||
|
GBApplication.setAppsNotifBlackList(apps_blacklist);
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
return applicationInfoList.size();
|
return applicationInfoList.size();
|
||||||
@ -123,9 +156,10 @@ public class AppBlacklistAdapter extends RecyclerView.Adapter<AppBlacklistAdapte
|
|||||||
return applicationFilter;
|
return applicationFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AppBLViewHolder extends RecyclerView.ViewHolder {
|
class AppBLViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
final CheckBox checkbox;
|
final CheckedTextView blacklist_checkbox;
|
||||||
|
final CheckedTextView blacklist_pebble_checkbox;
|
||||||
final ImageView deviceImageView;
|
final ImageView deviceImageView;
|
||||||
final TextView deviceAppVersionAuthorLabel;
|
final TextView deviceAppVersionAuthorLabel;
|
||||||
final TextView deviceAppNameLabel;
|
final TextView deviceAppNameLabel;
|
||||||
@ -133,7 +167,8 @@ public class AppBlacklistAdapter extends RecyclerView.Adapter<AppBlacklistAdapte
|
|||||||
AppBLViewHolder(View itemView) {
|
AppBLViewHolder(View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
|
|
||||||
checkbox = (CheckBox) itemView.findViewById(R.id.item_checkbox);
|
blacklist_checkbox = (CheckedTextView) itemView.findViewById(R.id.item_checkbox);
|
||||||
|
blacklist_pebble_checkbox = (CheckedTextView) itemView.findViewById(R.id.item_pebble_checkbox);
|
||||||
deviceImageView = (ImageView) itemView.findViewById(R.id.item_image);
|
deviceImageView = (ImageView) itemView.findViewById(R.id.item_image);
|
||||||
deviceAppVersionAuthorLabel = (TextView) itemView.findViewById(R.id.item_details);
|
deviceAppVersionAuthorLabel = (TextView) itemView.findViewById(R.id.item_details);
|
||||||
deviceAppNameLabel = (TextView) itemView.findViewById(R.id.item_name);
|
deviceAppNameLabel = (TextView) itemView.findViewById(R.id.item_name);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
Gobbetti
|
Gobbetti
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
Gobbetti, Lem Dulfo
|
Gobbetti, Lem Dulfo
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
@ -22,6 +22,7 @@ import android.app.AlertDialog;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.support.design.widget.Snackbar;
|
import android.support.design.widget.Snackbar;
|
||||||
import android.support.v4.content.LocalBroadcastManager;
|
import android.support.v4.content.LocalBroadcastManager;
|
||||||
import android.support.v7.widget.CardView;
|
import android.support.v7.widget.CardView;
|
||||||
@ -43,6 +44,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.activities.ActivitySummariesActivity;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureAlarms;
|
import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureAlarms;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.VibrationActivity;
|
import nodomain.freeyourgadget.gadgetbridge.activities.VibrationActivity;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity;
|
import nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity;
|
||||||
@ -51,6 +53,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.BatteryState;
|
import nodomain.freeyourgadget.gadgetbridge.model.BatteryState;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.RecordedDataTypes;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
|
||||||
@ -69,16 +72,16 @@ public class GBDeviceAdapterv2 extends RecyclerView.Adapter<GBDeviceAdapterv2.Vi
|
|||||||
this.deviceList = deviceList;
|
this.deviceList = deviceList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public GBDeviceAdapterv2.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
public GBDeviceAdapterv2.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.device_itemv2, parent, false);
|
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.device_itemv2, parent, false);
|
||||||
ViewHolder vh = new ViewHolder(view);
|
return new ViewHolder(view);
|
||||||
return vh;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(ViewHolder holder, final int position) {
|
public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
|
||||||
final GBDevice device = deviceList.get(position);
|
final GBDevice device = deviceList.get(position);
|
||||||
final DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(device);
|
final DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(device);
|
||||||
|
|
||||||
@ -143,7 +146,7 @@ public class GBDeviceAdapterv2 extends RecyclerView.Adapter<GBDeviceAdapterv2.Vi
|
|||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
showTransientSnackbar(R.string.busy_task_fetch_activity_data);
|
showTransientSnackbar(R.string.busy_task_fetch_activity_data);
|
||||||
GBApplication.deviceService().onFetchActivityData();
|
GBApplication.deviceService().onFetchRecordedData(RecordedDataTypes.TYPE_ACTIVITY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -210,6 +213,20 @@ public class GBDeviceAdapterv2 extends RecyclerView.Adapter<GBDeviceAdapterv2.Vi
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//show activity tracks
|
||||||
|
holder.showActivityTracks.setVisibility(coordinator.supportsActivityTracks() ? View.VISIBLE : View.GONE);
|
||||||
|
holder.showActivityTracks.setOnClickListener(new View.OnClickListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Intent startIntent;
|
||||||
|
startIntent = new Intent(context, ActivitySummariesActivity.class);
|
||||||
|
startIntent.putExtra(GBDevice.EXTRA_DEVICE, device);
|
||||||
|
context.startActivity(startIntent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
ItemWithDetailsAdapter infoAdapter = new ItemWithDetailsAdapter(context, device.getDeviceInfos());
|
ItemWithDetailsAdapter infoAdapter = new ItemWithDetailsAdapter(context, device.getDeviceInfos());
|
||||||
infoAdapter.setHorizontalAlignment(true);
|
infoAdapter.setHorizontalAlignment(true);
|
||||||
holder.deviceInfoList.setAdapter(infoAdapter);
|
holder.deviceInfoList.setAdapter(infoAdapter);
|
||||||
@ -338,6 +355,7 @@ public class GBDeviceAdapterv2 extends RecyclerView.Adapter<GBDeviceAdapterv2.Vi
|
|||||||
ImageView manageAppsView;
|
ImageView manageAppsView;
|
||||||
ImageView setAlarmsView;
|
ImageView setAlarmsView;
|
||||||
ImageView showActivityGraphs;
|
ImageView showActivityGraphs;
|
||||||
|
ImageView showActivityTracks;
|
||||||
|
|
||||||
ImageView deviceInfoView;
|
ImageView deviceInfoView;
|
||||||
//overflow
|
//overflow
|
||||||
@ -348,44 +366,44 @@ public class GBDeviceAdapterv2 extends RecyclerView.Adapter<GBDeviceAdapterv2.Vi
|
|||||||
|
|
||||||
ViewHolder(View view) {
|
ViewHolder(View view) {
|
||||||
super(view);
|
super(view);
|
||||||
container = (CardView) view.findViewById(R.id.card_view);
|
container = view.findViewById(R.id.card_view);
|
||||||
|
|
||||||
deviceImageView = (ImageView) view.findViewById(R.id.device_image);
|
deviceImageView = view.findViewById(R.id.device_image);
|
||||||
deviceNameLabel = (TextView) view.findViewById(R.id.device_name);
|
deviceNameLabel = view.findViewById(R.id.device_name);
|
||||||
deviceStatusLabel = (TextView) view.findViewById(R.id.device_status);
|
deviceStatusLabel = view.findViewById(R.id.device_status);
|
||||||
|
|
||||||
//actions
|
//actions
|
||||||
batteryStatusBox = (LinearLayout) view.findViewById(R.id.device_battery_status_box);
|
batteryStatusBox = view.findViewById(R.id.device_battery_status_box);
|
||||||
batteryStatusLabel = (TextView) view.findViewById(R.id.battery_status);
|
batteryStatusLabel = view.findViewById(R.id.battery_status);
|
||||||
batteryIcon = (ImageView) view.findViewById(R.id.device_battery_status);
|
batteryIcon = view.findViewById(R.id.device_battery_status);
|
||||||
fetchActivityDataBox = (LinearLayout) view.findViewById(R.id.device_action_fetch_activity_box);
|
fetchActivityDataBox = view.findViewById(R.id.device_action_fetch_activity_box);
|
||||||
fetchActivityData = (ImageView) view.findViewById(R.id.device_action_fetch_activity);
|
fetchActivityData = view.findViewById(R.id.device_action_fetch_activity);
|
||||||
busyIndicator = (ProgressBar) view.findViewById(R.id.device_busy_indicator);
|
busyIndicator = view.findViewById(R.id.device_busy_indicator);
|
||||||
takeScreenshotView = (ImageView) view.findViewById(R.id.device_action_take_screenshot);
|
takeScreenshotView = view.findViewById(R.id.device_action_take_screenshot);
|
||||||
manageAppsView = (ImageView) view.findViewById(R.id.device_action_manage_apps);
|
manageAppsView = view.findViewById(R.id.device_action_manage_apps);
|
||||||
setAlarmsView = (ImageView) view.findViewById(R.id.device_action_set_alarms);
|
setAlarmsView = view.findViewById(R.id.device_action_set_alarms);
|
||||||
showActivityGraphs = (ImageView) view.findViewById(R.id.device_action_show_activity_graphs);
|
showActivityGraphs = view.findViewById(R.id.device_action_show_activity_graphs);
|
||||||
deviceInfoView = (ImageView) view.findViewById(R.id.device_info_image);
|
showActivityTracks = view.findViewById(R.id.device_action_show_activity_tracks);
|
||||||
|
deviceInfoView = view.findViewById(R.id.device_info_image);
|
||||||
|
|
||||||
deviceInfoBox = (RelativeLayout) view.findViewById(R.id.device_item_infos_box);
|
deviceInfoBox = view.findViewById(R.id.device_item_infos_box);
|
||||||
//overflow
|
//overflow
|
||||||
deviceInfoList = (ListView) view.findViewById(R.id.device_item_infos);
|
deviceInfoList = view.findViewById(R.id.device_item_infos);
|
||||||
findDevice = (ImageView) view.findViewById(R.id.device_action_find);
|
findDevice = view.findViewById(R.id.device_action_find);
|
||||||
removeDevice = (ImageView) view.findViewById(R.id.device_action_remove);
|
removeDevice = view.findViewById(R.id.device_action_remove);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void justifyListViewHeightBasedOnChildren(ListView listView) {
|
private void justifyListViewHeightBasedOnChildren(ListView listView) {
|
||||||
ArrayAdapter adapter = (ArrayAdapter) listView.getAdapter();
|
ArrayAdapter adapter = (ArrayAdapter) listView.getAdapter();
|
||||||
|
|
||||||
if (adapter == null) {
|
if (adapter == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ViewGroup vg = listView;
|
|
||||||
int totalHeight = 0;
|
int totalHeight = 0;
|
||||||
for (int i = 0; i < adapter.getCount(); i++) {
|
for (int i = 0; i < adapter.getCount(); i++) {
|
||||||
View listItem = adapter.getView(i, null, vg);
|
View listItem = adapter.getView(i, null, listView);
|
||||||
listItem.measure(0, 0);
|
listItem.measure(0, 0);
|
||||||
totalHeight += listItem.getMeasuredHeight();
|
totalHeight += listItem.getMeasuredHeight();
|
||||||
}
|
}
|
||||||
@ -427,11 +445,11 @@ public class GBDeviceAdapterv2 extends RecyclerView.Adapter<GBDeviceAdapterv2.Vi
|
|||||||
private void showTransientSnackbar(int resource) {
|
private void showTransientSnackbar(int resource) {
|
||||||
Snackbar snackbar = Snackbar.make(parent, resource, Snackbar.LENGTH_SHORT);
|
Snackbar snackbar = Snackbar.make(parent, resource, Snackbar.LENGTH_SHORT);
|
||||||
|
|
||||||
View snackbarView = snackbar.getView();
|
//View snackbarView = snackbar.getView();
|
||||||
|
|
||||||
// change snackbar text color
|
// change snackbar text color
|
||||||
int snackbarTextId = android.support.design.R.id.snackbar_text;
|
//int snackbarTextId = android.support.design.R.id.snackbar_text;
|
||||||
TextView textView = (TextView) snackbarView.findViewById(snackbarTextId);
|
//TextView textView = snackbarView.findViewById(snackbarTextId);
|
||||||
//textView.setTextColor();
|
//textView.setTextColor();
|
||||||
//snackbarView.setBackgroundColor(Color.MAGENTA);
|
//snackbarView.setBackgroundColor(Color.MAGENTA);
|
||||||
snackbar.show();
|
snackbar.show();
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
Gobbetti
|
Gobbetti
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
@ -17,77 +17,33 @@
|
|||||||
package nodomain.freeyourgadget.gadgetbridge.adapter;
|
package nodomain.freeyourgadget.gadgetbridge.adapter;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.ArrayAdapter;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.ItemWithDetails;
|
import nodomain.freeyourgadget.gadgetbridge.model.ItemWithDetails;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adapter for displaying generic ItemWithDetails instances.
|
* Adapter for displaying generic ItemWithDetails instances.
|
||||||
*/
|
*/
|
||||||
public class ItemWithDetailsAdapter extends ArrayAdapter<ItemWithDetails> {
|
public class ItemWithDetailsAdapter extends AbstractItemAdapter<ItemWithDetails> {
|
||||||
|
|
||||||
public static final int SIZE_SMALL = 1;
|
|
||||||
public static final int SIZE_MEDIUM = 2;
|
|
||||||
public static final int SIZE_LARGE = 3;
|
|
||||||
private final Context context;
|
|
||||||
private boolean horizontalAlignment;
|
|
||||||
private int size = SIZE_MEDIUM;
|
|
||||||
|
|
||||||
public ItemWithDetailsAdapter(Context context, List<ItemWithDetails> items) {
|
public ItemWithDetailsAdapter(Context context, List<ItemWithDetails> items) {
|
||||||
super(context, 0, items);
|
super(context, items);
|
||||||
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHorizontalAlignment(boolean horizontalAlignment) {
|
|
||||||
this.horizontalAlignment = horizontalAlignment;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View getView(int position, View view, ViewGroup parent) {
|
protected String getName(ItemWithDetails item) {
|
||||||
ItemWithDetails item = getItem(position);
|
return item.getName();
|
||||||
|
|
||||||
if (view == null) {
|
|
||||||
LayoutInflater inflater = (LayoutInflater) context
|
|
||||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
|
||||||
|
|
||||||
if (horizontalAlignment) {
|
|
||||||
view = inflater.inflate(R.layout.item_with_details_horizontal, parent, false);
|
|
||||||
} else {
|
|
||||||
switch (size) {
|
|
||||||
case SIZE_SMALL:
|
|
||||||
view = inflater.inflate(R.layout.item_with_details_small, parent, false);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
view = inflater.inflate(R.layout.item_with_details, parent, false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImageView iconView = (ImageView) view.findViewById(R.id.item_image);
|
|
||||||
TextView nameView = (TextView) view.findViewById(R.id.item_name);
|
|
||||||
TextView detailsView = (TextView) view.findViewById(R.id.item_details);
|
|
||||||
|
|
||||||
nameView.setText(item.getName());
|
|
||||||
detailsView.setText(item.getDetails());
|
|
||||||
iconView.setImageResource(item.getIcon());
|
|
||||||
|
|
||||||
return view;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSize(int size) {
|
@Override
|
||||||
this.size = size;
|
protected String getDetails(ItemWithDetails item) {
|
||||||
|
return item.getDetails();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSize() {
|
@Override
|
||||||
return size;
|
protected int getIcon(ItemWithDetails item) {
|
||||||
|
return item.getIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2016-2017 Andreas Shimokawa, Carsten Pfeiffer
|
/* Copyright (C) 2016-2018 Andreas Shimokawa, Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
Gobbetti, JohnnySun
|
Gobbetti, JohnnySun
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
Gobbetti, JohnnySun
|
Gobbetti, Felix Konstantin Maurer, JohnnySun
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2016-2017 Andreas Shimokawa, Carsten Pfeiffer
|
/* Copyright (C) 2016-2018 Andreas Shimokawa, Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/* Copyright (C) 2018 Carsten Pfeiffer, Felix Konstantin Maurer
|
||||||
|
|
||||||
|
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.database;
|
package nodomain.freeyourgadget.gadgetbridge.database;
|
||||||
|
|
||||||
import android.app.AlarmManager;
|
import android.app.AlarmManager;
|
||||||
@ -65,8 +81,9 @@ public class PeriodicExporter extends BroadcastReceiver {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Uri dstUri = Uri.parse(dst);
|
Uri dstUri = Uri.parse(dst);
|
||||||
OutputStream out = context.getContentResolver().openOutputStream(dstUri);
|
try (OutputStream out = context.getContentResolver().openOutputStream(dstUri)) {
|
||||||
helper.exportDB(dbHandler, out);
|
helper.exportDB(dbHandler, out);
|
||||||
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
GB.updateExportFailedNotification(context.getString(R.string.notif_export_failed_title), context);
|
GB.updateExportFailedNotification(context.getString(R.string.notif_export_failed_title), context);
|
||||||
LOG.info("Exception while exporting DB: ", ex);
|
LOG.info("Exception while exporting DB: ", ex);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2016-2017 Andreas Shimokawa
|
/* Copyright (C) 2016-2018 Andreas Shimokawa
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2016-2017 Andreas Shimokawa
|
/* Copyright (C) 2016-2018 Andreas Shimokawa
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2017 protomors
|
/* Copyright (C) 2017-2018 protomors
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2016-2017 Andreas Shimokawa, Carsten Pfeiffer
|
/* Copyright (C) 2016-2018 Andreas Shimokawa, Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Daniele Gobbetti
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Daniele Gobbetti
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa
|
/* Copyright (C) 2015-2018 Andreas Shimokawa
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Daniele Gobbetti
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Daniele Gobbetti
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa
|
/* Copyright (C) 2015-2018 Andreas Shimokawa
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2016-2017 Andreas Shimokawa, Carsten Pfeiffer
|
/* Copyright (C) 2016-2018 Andreas Shimokawa, Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa
|
/* Copyright (C) 2015-2018 Andreas Shimokawa
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa
|
/* Copyright (C) 2015-2018 Andreas Shimokawa
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa
|
/* Copyright (C) 2015-2018 Andreas Shimokawa
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa
|
/* Copyright (C) 2015-2018 Andreas Shimokawa
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa
|
/* Copyright (C) 2015-2018 Andreas Shimokawa
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa
|
/* Copyright (C) 2015-2018 Andreas Shimokawa
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2017 Andreas Shimokawa
|
/* Copyright (C) 2017-2018 Andreas Shimokawa
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Carsten Pfeiffer, Daniele Gobbetti
|
/* Copyright (C) 2015-2018 Carsten Pfeiffer, Daniele Gobbetti
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
@ -124,4 +124,9 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
|
|||||||
public int getBondingStyle(GBDevice device) {
|
public int getBondingStyle(GBDevice device) {
|
||||||
return BONDING_STYLE_ASK;
|
return BONDING_STYLE_ASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsActivityTracks() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2016-2017 Andreas Shimokawa, Carsten Pfeiffer
|
/* Copyright (C) 2016-2018 Andreas Shimokawa, Carsten Pfeiffer
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
Gobbetti, JohnnySun, Uwe Hermann
|
Gobbetti, JohnnySun, Uwe Hermann
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
@ -139,6 +139,14 @@ public interface DeviceCoordinator {
|
|||||||
*/
|
*/
|
||||||
boolean supportsActivityTracking();
|
boolean supportsActivityTracking();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether the device supports recording dedicated activity tracks, like
|
||||||
|
* walking, hiking, running, swimming, etc. and retrieving the recorded
|
||||||
|
* data. This is different from the constant activity tracking since the tracks are
|
||||||
|
* usually recorded with additional features, like e.g. GPS.
|
||||||
|
*/
|
||||||
|
boolean supportsActivityTracks();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if activity data fetching is supported AND possible at this
|
* Returns true if activity data fetching is supported AND possible at this
|
||||||
* very moment. This will consider the device state (being connected/disconnected/busy...)
|
* very moment. This will consider the device state (being connected/disconnected/busy...)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
/* Copyright (C) 2016-2017 Andreas Shimokawa, Carsten Pfeiffer
|
/* Copyright (C) 2016-2018 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
@ -39,6 +40,7 @@ import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides access to the list of devices managed by Gadgetbridge.
|
* Provides access to the list of devices managed by Gadgetbridge.
|
||||||
@ -149,6 +151,8 @@ public class DeviceManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
GB.updateNotification(selectedDevice, context);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void refreshPairedDevices() {
|
private void refreshPairedDevices() {
|
||||||
@ -163,7 +167,10 @@ public class DeviceManager {
|
|||||||
Collections.sort(deviceList, new Comparator<GBDevice>() {
|
Collections.sort(deviceList, new Comparator<GBDevice>() {
|
||||||
@Override
|
@Override
|
||||||
public int compare(GBDevice lhs, GBDevice rhs) {
|
public int compare(GBDevice lhs, GBDevice rhs) {
|
||||||
return Collator.getInstance().compare(lhs.getName(), rhs.getName());
|
if (rhs.getStateOrdinal() - lhs.getStateOrdinal() == 0) {
|
||||||
|
return Collator.getInstance().compare(lhs.getName(), rhs.getName());
|
||||||
|
}
|
||||||
|
return (rhs.getStateOrdinal() - lhs.getStateOrdinal());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
notifyDevicesChanged();
|
notifyDevicesChanged();
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user