From 8a9162832207253a3a1f7853a3bbd1eaddeeaf82 Mon Sep 17 00:00:00 2001 From: Normano64 Date: Thu, 19 May 2016 16:34:59 +0200 Subject: [PATCH 01/17] Detects if Do Not Disturb is in use. Can handle sms and phone calls from priority senders when in Priority only, but doesn't handle events and reminders. --- .../gadgetbridge/GBApplication.java | 40 +++++++++++++++++++ .../activities/SettingsActivity.java | 9 +++++ .../externalevents/K9Receiver.java | 12 ++++++ .../externalevents/NotificationListener.java | 14 +++++++ .../externalevents/PhoneCallReceiver.java | 18 +++++++++ .../externalevents/SMSReceiver.java | 18 +++++++++ app/src/main/res/values/strings.xml | 2 + app/src/main/res/xml/preferences.xml | 7 ++++ 8 files changed, 120 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java index e17c4584..eb934346 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java @@ -1,15 +1,20 @@ package nodomain.freeyourgadget.gadgetbridge; import android.app.Application; +import android.app.NotificationManager.Policy; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.res.Resources; +import android.database.Cursor; +import android.net.Uri; import android.os.Build; import android.os.Build.VERSION; import android.preference.PreferenceManager; +import android.provider.ContactsContract; +import android.provider.ContactsContract.PhoneLookup; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import android.util.TypedValue; @@ -247,6 +252,41 @@ public class GBApplication extends Application { return VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; } + public static boolean isRunningMarshmallowOrLater() { + return VERSION.SDK_INT >= Build.VERSION_CODES.M; + } + + public static boolean isPriorityNumber(int prioritySenders, String number) { + Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)); + String[] projection = new String[]{PhoneLookup._ID, PhoneLookup.STARRED}; + Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null); + boolean exists = false; + int starred = 0; + try { + if (cursor.moveToFirst()) { + exists = true; + starred = cursor.getInt(cursor.getColumnIndexOrThrow(PhoneLookup.STARRED)); + } + } finally { + if (cursor != null) { + cursor.close(); + } + } + switch (prioritySenders) { + case Policy.PRIORITY_SENDERS_ANY: + return true; + case Policy.PRIORITY_SENDERS_CONTACTS: + if (exists) { + return true; + } + case Policy.PRIORITY_SENDERS_STARRED: + if (PhoneLookup.STARRED.equals(starred)) { + return true; + } + } + return false; + } + public static HashSet blacklist = null; private static void loadBlackList() { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java index c8bfe835..3684fab8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java @@ -1,13 +1,16 @@ package nodomain.freeyourgadget.gadgetbridge.activities; +import android.app.NotificationManager; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Bundle; import android.preference.ListPreference; import android.preference.Preference; +import android.preference.PreferenceCategory; import android.support.v4.content.LocalBroadcastManager; import android.widget.Toast; +import android.service.notification.NotificationListenerService; import java.io.IOException; import java.util.List; @@ -107,6 +110,12 @@ public class SettingsActivity extends AbstractSettingsActivity { }); + if (!GBApplication.isRunningMarshmallowOrLater()) { + pref = findPreference("notification_filter"); + PreferenceCategory category = (PreferenceCategory) findPreference("pref_key_notifications"); + category.removePreference(pref); + } + // Get all receivers of Media Buttons Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/K9Receiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/K9Receiver.java index 899ee0c6..732464aa 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/K9Receiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/K9Receiver.java @@ -1,5 +1,6 @@ package nodomain.freeyourgadget.gadgetbridge.externalevents; +import android.app.NotificationManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -33,6 +34,17 @@ public class K9Receiver extends BroadcastReceiver { return; } } + if (prefs.getBoolean("notification_filter", false) && GBApplication.isRunningMarshmallowOrLater()) { + NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE); + if (notificationManager.isNotificationPolicyAccessGranted()) { + switch (notificationManager.getCurrentInterruptionFilter()) { + case NotificationManager.INTERRUPTION_FILTER_ALARMS: + case NotificationManager.INTERRUPTION_FILTER_NONE: + case NotificationManager.INTERRUPTION_FILTER_PRIORITY: + return; + } + } + } String uriWanted = intent.getData().toString(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java index 9f93618b..d7d64088 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java @@ -3,6 +3,7 @@ package nodomain.freeyourgadget.gadgetbridge.externalevents; import android.annotation.SuppressLint; import android.app.ActivityManager; import android.app.Notification; +import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; @@ -167,6 +168,19 @@ public class NotificationListener extends NotificationListenerService { return; } } + if (prefs.getBoolean("notification_filter", false) && GBApplication.isRunningMarshmallowOrLater()) { + NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + if (notificationManager.isNotificationPolicyAccessGranted()) { + switch (notificationManager.getCurrentInterruptionFilter()) { + case NotificationManager.INTERRUPTION_FILTER_ALARMS: + case NotificationManager.INTERRUPTION_FILTER_NONE: + return; + case NotificationManager.INTERRUPTION_FILTER_PRIORITY: + // FIXME: Handle Reminders and Events if they are enabled in Do Not Disturb + return; + } + } + } String source = sbn.getPackageName(); Notification notification = sbn.getNotification(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PhoneCallReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PhoneCallReceiver.java index 496872db..eb344df1 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PhoneCallReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PhoneCallReceiver.java @@ -1,5 +1,6 @@ package nodomain.freeyourgadget.gadgetbridge.externalevents; +import android.app.NotificationManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -67,6 +68,23 @@ public class PhoneCallReceiver extends BroadcastReceiver { if ("never".equals(prefs.getString("notification_mode_calls", "always"))) { return; } + if (prefs.getBoolean("notification_filter", false) && GBApplication.isRunningMarshmallowOrLater()) { + NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE); + if (notificationManager.isNotificationPolicyAccessGranted()) { + switch (notificationManager.getCurrentInterruptionFilter()) { + case NotificationManager.INTERRUPTION_FILTER_ALARMS: + case NotificationManager.INTERRUPTION_FILTER_NONE: + return; + case NotificationManager.INTERRUPTION_FILTER_PRIORITY: + NotificationManager.Policy notificationPolicy = notificationManager.getNotificationPolicy(); + if (!GBApplication.isPriorityNumber(notificationPolicy.priorityCallSenders, mSavedNumber)) { + return; + } + // FIXME: Handle Repeat callers if it is enabled in Do Not Disturb + break; + } + } + } CallSpec callSpec = new CallSpec(); callSpec.number = mSavedNumber; callSpec.command = callCommand; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/SMSReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/SMSReceiver.java index 0404cbc2..05372ab3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/SMSReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/SMSReceiver.java @@ -1,11 +1,13 @@ package nodomain.freeyourgadget.gadgetbridge.externalevents; +import android.app.NotificationManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.PowerManager; import android.telephony.SmsMessage; +import android.util.Log; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; @@ -41,6 +43,22 @@ public class SMSReceiver extends BroadcastReceiver { notificationSpec.body = message.getDisplayMessageBody(); notificationSpec.phoneNumber = message.getOriginatingAddress(); if (notificationSpec.phoneNumber != null) { + if (prefs.getBoolean("notification_filter", false) && GBApplication.isRunningMarshmallowOrLater()) { + NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE); + if (notificationManager.isNotificationPolicyAccessGranted()) { + switch (notificationManager.getCurrentInterruptionFilter()) { + case NotificationManager.INTERRUPTION_FILTER_ALARMS: + case NotificationManager.INTERRUPTION_FILTER_NONE: + return; + case NotificationManager.INTERRUPTION_FILTER_PRIORITY: + NotificationManager.Policy notificationPolicy = notificationManager.getNotificationPolicy(); + if (!GBApplication.isPriorityNumber(notificationPolicy.priorityMessageSenders, notificationSpec.phoneNumber)) { + return; + } + break; + } + } + } GBApplication.deviceService().onNotification(notificationSpec); } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 133216e5..95f0f188 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -52,6 +52,8 @@ Support for applications which send Notifications to the Pebble via Intent. Can be used for Conversations. Generic notification support … also when screen is on + Do Not Disturb + Stop unwanted Notifications from being sent based on the Do Not Disturb mode. always when screen is off diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 4def8d01..6ae2be49 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -77,6 +77,13 @@ android:defaultValue="false" android:key="notifications_generic_whenscreenon" android:title="@string/pref_title_whenscreenon" /> + + + From 2e2030f67b8494d236a0b335e6b8f223ed8f1d02 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 19 May 2016 22:07:55 +0200 Subject: [PATCH 02/17] Update translations from transifex, thanks! --- app/src/main/res/values-es/strings.xml | 6 +----- app/src/main/res/values-fr/strings.xml | 2 +- app/src/main/res/values-it/strings.xml | 6 +----- app/src/main/res/values-ko/strings.xml | 3 ++- app/src/main/res/values-pl/strings.xml | 6 +----- app/src/main/res/values-ru/strings.xml | 6 +----- app/src/main/res/values-uk/strings.xml | 9 ++++----- app/src/main/res/values-vi/strings.xml | 3 --- 8 files changed, 11 insertions(+), 30 deletions(-) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 6dc1e3cc..adf7da93 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -69,8 +69,6 @@ Notificación de prueba desde Gadgetbridge Bluetooth no está soportado. Bluetooth está desactivado. - pulsa el dispositivo conectado para el Gestor de App - pulsa un dispositivo para conectar No se puede conectar. ¿Dirección BT incorrecta? Gadgetbridge funcionando instalando binario %1$d/%2$d @@ -101,13 +99,11 @@ No se han proporcionado datos de usuario válidos, se usarán datos de usuario por defecto. Cuando tu MiBand vibre y parpadee, púlsala repetidas veces. Instalar - Haz visible tu dispositivo. No es probable que se detecten los dispositivos que ya están conectados. Nota: Imagen del dispositivo Nombre/Apodo Número de vibraciones Monitor de sueño - Guardar logs iniciando Recuperando datos de actividad Desde %1$s a %2$s @@ -178,9 +174,9 @@ Pasos Actividad Pasos hoy, objetivo: %1$s + No confirmar transferencia Si los datos no son marcados como descargados, no serán borrados de tu MiBand. Útil si Gadgetbridge se usa conjuntamente con otras apps. Mantendrá los datos de actividad en la MiBand incluso después de la sincronización. Útil si GB se usa junto con otras apps. - No confirmar transferencia Historial de pasos Pasos/min actuales Pasos totales diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 4324f1f6..0ae83aa0 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -178,9 +178,9 @@ Pas Activité en direct Nombre de pas aujourd\'hui, objectif: %1$s + Ne pas confirmer le transfert de données d\'activités Les données d\'activités ne seront pas effacées du bracelet si elles ne sont pas confirmées. Utile si GB est utilisé avec d\'autres applications. Les données d\'activités seront conservées sur le Mi Band après la synchronisation. Utile si GB est utilisé avec d\'autres applications. - Ne pas confirmer le transfert de données d\'activités Historique de pas Pas/minute actuel Nombre total de pas diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 14f87afb..3f1e3135 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -70,8 +70,6 @@ Notifica di prova creata da Gadgetbridge Bluetooth non supportato. Bluetooth disabilitato. - tocca il dispositivo connesso per gestire le App - tocca il dispositivo da connettere Impossibile connettersi. Indirizzo BT non valido? Gadgetbridge in esecuzione installazione del binario %1$d/%2$d @@ -102,13 +100,11 @@ Dati dell\'utente non inseriti, vengono usati dati d\'esempio. Quando la Mi Band vibra e lampeggia, dalle qualche leggero colpetto. Installa - Imposta il tuo dispositivo perchè sia rilevabile. I dispositivi attualmente connessi non saranno probabilmente rilevati. Nota: Immagine dispositivo Nome / Soprannome Numero vibrazioni Monitoraggio del sonno - Salva il log su file inizializzazione in corso Recupero dati attività Da %1$s a %2$s @@ -179,9 +175,9 @@ Passi Attività in tempo reale Passi di oggi, traguardo: %1$s + Non confermare il trasferimento dati Se il trasferimento non viene confermato, i dati rimangono memorizzati sulla Mi Band. Utile se GB è usato insieme ad altre app. Conserva i dati delle attività sulla Mi Band anche dopo averli sincronizzati. Utile se GB è usato insieme ad altre app. - Non confermare il trasferimento dati Storico dei passi Passi/minuto Passi totali diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index ddce42bc..2afb4a02 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -181,9 +181,9 @@ 걸음 수 실시간 활동 오늘 걸음 수, 목표: %1$s + 활동 데이터 전송을 확인하지 않음 만약 활동 데이터가 밴드에 확인되지 않았다면, 지워지지 않을 것입니다. 가젯브릿지가 다른 앱들과 같이 사용될 때 유용합니다. 동기화 이후에도 Mi Band의 활동 데이터가 유지될 것입니다. 가젯브릿지가 다른 앱들과 같이 사용될 때 유용합니다. - 활동 데이터 전송을 확인하지 않음 걸음 수 기록 현재의 분당 걸음 수 전체 걸음 수 @@ -224,4 +224,5 @@ 펌웨어가 전송되지 않음 심박수 심박수 + 자동으로 재연결 diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index f1748748..bc0929a3 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -67,8 +67,6 @@ To jest testowe powiadomienie z Gadgetbridge Bluetooth nie jest obsługiwane Bluetooth jest wyłączone - Kliknij podłączone urządzenia dla zarządzania aplikacjami - kliknij urządzenie by połączyć Nie można połączyć. Adres BT nieprawidłowy? Gadgetbridge działa Instalowanie binarki %1$d/%2$d @@ -99,13 +97,11 @@ Brak prawidłowych danych użytkownika, używam danych zastępczych na ten moment. Gdy twój Mi Band wibruje i błyska, stuknij go kilka razy pod rząd. instaluj - Uwidocznij swoje urządzenie. Aktualnie połączone urządzenia prawdopodobnie nie będą znalezione. Uwaga Obraz urządzenia Nazwisko/Pseudonim Liczba wibracji Monitor snu - Zapisuj logi Uruchamianie Pobieranie danych aktywności Od %1$s do %2$s @@ -176,9 +172,9 @@ Kroki Ostatnia aktywność Kroków dziś, cel: %1$s + Nie wysyłaj danych aktywności Gdy dane aktywności nie są przesłane na opaskę, wtedy nie będą usuwane. Przydatne gdy Gadgetbridge jest używany wraz z innymi aplikacjami Dane aktywności będą zachowane na Mi Band nawet po synchronizacji. Przydatne gdy Gadgetbridge jest używany z innymi aplikacjami. - Nie wysyłaj danych aktywności Historia kroków Aktualnie kroków/min Kroków łącznie diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 5039e880..5ea805eb 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -68,8 +68,6 @@ Это тестовое уведомление от Gadgetbridge Bluetooth не поддерживается. Bluetooth отключён. - нажмите на подключённое устройство для App Manager - нажмите на устройство для соединения Не удалось соединиться. Неверен адрес BT? Gadgetbridge запущен установки бинарного файла %1$d/%2$d @@ -100,13 +98,11 @@ Не предоставлено действительных данных пользователя. Используются данные по-умолчанию. Когда ваш Mi Band вибрирует и мигает, постучите по нему несколько раз. Установить - Подключённые в настоящее время устройства, скорее всего, не будут обнаружены. Заметка: Изображение устройства Имя/псевдоним Количество вибраций Анализ сна - Записывать файлы журнала Инициализация Получение данных активности От %1$s до %2$s @@ -177,9 +173,9 @@ Шаги Жизненная активность Шагов сегодня, цель: %1$s + Не передавать данные об активности Если данные об активности не будут переданы на устройство, оно не будет очищено. Полезно, если GB используется с другими приложениями. Хранить данные о деятельности на Mi Band, даже после синхронизации. Полезно, если Mi Band используется совместно с другими приложениями. - Не передавать данные об активности История шагов Текущие шаги в минуту Всего шагов diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index f0d6f36a..7f79179f 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -31,6 +31,9 @@ Дата і час Синхронізувати час під час з\'єднання Синхронізувати час під час з\'єднання з пристроєм, а також під час зміни часу чи часової зони в системі + Тема + Світла + Темна Сповіщення Повтори Виклики @@ -67,8 +70,6 @@ Це тестове сповіщення від Gadgetbridge Bluetooth не підтримується. Bluetooth вимкнуто. - натисніть на під\'єднаний пристрій для App Manager - натисніть на пристрій для з\'єднання Не вдалося з\'єднатися. Можливо помилкова адреса BT? Gadgetbridge запущено встановлення бінарного файлу %1$d/%2$d @@ -99,13 +100,11 @@ Не отримано дійсних даних користувача. Використовуються типові дані. Коли ваш Mi—Band вібрує та блимає, постукайте по ньому кілька раз. Встановити - Під\'єднані на даний момент пристрої, скоріш за все не будуть виявлені. Замітка: Зображення пристрою Ім\'я/нік Кількість вібрацій Аналіз сну - Записувати файли звіту Ініціалізація… Отримання даних активності Від %1$s до %2$s @@ -176,9 +175,9 @@ Кроки Життєва активність Кроків сьогодні, мета: %1$s + Не передавати дані про активність Якщо дані не будуть передані на пристрій, пристрій не буде очищений. Корисно, якщо Gadgetbridge використовується разом з іншими додатками. Дозволяє лишити дані на Mi-браслеті після синхронізації. Зазвичай використовується, якщо GB працює ще з іншими додатками. - Не передавати дані про активність Історія кроків Поточні кроки/хв Загалом кроків diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index af3de63c..f41f8478 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -52,8 +52,6 @@ Đây là một kiểm tra thông báo từ Gadgetbridge Không hỗ trợ Bluetooth. Đã tắt Bluetooth. - chạm vào thiết bị đã kết nối để chạy Trình quản lý ứng dụng - chạm vào một thiết bị để kết nối Không thể kết nối. Địa chỉ BT không hợp lệ? Gadgetbridge đang chạy đang cài phần mềm chạy %1$d/%2$d @@ -83,7 +81,6 @@ Ảnh thiết bị Tên/Bí danh Trình giám sát giấc ngủ - Ghi tập tin nhật ký đang khởi chạy Từ %1$s đến %2$s Đeo bên trái hay phải? From cfed531ad0a45892925198e8c9515db15a3225f7 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 19 May 2016 22:33:27 +0200 Subject: [PATCH 03/17] Add list of contributors --- CONTRIBUTORS.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 CONTRIBUTORS.md diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md new file mode 100644 index 00000000..752c6abb --- /dev/null +++ b/CONTRIBUTORS.md @@ -0,0 +1,27 @@ + Andreas Shimokawa + cpfeiffer + Daniele Gobbetti + Daniele Gobbetti + danielegobbetti + Carsten Pfeiffer + Julien Pivotto + Lem Dulfo + Sergey Trofimov + Daniele Gobbetti + cpfeiffer + 0nse <0nse@users.noreply.github.com> + Christian Fischer + Ⲇⲁⲛⲓ Φi + xphnx + Tarik Sekmen + rober + Nicolò Balzarotti + Marc Schlaich + kevlarcade + Kasha + Chris Perelstein + Alexey Afanasev + +And all the Transifex translators, which I cannot automatically list, at the moment. + +git log --raw | grep "^Author: " | sort | uniq -c | sort -k 1 -n -r | cut -f 2- -d: > CONTRIBUTORS.md From 31eabe960527f5fa853e6e2d880dbfd1556f563e Mon Sep 17 00:00:00 2001 From: Normano64 Date: Thu, 19 May 2016 23:58:13 +0200 Subject: [PATCH 04/17] Fixed things based on feedback --- .../gadgetbridge/GBApplication.java | 77 ++++++++++++------- .../activities/SettingsActivity.java | 2 - .../externalevents/K9Receiver.java | 17 ++-- .../externalevents/NotificationListener.java | 21 +++-- .../externalevents/PhoneCallReceiver.java | 27 +++---- .../externalevents/SMSReceiver.java | 26 +++---- 6 files changed, 90 insertions(+), 80 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java index eb934346..e1aa01a2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java @@ -1,6 +1,7 @@ package nodomain.freeyourgadget.gadgetbridge; import android.app.Application; +import android.app.NotificationManager; import android.app.NotificationManager.Policy; import android.content.BroadcastReceiver; import android.content.Context; @@ -13,7 +14,6 @@ import android.net.Uri; import android.os.Build; import android.os.Build.VERSION; import android.preference.PreferenceManager; -import android.provider.ContactsContract; import android.provider.ContactsContract.PhoneLookup; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; @@ -64,6 +64,7 @@ public class GBApplication extends Application { private static Appender fileLogger; private static Prefs prefs; private static GBPrefs gbPrefs; + private static NotificationManager notificationManager; public static final String ACTION_QUIT = "nodomain.freeyourgadget.gadgetbridge.gbapplication.action.quit"; @@ -124,6 +125,10 @@ public class GBApplication extends Application { filterLocal.addAction(ACTION_QUIT); LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filterLocal); + if (isRunningMarshmallowOrLater()) { + notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE); + } + // for testing DB stuff // SQLiteDatabase db = mActivityDatabaseHandler.getWritableDatabase(); // db.close(); @@ -256,37 +261,57 @@ public class GBApplication extends Application { return VERSION.SDK_INT >= Build.VERSION_CODES.M; } - public static boolean isPriorityNumber(int prioritySenders, String number) { - Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)); - String[] projection = new String[]{PhoneLookup._ID, PhoneLookup.STARRED}; - Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null); - boolean exists = false; - int starred = 0; - try { - if (cursor.moveToFirst()) { - exists = true; - starred = cursor.getInt(cursor.getColumnIndexOrThrow(PhoneLookup.STARRED)); + private static boolean isPrioritySender(int prioritySenders, String number) { + if (prioritySenders == Policy.PRIORITY_SENDERS_ANY) { + return true; + } else { + Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)); + String[] projection = new String[]{PhoneLookup._ID, PhoneLookup.STARRED}; + Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null); + boolean exists = false; + int starred = 0; + try { + if (cursor.moveToFirst()) { + exists = true; + starred = cursor.getInt(cursor.getColumnIndexOrThrow(PhoneLookup.STARRED)); + } + } finally { + if (cursor != null) { + cursor.close(); + } } - } finally { - if (cursor != null) { - cursor.close(); - } - } - switch (prioritySenders) { - case Policy.PRIORITY_SENDERS_ANY: + if (prioritySenders == Policy.PRIORITY_SENDERS_CONTACTS && exists) { return true; - case Policy.PRIORITY_SENDERS_CONTACTS: - if (exists) { - return true; - } - case Policy.PRIORITY_SENDERS_STARRED: - if (PhoneLookup.STARRED.equals(starred)) { - return true; - } + } else if (prioritySenders == Policy.PRIORITY_SENDERS_STARRED && starred == 1) { + return true; + } + return false; + } + } + + public static boolean isPriorityNumber(int priorityType, String number) { + NotificationManager.Policy notificationPolicy = notificationManager.getNotificationPolicy(); + if(priorityType == Policy.PRIORITY_CATEGORY_MESSAGES) { + if ((notificationPolicy.priorityCategories & Policy.PRIORITY_CATEGORY_MESSAGES) == Policy.PRIORITY_CATEGORY_MESSAGES) { + return isPrioritySender(notificationPolicy.priorityMessageSenders, number); + } + } else if (priorityType == Policy.PRIORITY_CATEGORY_CALLS) { + if ((notificationPolicy.priorityCategories & Policy.PRIORITY_CATEGORY_CALLS) == Policy.PRIORITY_CATEGORY_CALLS) { + return isPrioritySender(notificationPolicy.priorityCallSenders, number); + } } return false; } + public static int getGrantedInterruptionFilter() { + if (prefs.getBoolean("notification_filter", false) && GBApplication.isRunningMarshmallowOrLater()) { + if (notificationManager.isNotificationPolicyAccessGranted()) { + return notificationManager.getCurrentInterruptionFilter(); + } + } + return NotificationManager.INTERRUPTION_FILTER_ALL; + } + public static HashSet blacklist = null; private static void loadBlackList() { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java index 3684fab8..c6479695 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java @@ -1,6 +1,5 @@ package nodomain.freeyourgadget.gadgetbridge.activities; -import android.app.NotificationManager; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; @@ -10,7 +9,6 @@ import android.preference.Preference; import android.preference.PreferenceCategory; import android.support.v4.content.LocalBroadcastManager; import android.widget.Toast; -import android.service.notification.NotificationListenerService; import java.io.IOException; import java.util.List; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/K9Receiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/K9Receiver.java index 732464aa..439c34b0 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/K9Receiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/K9Receiver.java @@ -34,16 +34,13 @@ public class K9Receiver extends BroadcastReceiver { return; } } - if (prefs.getBoolean("notification_filter", false) && GBApplication.isRunningMarshmallowOrLater()) { - NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE); - if (notificationManager.isNotificationPolicyAccessGranted()) { - switch (notificationManager.getCurrentInterruptionFilter()) { - case NotificationManager.INTERRUPTION_FILTER_ALARMS: - case NotificationManager.INTERRUPTION_FILTER_NONE: - case NotificationManager.INTERRUPTION_FILTER_PRIORITY: - return; - } - } + switch (GBApplication.getGrantedInterruptionFilter()) { + case NotificationManager.INTERRUPTION_FILTER_ALL: + break; + case NotificationManager.INTERRUPTION_FILTER_ALARMS: + case NotificationManager.INTERRUPTION_FILTER_NONE: + case NotificationManager.INTERRUPTION_FILTER_PRIORITY: + return; } String uriWanted = intent.getData().toString(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java index d7d64088..a3c3d37c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java @@ -168,18 +168,15 @@ public class NotificationListener extends NotificationListenerService { return; } } - if (prefs.getBoolean("notification_filter", false) && GBApplication.isRunningMarshmallowOrLater()) { - NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); - if (notificationManager.isNotificationPolicyAccessGranted()) { - switch (notificationManager.getCurrentInterruptionFilter()) { - case NotificationManager.INTERRUPTION_FILTER_ALARMS: - case NotificationManager.INTERRUPTION_FILTER_NONE: - return; - case NotificationManager.INTERRUPTION_FILTER_PRIORITY: - // FIXME: Handle Reminders and Events if they are enabled in Do Not Disturb - return; - } - } + switch (GBApplication.getGrantedInterruptionFilter()) { + case NotificationManager.INTERRUPTION_FILTER_ALL: + break; + case NotificationManager.INTERRUPTION_FILTER_ALARMS: + case NotificationManager.INTERRUPTION_FILTER_NONE: + return; + case NotificationManager.INTERRUPTION_FILTER_PRIORITY: + // FIXME: Handle Reminders and Events if they are enabled in Do Not Disturb + return; } String source = sbn.getPackageName(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PhoneCallReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PhoneCallReceiver.java index eb344df1..29693538 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PhoneCallReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PhoneCallReceiver.java @@ -1,6 +1,7 @@ package nodomain.freeyourgadget.gadgetbridge.externalevents; import android.app.NotificationManager; +import android.app.NotificationManager.Policy; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -68,22 +69,18 @@ public class PhoneCallReceiver extends BroadcastReceiver { if ("never".equals(prefs.getString("notification_mode_calls", "always"))) { return; } - if (prefs.getBoolean("notification_filter", false) && GBApplication.isRunningMarshmallowOrLater()) { - NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE); - if (notificationManager.isNotificationPolicyAccessGranted()) { - switch (notificationManager.getCurrentInterruptionFilter()) { - case NotificationManager.INTERRUPTION_FILTER_ALARMS: - case NotificationManager.INTERRUPTION_FILTER_NONE: - return; - case NotificationManager.INTERRUPTION_FILTER_PRIORITY: - NotificationManager.Policy notificationPolicy = notificationManager.getNotificationPolicy(); - if (!GBApplication.isPriorityNumber(notificationPolicy.priorityCallSenders, mSavedNumber)) { - return; - } - // FIXME: Handle Repeat callers if it is enabled in Do Not Disturb - break; + switch (GBApplication.getGrantedInterruptionFilter()) { + case NotificationManager.INTERRUPTION_FILTER_ALL: + break; + case NotificationManager.INTERRUPTION_FILTER_ALARMS: + case NotificationManager.INTERRUPTION_FILTER_NONE: + return; + case NotificationManager.INTERRUPTION_FILTER_PRIORITY: + if (GBApplication.isPriorityNumber(Policy.PRIORITY_CATEGORY_CALLS, mSavedNumber)) { + break; } - } + // FIXME: Handle Repeat callers if it is enabled in Do Not Disturb + return; } CallSpec callSpec = new CallSpec(); callSpec.number = mSavedNumber; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/SMSReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/SMSReceiver.java index 05372ab3..5df07c8d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/SMSReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/SMSReceiver.java @@ -1,13 +1,13 @@ package nodomain.freeyourgadget.gadgetbridge.externalevents; import android.app.NotificationManager; +import android.app.NotificationManager.Policy; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.PowerManager; import android.telephony.SmsMessage; -import android.util.Log; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; @@ -43,21 +43,17 @@ public class SMSReceiver extends BroadcastReceiver { notificationSpec.body = message.getDisplayMessageBody(); notificationSpec.phoneNumber = message.getOriginatingAddress(); if (notificationSpec.phoneNumber != null) { - if (prefs.getBoolean("notification_filter", false) && GBApplication.isRunningMarshmallowOrLater()) { - NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE); - if (notificationManager.isNotificationPolicyAccessGranted()) { - switch (notificationManager.getCurrentInterruptionFilter()) { - case NotificationManager.INTERRUPTION_FILTER_ALARMS: - case NotificationManager.INTERRUPTION_FILTER_NONE: - return; - case NotificationManager.INTERRUPTION_FILTER_PRIORITY: - NotificationManager.Policy notificationPolicy = notificationManager.getNotificationPolicy(); - if (!GBApplication.isPriorityNumber(notificationPolicy.priorityMessageSenders, notificationSpec.phoneNumber)) { - return; - } - break; + switch (GBApplication.getGrantedInterruptionFilter()) { + case NotificationManager.INTERRUPTION_FILTER_ALL: + break; + case NotificationManager.INTERRUPTION_FILTER_ALARMS: + case NotificationManager.INTERRUPTION_FILTER_NONE: + return; + case NotificationManager.INTERRUPTION_FILTER_PRIORITY: + if (GBApplication.isPriorityNumber(Policy.PRIORITY_CATEGORY_MESSAGES, notificationSpec.phoneNumber)) { + break; } - } + return; } GBApplication.deviceService().onNotification(notificationSpec); } From a97efe15132c20548dcb1c9cc3639dd76984bf2c Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Fri, 20 May 2016 21:31:30 +0200 Subject: [PATCH 05/17] Updated contributors --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 752c6abb..1637e814 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -11,6 +11,7 @@ cpfeiffer 0nse <0nse@users.noreply.github.com> Christian Fischer + Normano64 Ⲇⲁⲛⲓ Φi xphnx Tarik Sekmen From 400ae2bc3b9914b92a2b5dc6ae2e7848f0f0bc71 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Fri, 20 May 2016 21:49:25 +0200 Subject: [PATCH 06/17] Fix lint warnings using @TargetApi --- .../nodomain/freeyourgadget/gadgetbridge/GBApplication.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java index e1aa01a2..6e5043fa 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java @@ -1,5 +1,6 @@ package nodomain.freeyourgadget.gadgetbridge; +import android.annotation.TargetApi; import android.app.Application; import android.app.NotificationManager; import android.app.NotificationManager.Policy; @@ -289,6 +290,7 @@ public class GBApplication extends Application { } } + @TargetApi(Build.VERSION_CODES.M) public static boolean isPriorityNumber(int priorityType, String number) { NotificationManager.Policy notificationPolicy = notificationManager.getNotificationPolicy(); if(priorityType == Policy.PRIORITY_CATEGORY_MESSAGES) { @@ -303,6 +305,7 @@ public class GBApplication extends Application { return false; } + @TargetApi(Build.VERSION_CODES.M) public static int getGrantedInterruptionFilter() { if (prefs.getBoolean("notification_filter", false) && GBApplication.isRunningMarshmallowOrLater()) { if (notificationManager.isNotificationPolicyAccessGranted()) { From d5cca847804841d8eb0f2a47edf6565587ea49b5 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Fri, 20 May 2016 22:04:30 +0200 Subject: [PATCH 07/17] Small fixlets --- .../freeyourgadget/gadgetbridge/GBApplication.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java index 6e5043fa..073689a8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java @@ -65,6 +65,9 @@ public class GBApplication extends Application { private static Appender fileLogger; private static Prefs prefs; private static GBPrefs gbPrefs; + /** + * Note: is null on Lollipop and Kitkat + */ private static NotificationManager notificationManager; public static final String ACTION_QUIT @@ -127,7 +130,7 @@ public class GBApplication extends Application { LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filterLocal); if (isRunningMarshmallowOrLater()) { - notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE); + notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); } // for testing DB stuff @@ -272,7 +275,7 @@ public class GBApplication extends Application { boolean exists = false; int starred = 0; try { - if (cursor.moveToFirst()) { + if (cursor != null && cursor.moveToFirst()) { exists = true; starred = cursor.getInt(cursor.getColumnIndexOrThrow(PhoneLookup.STARRED)); } From 0d7986a5ab59e0ac474b49e5fada2ed5462f689b Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 22 May 2016 01:19:28 +0200 Subject: [PATCH 08/17] Pebble: rework incoming reconnection support This is now completely generic and should work for other devices also Fixes #296 --- .../BluetoothConnectReceiver.java | 43 ++++++++++++++++ .../service/DeviceCommunicationService.java | 20 ++++++++ .../devices/pebble/PebbleIoThread.java | 49 ++++--------------- .../service/devices/pebble/PebbleSupport.java | 1 + 4 files changed, 74 insertions(+), 39 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothConnectReceiver.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothConnectReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothConnectReceiver.java new file mode 100644 index 00000000..5282e7a5 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothConnectReceiver.java @@ -0,0 +1,43 @@ +package nodomain.freeyourgadget.gadgetbridge.externalevents; + +import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService; + +public class BluetoothConnectReceiver extends BroadcastReceiver { + + private static final Logger LOG = LoggerFactory.getLogger(DeviceCommunicationService.class); + + final DeviceCommunicationService service; + + public BluetoothConnectReceiver(DeviceCommunicationService service) { + this.service = service; + } + + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (!action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) { + return; + } + LOG.info("got connection attempt"); + GBDevice gbDevice = service.getGBDevice(); + if (gbDevice != null) { + BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + if (device.getAddress().equals(gbDevice.getAddress())) { + LOG.info("will connect to " + gbDevice.getName()); + GBApplication.deviceService().connect(); + } else { + LOG.info("won't connect to " + device.getAddress() + "(" + device.getName() + ")"); + } + } + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java index 7738f40c..37d217f8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -2,6 +2,7 @@ package nodomain.freeyourgadget.gadgetbridge.service; import android.app.NotificationManager; import android.app.Service; +import android.bluetooth.BluetoothDevice; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -24,6 +25,7 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.externalevents.BluetoothConnectReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.K9Receiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.MusicPlaybackReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.PebbleReceiver; @@ -105,6 +107,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere private PebbleReceiver mPebbleReceiver = null; private MusicPlaybackReceiver mMusicPlaybackReceiver = null; private TimeChangeReceiver mTimeChangeReceiver = null; + private BluetoothConnectReceiver mBlueToothConnectReceiver = null; private Random mRandom = new Random(); @@ -279,6 +282,11 @@ public class DeviceCommunicationService extends Service implements SharedPrefere } case ACTION_DISCONNECT: { mDeviceSupport.dispose(); + if (mGBDevice != null && mGBDevice.getState() == GBDevice.State.WAITING_FOR_RECONNECT) { + setReceiversEnableState(false); + mGBDevice.setState(GBDevice.State.NOT_CONNECTED); + mGBDevice.sendDeviceUpdateIntent(this); + } mDeviceSupport = null; break; } @@ -457,6 +465,10 @@ public class DeviceCommunicationService extends Service implements SharedPrefere filter.addAction("android.intent.action.TIMEZONE_CHANGED"); registerReceiver(mTimeChangeReceiver, filter); } + if (mBlueToothConnectReceiver == null) { + mBlueToothConnectReceiver = new BluetoothConnectReceiver(this); + registerReceiver(mBlueToothConnectReceiver, new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED)); + } } else { if (mPhoneCallReceiver != null) { unregisterReceiver(mPhoneCallReceiver); @@ -482,6 +494,10 @@ public class DeviceCommunicationService extends Service implements SharedPrefere unregisterReceiver(mTimeChangeReceiver); mTimeChangeReceiver = null; } + if (mBlueToothConnectReceiver != null) { + unregisterReceiver(mBlueToothConnectReceiver); + mBlueToothConnectReceiver = null; + } } } @@ -549,4 +565,8 @@ public class DeviceCommunicationService extends Service implements SharedPrefere public GBPrefs getGBPrefs() { return GBApplication.getGBPrefs(); } + + public GBDevice getGBDevice() { + return mGBDevice; + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java index 43b86e2f..a14fb496 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java @@ -2,7 +2,6 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothServerSocket; import android.bluetooth.BluetoothSocket; import android.content.BroadcastReceiver; import android.content.Context; @@ -48,9 +47,6 @@ import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class PebbleIoThread extends GBDeviceIoThread { private static final Logger LOG = LoggerFactory.getLogger(PebbleIoThread.class); - private static final UUID PEBBLE_UUID_RECONNECT = UUID.fromString("00000000-deca-fade-deca-deafdecacafe"); - private static final UUID PEBBLE_UUID_RECONNECT3X = UUID.fromString("a924496e-cc7c-4dff-8a9f-9a76cc2e9d50"); - public static final String PEBBLEKIT_ACTION_PEBBLE_CONNECTED = "com.getpebble.action.PEBBLE_CONNECTED"; public static final String PEBBLEKIT_ACTION_PEBBLE_DISCONNECTED = "com.getpebble.action.PEBBLE_DISCONNECTED"; public static final String PEBBLEKIT_ACTION_APP_ACK = "com.getpebble.action.app.ACK"; @@ -71,7 +67,6 @@ public class PebbleIoThread extends GBDeviceIoThread { private boolean mIsTCP = false; private BluetoothAdapter mBtAdapter = null; private BluetoothSocket mBtSocket = null; - private BluetoothServerSocket mBtServerSocket = null; private Socket mTCPSocket = null; // for emulator private InputStream mInStream = null; private OutputStream mOutStream = null; @@ -365,7 +360,7 @@ public class PebbleIoThread extends GBDeviceIoThread { LOG.info(e.getMessage()); mIsConnected = false; int reconnectAttempts = prefs.getInt("pebble_reconnect_attempts", 10); - if (GBApplication.getGBPrefs().getAutoReconnect() && reconnectAttempts > 0) { + if (!mQuit && GBApplication.getGBPrefs().getAutoReconnect() && reconnectAttempts > 0) { gbDevice.setState(GBDevice.State.CONNECTING); gbDevice.sendDeviceUpdateIntent(getContext()); int delaySeconds = 1; @@ -383,33 +378,10 @@ public class PebbleIoThread extends GBDeviceIoThread { } } } - if (!mIsConnected && !mQuit) { - try { - gbDevice.setState(GBDevice.State.WAITING_FOR_RECONNECT); - gbDevice.sendDeviceUpdateIntent(getContext()); - UUID reconnectUUID = mPebbleProtocol.isFw3x ? PEBBLE_UUID_RECONNECT3X : PEBBLE_UUID_RECONNECT; - mBtServerSocket = mBtAdapter.listenUsingRfcommWithServiceRecord("PebbleReconnectListener", reconnectUUID); - mBtSocket = mBtServerSocket.accept(); - LOG.info("incoming connection on reconnect uuid (" + reconnectUUID + "), will connect actively"); - mBtSocket.close(); - mIsConnected = connect(gbDevice.getAddress()); - } catch (IOException ex) { - ex.printStackTrace(); - LOG.info("error while reconnecting"); - } finally { - try { - if (mBtServerSocket != null) { - mBtServerSocket.close(); - mBtServerSocket = null; - } - } catch (IOException ignore) { - } - } - } if (!mIsConnected) { mBtSocket = null; LOG.info("Bluetooth socket closed, will quit IO Thread"); - mQuit = true; + break; } } } @@ -421,10 +393,16 @@ public class PebbleIoThread extends GBDeviceIoThread { } catch (IOException e) { e.printStackTrace(); } + mBtSocket = null; } + enablePebbleKitReceiver(false); - mBtSocket = null; - gbDevice.setState(GBDevice.State.NOT_CONNECTED); + + if (mQuit) { + gbDevice.setState(GBDevice.State.NOT_CONNECTED); + } else { + gbDevice.setState(GBDevice.State.WAITING_FOR_RECONNECT); + } gbDevice.sendDeviceUpdateIntent(getContext()); } @@ -700,13 +678,6 @@ public class PebbleIoThread extends GBDeviceIoThread { e.printStackTrace(); } } - if (mBtServerSocket != null) { - try { - mBtServerSocket.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } if (mTCPSocket != null) { try { mTCPSocket.close(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleSupport.java index 74e4736d..e396d03f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleSupport.java @@ -78,6 +78,7 @@ public class PebbleSupport extends AbstractSerialDeviceSupport { private boolean reconnect() { if (!isConnected() && useAutoConnect()) { if (getDevice().getState() == GBDevice.State.WAITING_FOR_RECONNECT) { + gbDeviceIOThread.quit(); gbDeviceIOThread.interrupt(); gbDeviceIOThread = null; if (!connect()) { From ca714417ac3e511448e4e2f174c15e7b4bf0c2a2 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 22 May 2016 11:33:14 +0200 Subject: [PATCH 09/17] Pebble: also copy pbw to cache on Firmware 2.x Neccessary step towards watchface configuration on 2.x --- .../gadgetbridge/devices/pebble/PBWInstallHandler.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PBWInstallHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PBWInstallHandler.java index 30becd11..9d66c0db 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PBWInstallHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PBWInstallHandler.java @@ -129,10 +129,6 @@ public class PBWInstallHandler implements InstallHandler { return; } - if (!device.getFirmwareVersion().startsWith("v3")) { - return; - } - File destDir; GBDeviceApp app = mPBWReader.getGBDeviceApp(); try { From 5a20d7ec810e7005818c8ad1c291f179e925af4f Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 22 May 2016 12:30:47 +0200 Subject: [PATCH 10/17] Pebble: no longer clear list of cached apps as soon as the installed watchfaces is received from Firmware 2.x This will result in duplicate entries (first the whole cache, then actually installed watchfaces) It might already make watchface configuation working on 2.x even though it is dirty I wish everybody would just update to 3.x *sigh* --- .../gadgetbridge/activities/AppManagerActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java index 2e6bbba0..e82d1b23 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java @@ -47,7 +47,7 @@ public class AppManagerActivity extends GBActivity { if (action.equals(GBApplication.ACTION_QUIT)) { finish(); } else if (action.equals(ACTION_REFRESH_APPLIST)) { - appList.clear(); + //appList.clear(); int appCount = intent.getIntExtra("app_count", 0); for (Integer i = 0; i < appCount; i++) { String appName = intent.getStringExtra("app_name" + i.toString()); From 30883ab244dec5b27bafa8720cf8d45b8ea42a95 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 22 May 2016 22:48:45 +0200 Subject: [PATCH 11/17] Pebble: In AppManager mark cached apps with (C), installed apps on FW 2.x with (D) and (CD) if both is the case Also always add pebble health as a system app to the list on devices that have it (no need to enable untested features for that anymore) --- .../activities/AppManagerActivity.java | 32 ++++++++++++------- .../adapter/GBDeviceAppAdapter.java | 10 +++++- .../gadgetbridge/impl/GBDeviceApp.java | 10 ++++++ 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java index e82d1b23..56a324dd 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java @@ -22,6 +22,7 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.ListIterator; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.GBApplication; @@ -47,7 +48,6 @@ public class AppManagerActivity extends GBActivity { if (action.equals(GBApplication.ACTION_QUIT)) { finish(); } else if (action.equals(ACTION_REFRESH_APPLIST)) { - //appList.clear(); int appCount = intent.getIntExtra("app_count", 0); for (Integer i = 0; i < appCount; i++) { String appName = intent.getStringExtra("app_name" + i.toString()); @@ -55,11 +55,21 @@ public class AppManagerActivity extends GBActivity { UUID uuid = UUID.fromString(intent.getStringExtra("app_uuid" + i.toString())); GBDeviceApp.Type appType = GBDeviceApp.Type.values()[intent.getIntExtra("app_type" + i.toString(), 0)]; - appList.add(new GBDeviceApp(uuid, appName, appCreator, "", appType)); - } - - if (prefs.getBoolean("pebble_force_untested", false)) { - appList.addAll(getSystemApps()); + boolean found = false; + for (final ListIterator iter = appList.listIterator(); iter.hasNext(); ) { + final GBDeviceApp app = iter.next(); + if (app.getName().equals(appName) && app.getCreator().equals(appCreator)) { + app.setOnDevice(true); + iter.set(app); + found = true; + break; + } + } + if (!found) { + GBDeviceApp app = new GBDeviceApp(uuid, appName, appCreator, "", appType); + app.setOnDevice(true); + appList.add(app); + } } mGBDeviceAppAdapter.notifyDataSetChanged(); @@ -76,8 +86,10 @@ public class AppManagerActivity extends GBActivity { private List getSystemApps() { List systemApps = new ArrayList<>(); - systemApps.add(new GBDeviceApp(UUID.fromString("4dab81a6-d2fc-458a-992c-7a1f3b96a970"), "Sports (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM)); - systemApps.add(new GBDeviceApp(UUID.fromString("cf1e816a-9db0-4511-bbb8-f60c48ca8fac"), "Golf (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM)); + if (prefs.getBoolean("pebble_force_untested", false)) { + systemApps.add(new GBDeviceApp(UUID.fromString("4dab81a6-d2fc-458a-992c-7a1f3b96a970"), "Sports (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM)); + systemApps.add(new GBDeviceApp(UUID.fromString("cf1e816a-9db0-4511-bbb8-f60c48ca8fac"), "Golf (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM)); + } if (mGBDevice != null && !"aplite".equals(PebbleUtils.getPlatformName(mGBDevice.getHardwareVersion()))) { systemApps.add(new GBDeviceApp(PebbleProtocol.UUID_PEBBLE_HEALTH, "Health (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM)); } @@ -149,9 +161,7 @@ public class AppManagerActivity extends GBActivity { appList.addAll(getCachedApps()); - if (prefs.getBoolean("pebble_force_untested", false)) { - appList.addAll(getSystemApps()); - } + appList.addAll(getSystemApps()); IntentFilter filter = new IntentFilter(); filter.addAction(GBApplication.ACTION_QUIT); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAppAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAppAdapter.java index 5a813792..d4ae263f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAppAdapter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAppAdapter.java @@ -41,7 +41,15 @@ public class GBDeviceAppAdapter extends ArrayAdapter { ImageView deviceImageView = (ImageView) view.findViewById(R.id.item_image); deviceAppVersionAuthorLabel.setText(getContext().getString(R.string.appversion_by_creator, deviceApp.getVersion(), deviceApp.getCreator())); - deviceAppNameLabel.setText(deviceApp.getName()); + + // FIXME: replace with small icons + String appNameLabelText = deviceApp.getName(); + if (deviceApp.isInCache() || deviceApp.isOnDevice()) { + appNameLabelText += " (" + (deviceApp.isInCache() ? "C" : "") + + (deviceApp.isOnDevice() ? "D" : "") + ")"; + } + deviceAppNameLabel.setText(appNameLabelText); + switch (deviceApp.getType()) { case APP_GENERIC: deviceImageView.setImageResource(R.drawable.ic_watchapp); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceApp.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceApp.java index d2280d17..f5587645 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceApp.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceApp.java @@ -12,6 +12,7 @@ public class GBDeviceApp { private final UUID uuid; private final Type type; private final boolean inCache; + private boolean isOnDevice; private final boolean configurable; public GBDeviceApp(UUID uuid, String name, String creator, String version, Type type) { @@ -23,6 +24,7 @@ public class GBDeviceApp { //FIXME: do not assume this.inCache = false; this.configurable = false; + this.isOnDevice = false; } public GBDeviceApp(JSONObject json, boolean configurable) { @@ -52,10 +54,18 @@ public class GBDeviceApp { this.configurable = configurable; } + public void setOnDevice(boolean isOnDevice) { + this.isOnDevice = isOnDevice; + } + public boolean isInCache() { return inCache; } + public boolean isOnDevice() { + return isOnDevice; + } + public String getName() { return name; } From 80cf9fa8fe1c0aa976b4aff791f6a2bc0f55ffe0 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 22 May 2016 23:32:25 +0200 Subject: [PATCH 12/17] Pebble: allow to delete apps from pbw cache Also remove delete entries from all system apps' context menus (not only health) --- .../activities/AppManagerActivity.java | 36 ++++++++++++++++--- app/src/main/res/menu/appmanager_context.xml | 3 ++ app/src/main/res/values/strings.xml | 2 +- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java index 56a324dd..de5147e9 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java @@ -58,7 +58,7 @@ public class AppManagerActivity extends GBActivity { boolean found = false; for (final ListIterator iter = appList.listIterator(); iter.hasNext(); ) { final GBDeviceApp app = iter.next(); - if (app.getName().equals(appName) && app.getCreator().equals(appCreator)) { + if (app.getUUID().equals(uuid)) { app.setOnDevice(true); iter.set(app); found = true; @@ -181,11 +181,13 @@ public class AppManagerActivity extends GBActivity { if (!selectedApp.isInCache()) { menu.removeItem(R.id.appmanager_app_reinstall); + menu.removeItem(R.id.appmanager_app_delete_cache); } if (!PebbleProtocol.UUID_PEBBLE_HEALTH.equals(selectedApp.getUUID())) { menu.removeItem(R.id.appmanager_health_activate); menu.removeItem(R.id.appmanager_health_deactivate); - } else if (PebbleProtocol.UUID_PEBBLE_HEALTH.equals(selectedApp.getUUID())) { + } + if (selectedApp.getType() == GBDeviceApp.Type.APP_SYSTEM) { menu.removeItem(R.id.appmanager_app_delete); } if (!selectedApp.isConfigurable()) { @@ -194,19 +196,45 @@ public class AppManagerActivity extends GBActivity { menu.setHeaderTitle(selectedApp.getName()); } + private void removeAppFromList(UUID uuid) { + for (final ListIterator iter = appList.listIterator(); iter.hasNext(); ) { + final GBDeviceApp app = iter.next(); + if (app.getUUID().equals(uuid)) { + iter.remove(); + mGBDeviceAppAdapter.notifyDataSetChanged(); + break; + } + } + } + @Override public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.appmanager_health_deactivate: + case R.id.appmanager_app_delete_cache: + File cachedFile = null; + boolean deleteSuccess = true; + try { + cachedFile = new File(FileUtils.getExternalFilesDir().getPath() + "/pbw-cache/" + selectedApp.getUUID() + ".pbw"); + deleteSuccess = cachedFile.delete(); + } catch (IOException e) { + LOG.warn("could not get external dir while trying to access pbw cache."); + } + if (!deleteSuccess) { + LOG.warn("could not delete file from pbw cache: " + cachedFile.toString()); + } + // fall through case R.id.appmanager_app_delete: - GBApplication.deviceService().onAppDelete(selectedApp.getUUID()); + UUID uuid = selectedApp.getUUID(); + GBApplication.deviceService().onAppDelete(uuid); + removeAppFromList(uuid); return true; case R.id.appmanager_app_reinstall: File cachePath; try { cachePath = new File(FileUtils.getExternalFilesDir().getPath() + "/pbw-cache/" + selectedApp.getUUID() + ".pbw"); } catch (IOException e) { - LOG.warn("could not get external dir while reading pbw cache."); + LOG.warn("could not get external dir while trying to access pbw cache."); return true; } GBApplication.deviceService().onInstallApp(Uri.fromFile(cachePath)); diff --git a/app/src/main/res/menu/appmanager_context.xml b/app/src/main/res/menu/appmanager_context.xml index dd5d22c3..873e0c24 100644 --- a/app/src/main/res/menu/appmanager_context.xml +++ b/app/src/main/res/menu/appmanager_context.xml @@ -6,6 +6,9 @@ + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 95f0f188..141484d1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -17,6 +17,7 @@ App Manager Delete + Delete and remove from cache Notification Blacklist @@ -251,5 +252,4 @@ Heart Rate Heart Rate Reconnect automatically - From bef59ae9c08ad55a55ca7b050448d002d624b9de Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Mon, 23 May 2016 21:13:12 +0200 Subject: [PATCH 13/17] Parse new version of Pebble health datalog message with tag "84". This message was previously treated as a further "Sleep" message type, with firmware version 3.12 further types were added that are clearly unrelated to sleep (possibly to high-intensity activities like running etc.), hence the related code is now moved to a separate class. The only decoded records are still sleep-related. Fixes #312 --- .../DatalogSessionHealthOverlayData.java | 99 +++++++++++++++++++ .../pebble/DatalogSessionHealthSleep.java | 95 ++---------------- .../devices/pebble/PebbleProtocol.java | 4 +- 3 files changed, 109 insertions(+), 89 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthOverlayData.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthOverlayData.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthOverlayData.java new file mode 100644 index 00000000..b7d42544 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthOverlayData.java @@ -0,0 +1,99 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.ByteBuffer; +import java.util.UUID; + +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; +import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; +import nodomain.freeyourgadget.gadgetbridge.devices.pebble.HealthSampleProvider; +import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind; +import nodomain.freeyourgadget.gadgetbridge.util.GB; + +class DatalogSessionHealthOverlayData extends DatalogSession { + + private static final Logger LOG = LoggerFactory.getLogger(DatalogSessionHealthOverlayData.class); + + public DatalogSessionHealthOverlayData(byte id, UUID uuid, int tag, byte item_type, short item_size) { + super(id, uuid, tag, item_type, item_size); + taginfo = "(health - overlay data " + tag + " )"; + } + + @Override + public boolean handleMessage(ByteBuffer datalogMessage, int length) { + LOG.info("DATALOG " + taginfo + GB.hexdump(datalogMessage.array(), datalogMessage.position(), length)); + + int initialPosition = datalogMessage.position(); + int beginOfRecordPosition; + short recordVersion; //probably + short recordType; //probably: 1=sleep, 2=deep sleep, 5=??run??ignored for now + + if (0 != (length % itemSize)) + return false;//malformed message? + + int recordCount = length / itemSize; + OverlayRecord[] overlayRecords = new OverlayRecord[recordCount]; + + for (int recordIdx = 0; recordIdx < recordCount; recordIdx++) { + beginOfRecordPosition = initialPosition + recordIdx * itemSize; + datalogMessage.position(beginOfRecordPosition);//we may not consume all the bytes of a record + recordVersion = datalogMessage.getShort(); + if ((recordVersion != 1) && (recordVersion != 3)) + return false;//we don't know how to deal with the data TODO: this is not ideal because we will get the same message again and again since we NACK it + + datalogMessage.getShort();//throwaway, unknown + recordType = datalogMessage.getShort(); + + overlayRecords[recordIdx] = new OverlayRecord(recordType, datalogMessage.getInt(), datalogMessage.getInt(), datalogMessage.getInt()); + } + + return store(overlayRecords);//NACK if we cannot store the data yet, the watch will send the overlay records again. + } + + private boolean store(OverlayRecord[] overlayRecords) { + DBHandler dbHandler = null; + SampleProvider sampleProvider = new HealthSampleProvider(); + try { + dbHandler = GBApplication.acquireDB(); + int latestTimestamp = dbHandler.fetchLatestTimestamp(sampleProvider); + for (OverlayRecord overlayRecord : overlayRecords) { + if (latestTimestamp < (overlayRecord.timestampStart + overlayRecord.durationSeconds)) + return false; + switch (overlayRecord.type) { + case 1: + dbHandler.changeStoredSamplesType(overlayRecord.timestampStart, (overlayRecord.timestampStart + overlayRecord.durationSeconds), sampleProvider.toRawActivityKind(ActivityKind.TYPE_ACTIVITY), sampleProvider.toRawActivityKind(ActivityKind.TYPE_LIGHT_SLEEP), sampleProvider); + break; + case 2: + dbHandler.changeStoredSamplesType(overlayRecord.timestampStart, (overlayRecord.timestampStart + overlayRecord.durationSeconds), sampleProvider.toRawActivityKind(ActivityKind.TYPE_DEEP_SLEEP), sampleProvider); + break; + default: + //TODO: other values refer to unknown activity types. + } + } + } catch (Exception ex) { + LOG.debug(ex.getMessage()); + } finally { + if (dbHandler != null) { + dbHandler.release(); + } + } + return true; + } + + private class OverlayRecord { + int type; //1=sleep, 2=deep sleep + int offsetUTC; //probably + int timestampStart; + int durationSeconds; + + public OverlayRecord(int type, int offsetUTC, int timestampStart, int durationSeconds) { + this.type = type; + this.offsetUTC = offsetUTC; + this.timestampStart = timestampStart; + this.durationSeconds = durationSeconds; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSleep.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSleep.java index 7d06876f..2162f9d5 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSleep.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSleep.java @@ -1,7 +1,5 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble; -import android.widget.Toast; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,71 +25,6 @@ class DatalogSessionHealthSleep extends DatalogSession { @Override public boolean handleMessage(ByteBuffer datalogMessage, int length) { LOG.info("DATALOG " + taginfo + GB.hexdump(datalogMessage.array(), datalogMessage.position(), length)); - switch (this.tag) { - case 83: - return handleMessage83(datalogMessage, length); - case 84: - return handleMessage84(datalogMessage, length); - default: - return false; - } - } - - private boolean handleMessage84(ByteBuffer datalogMessage, int length) { - int initialPosition = datalogMessage.position(); - int beginOfRecordPosition; - short recordVersion; //probably - short recordType; //probably: 1=sleep, 2=deep sleep - - if (0 != (length % itemSize)) - return false;//malformed message? - - int recordCount = length / itemSize; - SleepRecord84[] sleepRecords = new SleepRecord84[recordCount]; - - for (int recordIdx = 0; recordIdx < recordCount; recordIdx++) { - beginOfRecordPosition = initialPosition + recordIdx * itemSize; - datalogMessage.position(beginOfRecordPosition);//we may not consume all the bytes of a record - recordVersion = datalogMessage.getShort(); - if (recordVersion != 1) - return false;//we don't know how to deal with the data TODO: this is not ideal because we will get the same message again and again since we NACK it - - datalogMessage.getShort();//throwaway, unknown - recordType = datalogMessage.getShort(); - - sleepRecords[recordIdx] = new SleepRecord84(recordType, datalogMessage.getInt(), datalogMessage.getInt(), datalogMessage.getInt()); - } - - return store84(sleepRecords);//NACK if we cannot store the data yet, the watch will send the sleep records again. - } - - private boolean store84(SleepRecord84[] sleepRecords) { - DBHandler dbHandler = null; - SampleProvider sampleProvider = new HealthSampleProvider(); - try { - dbHandler = GBApplication.acquireDB(); - int latestTimestamp = dbHandler.fetchLatestTimestamp(sampleProvider); - for (SleepRecord84 sleepRecord : sleepRecords) { - if (latestTimestamp < (sleepRecord.timestampStart + sleepRecord.durationSeconds)) - return false; - if (sleepRecord.type == 2) { - dbHandler.changeStoredSamplesType(sleepRecord.timestampStart, (sleepRecord.timestampStart + sleepRecord.durationSeconds), sampleProvider.toRawActivityKind(ActivityKind.TYPE_DEEP_SLEEP), sampleProvider); - } else { - dbHandler.changeStoredSamplesType(sleepRecord.timestampStart, (sleepRecord.timestampStart + sleepRecord.durationSeconds), sampleProvider.toRawActivityKind(ActivityKind.TYPE_ACTIVITY), sampleProvider.toRawActivityKind(ActivityKind.TYPE_LIGHT_SLEEP), sampleProvider); - } - - } - } catch (Exception ex) { - LOG.debug(ex.getMessage()); - } finally { - if (dbHandler != null) { - dbHandler.release(); - } - } - return true; - } - - private boolean handleMessage83(ByteBuffer datalogMessage, int length) { int initialPosition = datalogMessage.position(); int beginOfRecordPosition; short recordVersion; //probably @@ -100,7 +33,7 @@ class DatalogSessionHealthSleep extends DatalogSession { return false;//malformed message? int recordCount = length / itemSize; - SleepRecord83[] sleepRecords = new SleepRecord83[recordCount]; + SleepRecord[] sleepRecords = new SleepRecord[recordCount]; for (int recordIdx = 0; recordIdx < recordCount; recordIdx++) { beginOfRecordPosition = initialPosition + recordIdx * itemSize; @@ -109,23 +42,22 @@ class DatalogSessionHealthSleep extends DatalogSession { if (recordVersion != 1) return false;//we don't know how to deal with the data TODO: this is not ideal because we will get the same message again and again since we NACK it - sleepRecords[recordIdx] = new SleepRecord83(datalogMessage.getInt(), + sleepRecords[recordIdx] = new SleepRecord(datalogMessage.getInt(), datalogMessage.getInt(), datalogMessage.getInt(), datalogMessage.getInt()); } - return store83(sleepRecords);//NACK if we cannot store the data yet, the watch will send the sleep records again. + return store(sleepRecords);//NACK if we cannot store the data yet, the watch will send the sleep records again. } - private boolean store83(SleepRecord83[] sleepRecords) { + private boolean store(SleepRecord[] sleepRecords) { DBHandler dbHandler = null; SampleProvider sampleProvider = new HealthSampleProvider(); - GB.toast("Deep sleep is supported only from firmware 3.11 onwards.", Toast.LENGTH_LONG, GB.INFO); try { dbHandler = GBApplication.acquireDB(); int latestTimestamp = dbHandler.fetchLatestTimestamp(sampleProvider); - for (SleepRecord83 sleepRecord : sleepRecords) { + for (SleepRecord sleepRecord : sleepRecords) { if (latestTimestamp < sleepRecord.bedTimeEnd) return false; dbHandler.changeStoredSamplesType(sleepRecord.bedTimeStart, sleepRecord.bedTimeEnd, sampleProvider.toRawActivityKind(ActivityKind.TYPE_ACTIVITY), sampleProvider.toRawActivityKind(ActivityKind.TYPE_LIGHT_SLEEP), sampleProvider); @@ -140,13 +72,13 @@ class DatalogSessionHealthSleep extends DatalogSession { return true; } - private class SleepRecord83 { + private class SleepRecord { int offsetUTC; //probably int bedTimeStart; int bedTimeEnd; int deepSleepSeconds; - public SleepRecord83(int offsetUTC, int bedTimeStart, int bedTimeEnd, int deepSleepSeconds) { + public SleepRecord(int offsetUTC, int bedTimeStart, int bedTimeEnd, int deepSleepSeconds) { this.offsetUTC = offsetUTC; this.bedTimeStart = bedTimeStart; this.bedTimeEnd = bedTimeEnd; @@ -154,17 +86,4 @@ class DatalogSessionHealthSleep extends DatalogSession { } } - private class SleepRecord84 { - int type; //1=sleep, 2=deep sleep - int offsetUTC; //probably - int timestampStart; - int durationSeconds; - - public SleepRecord84(int type, int offsetUTC, int timestampStart, int durationSeconds) { - this.type = type; - this.offsetUTC = offsetUTC; - this.timestampStart = timestampStart; - this.durationSeconds = durationSeconds; - } - } } \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 5d261e6a..56863447 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -1881,8 +1881,10 @@ public class PebbleProtocol extends GBDeviceProtocol { if (!mDatalogSessions.containsKey(id)) { if (uuid.equals(UUID_ZERO) && log_tag == 81) { mDatalogSessions.put(id, new DatalogSessionHealthSteps(id, uuid, log_tag, item_type, item_size)); - } else if (uuid.equals(UUID_ZERO) && (log_tag == 83 || log_tag == 84)) { + } else if (uuid.equals(UUID_ZERO) && log_tag == 83) { mDatalogSessions.put(id, new DatalogSessionHealthSleep(id, uuid, log_tag, item_type, item_size)); + } else if (uuid.equals(UUID_ZERO) && log_tag == 84) { + mDatalogSessions.put(id, new DatalogSessionHealthOverlayData(id, uuid, log_tag, item_type, item_size)); } else { mDatalogSessions.put(id, new DatalogSession(id, uuid, log_tag, item_type, item_size)); } From f6979065729acc8aefe97f0792df1d2358cf3243 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Mon, 23 May 2016 22:03:21 +0200 Subject: [PATCH 14/17] update Japanese and German tranlation from transifex (thanks!) --- app/src/main/res/values-de/strings.xml | 5 +++++ app/src/main/res/values-ja/strings.xml | 3 +++ 2 files changed, 8 insertions(+) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 121df48e..5baa517c 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -14,6 +14,7 @@ App Manager Löschen + Löschen und aus dem Zwischenspeicher entfernen Sperre für Benachrichtigungen @@ -44,6 +45,8 @@ Unterstützung für Anwendungen, die Benachrichtigungen per Intent an die Pebble schicken. Kann für Conversations verwendet werden. Andere Benachrichtigungen … auch wenn der Bildschirm an ist + Bitte nicht stören + Stoppe unerwünschte Nachrichten, wenn im \"Nicht Stören\"-Modus immer wenn der Bildschirm aus ist niemals @@ -202,6 +205,7 @@ Aktivitätsdaten auf dem Gerät lassen Inkompatible Firmware Diese Firmware ist nicht mit dem Gerät kompatibel + Wecker für zukünftige Ereignisse vormerken Verwende den Herzfrequenzsensor um die Schlaferkennung zu verbessern warte auf eingehende Verbindung Erneut installieren @@ -214,6 +218,7 @@ deaktivieren Authentifiziere Authentifizierung erforderlich + Konfigurieren Zzz Widget hinzufügen Gewünschte Schlafdauer in Stunden diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 864ce541..f4013879 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -14,6 +14,7 @@ アプリ管理画面 削除 + キャッシュから削除 ステータス通知ブラックリスト @@ -44,6 +45,8 @@ インテント経由でPebbleに通知を送信するアプリケーションをサポートします。Conversationsに使用することができます。 一般ステータス通知対応 … スクリーンがオンのときにも + サイレント + サイレントモードに基づいて、送信される不要な通知を停止します。 いつも スクリーンがオフのとき なし From 24c51deaf9776131f5946ab5e57cc723311be1b4 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Mon, 23 May 2016 23:15:07 +0200 Subject: [PATCH 15/17] Pebble: also delete other files from cache when deleting .pbw --- .../activities/AppManagerActivity.java | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java index de5147e9..9c0fd166 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java @@ -212,16 +212,25 @@ public class AppManagerActivity extends GBActivity { switch (item.getItemId()) { case R.id.appmanager_health_deactivate: case R.id.appmanager_app_delete_cache: - File cachedFile = null; - boolean deleteSuccess = true; + + + String baseName; try { - cachedFile = new File(FileUtils.getExternalFilesDir().getPath() + "/pbw-cache/" + selectedApp.getUUID() + ".pbw"); - deleteSuccess = cachedFile.delete(); + baseName = FileUtils.getExternalFilesDir().getPath() + "/pbw-cache/" + selectedApp.getUUID(); } catch (IOException e) { LOG.warn("could not get external dir while trying to access pbw cache."); + return true; } - if (!deleteSuccess) { - LOG.warn("could not delete file from pbw cache: " + cachedFile.toString()); + + String[] suffixToDelete = new String[]{".pbw", ".json", "_config.js"}; + + for (String suffix : suffixToDelete) { + File fileToDelete = new File(baseName + suffix); + if (!fileToDelete.delete()) { + LOG.warn("could not delete file from pbw cache: " + fileToDelete.toString()); + } else { + LOG.info("deleted file: " + fileToDelete.toString()); + } } // fall through case R.id.appmanager_app_delete: From 884c4262cf1a3ce62df3b963bd9560b9284c1237 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Mon, 23 May 2016 23:37:08 +0200 Subject: [PATCH 16/17] update changelog, bump version (also change one German string and remove two newlines :P) --- CHANGELOG.md | 8 ++++++++ app/build.gradle | 4 ++-- .../gadgetbridge/activities/AppManagerActivity.java | 2 -- app/src/main/res/values-de/strings.xml | 2 +- app/src/main/res/xml/changelog_master.xml | 8 ++++++++ 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf801f26..91ce3b0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,12 @@ ###Changelog +####Version 0.9.8 +* Pebble: fix more reconnnect issues +* Pebble: fix deep sleep not being detected with Firmware 3.12 when using Pebble Health +* Pebble: option in AppManager to delete files from cache +* Pebble: enable pbw cache and watchface configuration for Firmware 2.x +* Pebble: allow enabling of Pebble Health without "untested features" being enabled +* Honour "Do Not Disturb" for phone calls and SMS + ####Version 0.9.7 * Pebble: hopefully fix some reconnect issues * Mi Band: fix live activity monitoring running forever if back button pressed diff --git a/app/build.gradle b/app/build.gradle index fffe7f3c..c30ca034 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,8 +16,8 @@ android { targetSdkVersion 23 // note: always bump BOTH versionCode and versionName! - versionName "0.9.7" - versionCode 51 + versionName "0.9.8" + versionCode 52 } buildTypes { release { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java index 9c0fd166..5f7e5af8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java @@ -212,8 +212,6 @@ public class AppManagerActivity extends GBActivity { switch (item.getItemId()) { case R.id.appmanager_health_deactivate: case R.id.appmanager_app_delete_cache: - - String baseName; try { baseName = FileUtils.getExternalFilesDir().getPath() + "/pbw-cache/" + selectedApp.getUUID(); diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 5baa517c..1588000a 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -207,7 +207,7 @@ Diese Firmware ist nicht mit dem Gerät kompatibel Wecker für zukünftige Ereignisse vormerken Verwende den Herzfrequenzsensor um die Schlaferkennung zu verbessern - warte auf eingehende Verbindung + warte auf Verbindung Erneut installieren Über Dich Geburtsjahr diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml index 425e5c4a..abe77eba 100644 --- a/app/src/main/res/xml/changelog_master.xml +++ b/app/src/main/res/xml/changelog_master.xml @@ -1,5 +1,13 @@ + + Pebble: fix more reconnnect issues + Pebble: fix deep sleep not being detected with Firmware 3.12 when using Pebble Health + Pebble: option in AppManager to delete files from cache + Pebble: enable pbw cache and watchface configuration for Firmware 2.x + Pebble: allow enabling of Pebble Health without "untested features" being enabled + Honour "Do Not Disturb" for phone calls and SMS + Pebble: hopefully fix some reconnect issues Mi Band: fix live activity monitoring running forever if back button pressed From 30c37d3172ccc60e0de6212e1ba24728f5c62926 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Mon, 23 May 2016 23:46:54 +0200 Subject: [PATCH 17/17] Pebble: only remove apps from app list when they got deleted from cache also --- .../gadgetbridge/activities/AppManagerActivity.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java index 5f7e5af8..f66bd731 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java @@ -230,11 +230,10 @@ public class AppManagerActivity extends GBActivity { LOG.info("deleted file: " + fileToDelete.toString()); } } + removeAppFromList(selectedApp.getUUID()); // fall through case R.id.appmanager_app_delete: - UUID uuid = selectedApp.getUUID(); - GBApplication.deviceService().onAppDelete(uuid); - removeAppFromList(uuid); + GBApplication.deviceService().onAppDelete(selectedApp.getUUID()); return true; case R.id.appmanager_app_reinstall: File cachePath;