From 017f650b3f968406538bfdde0839236f0fb08595 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Mon, 16 May 2016 17:30:11 +0200 Subject: [PATCH 01/58] Pebble: send sunrine and sunset pins to timeline when setting time in debug menu This is just a test and it will leak your timeline data, since we never delete it. Also this adds some rough infrastructure for calendar events. --- app/build.gradle | 1 + .../activities/DebugActivity.java | 36 +++++++++++++++++++ .../gadgetbridge/devices/EventHandler.java | 3 ++ .../gadgetbridge/impl/GBDeviceService.java | 13 +++++++ .../gadgetbridge/model/CalendarEventSpec.java | 14 ++++++++ .../gadgetbridge/model/DeviceService.java | 7 ++++ .../service/DeviceCommunicationService.java | 19 ++++++++++ .../service/ServiceDeviceSupport.java | 9 +++++ .../service/devices/miband/MiBandSupport.java | 6 ++++ .../devices/pebble/PebbleProtocol.java | 23 ++++++++++-- .../service/devices/pebble/PebbleSupport.java | 8 +++++ .../serial/AbstractSerialDeviceSupport.java | 6 ++++ .../service/serial/GBDeviceProtocol.java | 5 +++ app/src/main/res/values/strings.xml | 6 +++- app/src/main/res/xml/preferences.xml | 8 +++++ .../service/TestDeviceSupport.java | 6 ++++ 16 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/CalendarEventSpec.java diff --git a/app/build.gradle b/app/build.gradle index fffe7f3c..a238ccab 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -54,6 +54,7 @@ dependencies { compile 'com.github.PhilJay:MPAndroidChart:v2.2.4' compile 'com.github.pfichtner:durationformatter:0.1.1' compile 'de.cketti.library.changelog:ckchangelog:1.2.2' + compile 'net.e175.klaus:solarpositioning:0.0.9' } check.dependsOn 'findbugs', 'pmd', 'lint' diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java index d7d81f69..42f1c815 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java @@ -20,15 +20,20 @@ import android.widget.Button; import android.widget.EditText; import android.widget.Toast; +import net.e175.klaus.solarpositioning.DeltaT; +import net.e175.klaus.solarpositioning.SPA; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; +import java.util.GregorianCalendar; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; +import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec; import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; import nodomain.freeyourgadget.gadgetbridge.model.DeviceService; import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; @@ -36,6 +41,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; import nodomain.freeyourgadget.gadgetbridge.util.GB; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class DebugActivity extends GBActivity { @@ -224,6 +230,36 @@ public class DebugActivity extends GBActivity { @Override public void onClick(View v) { GBApplication.deviceService().onSetTime(); + + //FIXME: dont do it here, make another button + + Prefs prefs = GBApplication.getPrefs(); + + float latitude = prefs.getFloat("location_latitude", 0); + float longitude = prefs.getFloat("location_longitude", 0); + final GregorianCalendar dateTime = new GregorianCalendar(); + GregorianCalendar[] sunriseTransitSet = SPA.calculateSunriseTransitSet(dateTime, latitude, longitude, DeltaT.estimate(dateTime)); + + if (sunriseTransitSet[0] != null) { + CalendarEventSpec calendarEventSpec = new CalendarEventSpec(); + calendarEventSpec.id = -1; + calendarEventSpec.type = CalendarEventSpec.TYPE_SUNRISE; + calendarEventSpec.timestamp = (int) (sunriseTransitSet[0].getTimeInMillis() / 1000); + calendarEventSpec.durationInSeconds = 0; + calendarEventSpec.title = "Sunrise"; + calendarEventSpec.description = null; + GBApplication.deviceService().onAddCalendarEvent(calendarEventSpec); + } + if (sunriseTransitSet[2] != null) { + CalendarEventSpec calendarEventSpec = new CalendarEventSpec(); + calendarEventSpec.id = -1; + calendarEventSpec.type = CalendarEventSpec.TYPE_SUNSET; + calendarEventSpec.timestamp = (int) (sunriseTransitSet[2].getTimeInMillis() / 1000); + calendarEventSpec.durationInSeconds = 0; + calendarEventSpec.title = "Sunset"; + calendarEventSpec.description = null; + GBApplication.deviceService().onAddCalendarEvent(calendarEventSpec); + } } }); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java index a6dd21bf..cc8486c9 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; +import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec; import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; @@ -51,4 +52,6 @@ public interface EventHandler { void onScreenshotReq(); void onEnableHeartRateSleepSupport(boolean enable); + + void onAddCalendarEvent(CalendarEventSpec calendarEventSpec); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java index 61af3fcb..e2f0a220 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java @@ -10,6 +10,7 @@ import java.util.ArrayList; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; +import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec; import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; import nodomain.freeyourgadget.gadgetbridge.model.DeviceService; import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; @@ -223,4 +224,16 @@ public class GBDeviceService implements DeviceService { .putExtra(EXTRA_BOOLEAN_ENABLE, enable); invokeService(intent); } + + @Override + public void onAddCalendarEvent(CalendarEventSpec calendarEventSpec) { + Intent intent = createIntent().setAction(ACTION_ADD_CALENDAREVENT) + .putExtra(EXTRA_CALENDAREVENT_ID, calendarEventSpec.id) + .putExtra(EXTRA_CALENDAREVENT_TYPE, calendarEventSpec.type) + .putExtra(EXTRA_CALENDAREVENT_TIMESTAMP, calendarEventSpec.timestamp) + .putExtra(EXTRA_CALENDAREVENT_DURATION, calendarEventSpec.durationInSeconds) + .putExtra(EXTRA_CALENDAREVENT_TITLE, calendarEventSpec.title) + .putExtra(EXTRA_CALENDAREVENT_DESCRIPTION, calendarEventSpec.description); + invokeService(intent); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/CalendarEventSpec.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/CalendarEventSpec.java new file mode 100644 index 00000000..7f52b2a2 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/CalendarEventSpec.java @@ -0,0 +1,14 @@ +package nodomain.freeyourgadget.gadgetbridge.model; + +public class CalendarEventSpec { + public static final int TYPE_UNKNOWN = 0; + public static final int TYPE_SUNRISE = 1; + public static final int TYPE_SUNSET = 2; + + public int type; + public long id; + public int timestamp; + public int durationInSeconds; + public String title; + public String description; +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java index 2cf979cd..927a258b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java @@ -36,6 +36,7 @@ public interface DeviceService extends EventHandler { String ACTION_ENABLE_REALTIME_HEARTRATE_MEASUREMENT = PREFIX + ".action.realtime_hr_measurement"; String ACTION_ENABLE_HEARTRATE_SLEEP_SUPPORT = PREFIX + ".action.enable_heartrate_sleep_support"; String ACTION_HEARTRATE_MEASUREMENT = PREFIX + ".action.hr_measurement"; + String ACTION_ADD_CALENDAREVENT = PREFIX + ".action.add_calendarevent"; String EXTRA_DEVICE_ADDRESS = "device_address"; String EXTRA_NOTIFICATION_BODY = "notification_body"; String EXTRA_NOTIFICATION_FLAGS = "notification_flags"; @@ -65,6 +66,12 @@ public interface DeviceService extends EventHandler { String EXTRA_REALTIME_STEPS = "realtime_steps"; String EXTRA_TIMESTAMP = "timestamp"; String EXTRA_HEART_RATE_VALUE = "hr_value"; + String EXTRA_CALENDAREVENT_ID = "calendarevent_id"; + String EXTRA_CALENDAREVENT_TYPE = "calendarevent_type"; + String EXTRA_CALENDAREVENT_TIMESTAMP = "calendarevent_timestamp"; + String EXTRA_CALENDAREVENT_DURATION = "calendarevent_duration"; + String EXTRA_CALENDAREVENT_TITLE = "calendarevent_title"; + String EXTRA_CALENDAREVENT_DESCRIPTION = "calendarevent_description"; void start(); 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..57f48fcd 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -32,6 +32,7 @@ import nodomain.freeyourgadget.gadgetbridge.externalevents.SMSReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.TimeChangeReceiver; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; +import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec; import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; @@ -41,6 +42,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.GB; import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_ADD_CALENDAREVENT; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_APP_CONFIGURE; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_CALLSTATE; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_CONNECT; @@ -68,6 +70,12 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_APP import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_APP_START; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_APP_UUID; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_BOOLEAN_ENABLE; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_CALENDAREVENT_DESCRIPTION; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_CALENDAREVENT_DURATION; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_CALENDAREVENT_ID; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_CALENDAREVENT_TIMESTAMP; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_CALENDAREVENT_TITLE; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_CALENDAREVENT_TYPE; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_CALL_COMMAND; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_CALL_PHONENUMBER; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_DEVICE_ADDRESS; @@ -265,6 +273,17 @@ public class DeviceCommunicationService extends Service implements SharedPrefere mDeviceSupport.onNotification(notificationSpec); break; } + case ACTION_ADD_CALENDAREVENT: { + CalendarEventSpec calendarEventSpec = new CalendarEventSpec(); + calendarEventSpec.id = intent.getLongExtra(EXTRA_CALENDAREVENT_ID, -1); + calendarEventSpec.type = intent.getIntExtra(EXTRA_CALENDAREVENT_TYPE, -1); + calendarEventSpec.timestamp = intent.getIntExtra(EXTRA_CALENDAREVENT_TIMESTAMP, -1); + calendarEventSpec.durationInSeconds = intent.getIntExtra(EXTRA_CALENDAREVENT_DURATION, -1); + calendarEventSpec.title = intent.getStringExtra(EXTRA_CALENDAREVENT_TITLE); + calendarEventSpec.description = intent.getStringExtra(EXTRA_CALENDAREVENT_DESCRIPTION); + mDeviceSupport.onAddCalendarEvent(calendarEventSpec); + break; + } case ACTION_REBOOT: { mDeviceSupport.onReboot(); break; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java index 8047aad6..166c65cb 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java @@ -13,6 +13,7 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; +import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec; import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; @@ -268,4 +269,12 @@ public class ServiceDeviceSupport implements DeviceSupport { } delegate.onEnableRealtimeHeartRateMeasurement(enable); } + + @Override + public void onAddCalendarEvent(CalendarEventSpec calendarEventSpec) { + if (checkBusy("add calendar event")) { + return; + } + delegate.onAddCalendarEvent(calendarEventSpec); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java index 2d97818d..393ad81a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java @@ -32,6 +32,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.miband.VibrationProfile; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice.State; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; +import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec; import nodomain.freeyourgadget.gadgetbridge.model.CalendarEvents; import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; import nodomain.freeyourgadget.gadgetbridge.model.DeviceService; @@ -382,6 +383,11 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { } } + @Override + public void onAddCalendarEvent(CalendarEventSpec calendarEventSpec) { + // not supported + } + /** * Part of device initialization process. Do not call manually. * 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..83433496 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 @@ -33,6 +33,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleColor; import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleIconID; import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp; import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser; +import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec; import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; @@ -464,6 +465,24 @@ public class PebbleProtocol extends GBDeviceProtocol { } } + @Override + public byte[] encodeAddCalendarEvent(CalendarEventSpec calendarEventSpec) { + long id = calendarEventSpec.id != -1 ? calendarEventSpec.id : mRandom.nextLong(); + int iconId; + switch (calendarEventSpec.type) { + case CalendarEventSpec.TYPE_SUNRISE: + iconId = PebbleIconID.SUNRISE; + break; + case CalendarEventSpec.TYPE_SUNSET: + iconId = PebbleIconID.SUNSET; + break; + default: + iconId = PebbleIconID.TIMELINE_CALENDAR; + } + + return encodeTimelinePin(id, calendarEventSpec.timestamp, (short)calendarEventSpec.durationInSeconds, iconId, calendarEventSpec.title, calendarEventSpec.description); + } + @Override public byte[] encodeSetTime() { long ts = System.currentTimeMillis(); @@ -742,11 +761,11 @@ public class PebbleProtocol extends GBDeviceProtocol { return buf.array(); } - private byte[] encodeTimelinePin(int id, int timestamp, short duration, int icon_id, String title, String subtitle) { + private byte[] encodeTimelinePin(long id, int timestamp, short duration, int icon_id, String title, String subtitle) { final short TIMELINE_PIN_LENGTH = 46; icon_id |= 0x80000000; - UUID uuid = new UUID(mRandom.nextLong(), ((long) mRandom.nextInt() << 32) | id); + UUID uuid = new UUID(mRandom.nextLong(), id); byte attributes_count = 2; byte actions_count = 0; 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..7834161c 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 @@ -12,6 +12,7 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; +import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec; import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; @@ -118,4 +119,11 @@ public class PebbleSupport extends AbstractSerialDeviceSupport { public void onSetAlarms(ArrayList alarms) { //nothing to do ATM } + + @Override + public void onAddCalendarEvent(CalendarEventSpec calendarEventSpec) { + if (reconnect()) { + super.onAddCalendarEvent(calendarEventSpec); + } + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java index 5dfa8b2a..dee77821 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java @@ -8,6 +8,7 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; import nodomain.freeyourgadget.gadgetbridge.devices.EventHandler; +import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec; import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; @@ -187,4 +188,9 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport byte[] bytes = gbDeviceProtocol.encodeEnableRealtimeHeartRateMeasurement(enable); sendToDevice(bytes); } + @Override + public void onAddCalendarEvent(CalendarEventSpec calendarEventSpec) { + byte[] bytes = gbDeviceProtocol.encodeAddCalendarEvent(calendarEventSpec); + sendToDevice(bytes); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java index bdf1b101..1005f980 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java @@ -3,6 +3,7 @@ package nodomain.freeyourgadget.gadgetbridge.service.serial; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; +import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; public abstract class GBDeviceProtocol { @@ -65,6 +66,10 @@ public abstract class GBDeviceProtocol { public byte[] encodeEnableRealtimeHeartRateMeasurement(boolean enable) { return null; } + public byte[] encodeAddCalendarEvent(CalendarEventSpec calendarEventSpec) { + return null; + } + public GBDeviceEvent[] decodeResponse(byte[] responseData) { return null; } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 133216e5..81974ec2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -34,11 +34,16 @@ General Settings Connect to device when Bluetooth turned on + Reconnect automatically Preferred Audioplayer Default + Date and Time Sync time Sync time to device when connecting and when time or timezone changes on Android + Latitude + Longitude + Theme Light Dark @@ -248,6 +253,5 @@ Firmware not sent Heart Rate Heart Rate - Reconnect automatically diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 4def8d01..cfac0fb2 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -32,6 +32,14 @@ android:key="datetime_synconconnect" android:summary="@string/pref_summary_datetime_syctimeonconnect" android:title="@string/pref_title_datetime_syctimeonconnect" /> + + Date: Mon, 16 May 2016 23:37:40 +0200 Subject: [PATCH 02/58] Pebble: send sunrise/sunset to watch for today and tomorrow, also delete previous timeline pins --- .../activities/DebugActivity.java | 55 ++++++++++++------- .../gadgetbridge/devices/EventHandler.java | 2 + .../gadgetbridge/impl/GBDeviceService.java | 8 +++ .../gadgetbridge/model/DeviceService.java | 1 + .../service/DeviceCommunicationService.java | 7 +++ .../service/ServiceDeviceSupport.java | 8 +++ .../service/devices/miband/MiBandSupport.java | 5 ++ .../devices/pebble/PebbleProtocol.java | 11 ++-- .../service/devices/pebble/PebbleSupport.java | 7 +++ .../serial/AbstractSerialDeviceSupport.java | 7 +++ .../service/serial/GBDeviceProtocol.java | 4 ++ .../service/TestDeviceSupport.java | 5 ++ 12 files changed, 97 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java index 42f1c815..6a8e539d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java @@ -231,33 +231,50 @@ public class DebugActivity extends GBActivity { public void onClick(View v) { GBApplication.deviceService().onSetTime(); - //FIXME: dont do it here, make another button + //FIXME: dont do it here, and make another button + GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_SUNRISE, 1); + GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_SUNRISE, 3); + GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_SUNSET, 2); + GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_SUNSET, 4); Prefs prefs = GBApplication.getPrefs(); float latitude = prefs.getFloat("location_latitude", 0); float longitude = prefs.getFloat("location_longitude", 0); - final GregorianCalendar dateTime = new GregorianCalendar(); - GregorianCalendar[] sunriseTransitSet = SPA.calculateSunriseTransitSet(dateTime, latitude, longitude, DeltaT.estimate(dateTime)); + final GregorianCalendar dateTimeToday = new GregorianCalendar(); + final GregorianCalendar dateTimeTomorrow = new GregorianCalendar(); + dateTimeTomorrow.add(GregorianCalendar.DAY_OF_MONTH, 1); - if (sunriseTransitSet[0] != null) { - CalendarEventSpec calendarEventSpec = new CalendarEventSpec(); - calendarEventSpec.id = -1; - calendarEventSpec.type = CalendarEventSpec.TYPE_SUNRISE; - calendarEventSpec.timestamp = (int) (sunriseTransitSet[0].getTimeInMillis() / 1000); - calendarEventSpec.durationInSeconds = 0; - calendarEventSpec.title = "Sunrise"; - calendarEventSpec.description = null; + GregorianCalendar[] sunriseTransitSetToday = SPA.calculateSunriseTransitSet(dateTimeToday, latitude, longitude, DeltaT.estimate(dateTimeToday)); + GregorianCalendar[] sunriseTransitSetTomorrow = SPA.calculateSunriseTransitSet(dateTimeTomorrow, latitude, longitude, DeltaT.estimate(dateTimeToday)); + + CalendarEventSpec calendarEventSpec = new CalendarEventSpec(); + calendarEventSpec.durationInSeconds = 0; + calendarEventSpec.description = null; + + calendarEventSpec.type = CalendarEventSpec.TYPE_SUNRISE; + calendarEventSpec.title = "Sunrise"; + if (sunriseTransitSetToday[0] != null) { + calendarEventSpec.id = 1; + calendarEventSpec.timestamp = (int) (sunriseTransitSetToday[0].getTimeInMillis() / 1000); GBApplication.deviceService().onAddCalendarEvent(calendarEventSpec); } - if (sunriseTransitSet[2] != null) { - CalendarEventSpec calendarEventSpec = new CalendarEventSpec(); - calendarEventSpec.id = -1; - calendarEventSpec.type = CalendarEventSpec.TYPE_SUNSET; - calendarEventSpec.timestamp = (int) (sunriseTransitSet[2].getTimeInMillis() / 1000); - calendarEventSpec.durationInSeconds = 0; - calendarEventSpec.title = "Sunset"; - calendarEventSpec.description = null; + if (sunriseTransitSetTomorrow[0] != null) { + calendarEventSpec.id = 2; + calendarEventSpec.timestamp = (int) (sunriseTransitSetTomorrow[0].getTimeInMillis() / 1000); + GBApplication.deviceService().onAddCalendarEvent(calendarEventSpec); + } + + calendarEventSpec.type = CalendarEventSpec.TYPE_SUNSET; + calendarEventSpec.title = "Sunset"; + if (sunriseTransitSetToday[2] != null) { + calendarEventSpec.id = 1; + calendarEventSpec.timestamp = (int) (sunriseTransitSetToday[2].getTimeInMillis() / 1000); + GBApplication.deviceService().onAddCalendarEvent(calendarEventSpec); + } + if (sunriseTransitSetTomorrow[2] != null) { + calendarEventSpec.id = 2; + calendarEventSpec.timestamp = (int) (sunriseTransitSetTomorrow[2].getTimeInMillis() / 1000); GBApplication.deviceService().onAddCalendarEvent(calendarEventSpec); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java index cc8486c9..d4f44101 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java @@ -54,4 +54,6 @@ public interface EventHandler { void onEnableHeartRateSleepSupport(boolean enable); void onAddCalendarEvent(CalendarEventSpec calendarEventSpec); + + void onDeleteCalendarEvent(int type, long id); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java index e2f0a220..6c51e6b2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java @@ -236,4 +236,12 @@ public class GBDeviceService implements DeviceService { .putExtra(EXTRA_CALENDAREVENT_DESCRIPTION, calendarEventSpec.description); invokeService(intent); } + + @Override + public void onDeleteCalendarEvent(int type, long id) { + Intent intent = createIntent().setAction(ACTION_DELETE_CALENDAREVENT) + .putExtra(EXTRA_CALENDAREVENT_TYPE, type) + .putExtra(EXTRA_CALENDAREVENT_ID, id); + invokeService(intent); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java index 927a258b..aaf02798 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java @@ -37,6 +37,7 @@ public interface DeviceService extends EventHandler { String ACTION_ENABLE_HEARTRATE_SLEEP_SUPPORT = PREFIX + ".action.enable_heartrate_sleep_support"; String ACTION_HEARTRATE_MEASUREMENT = PREFIX + ".action.hr_measurement"; String ACTION_ADD_CALENDAREVENT = PREFIX + ".action.add_calendarevent"; + String ACTION_DELETE_CALENDAREVENT = PREFIX + ".action.delete_calendarevent"; String EXTRA_DEVICE_ADDRESS = "device_address"; String EXTRA_NOTIFICATION_BODY = "notification_body"; String EXTRA_NOTIFICATION_FLAGS = "notification_flags"; 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 57f48fcd..12e8d1c0 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -47,6 +47,7 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_AP import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_CALLSTATE; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_CONNECT; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_DELETEAPP; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_DELETE_CALENDAREVENT; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_DISCONNECT; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_ENABLE_HEARTRATE_SLEEP_SUPPORT; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_ENABLE_REALTIME_HEARTRATE_MEASUREMENT; @@ -284,6 +285,12 @@ public class DeviceCommunicationService extends Service implements SharedPrefere mDeviceSupport.onAddCalendarEvent(calendarEventSpec); break; } + case ACTION_DELETE_CALENDAREVENT: { + long id = intent.getLongExtra(EXTRA_CALENDAREVENT_ID, -1); + int type = intent.getIntExtra(EXTRA_CALENDAREVENT_TYPE, -1); + mDeviceSupport.onDeleteCalendarEvent(type, id); + break; + } case ACTION_REBOOT: { mDeviceSupport.onReboot(); break; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java index 166c65cb..6753f27e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java @@ -277,4 +277,12 @@ public class ServiceDeviceSupport implements DeviceSupport { } delegate.onAddCalendarEvent(calendarEventSpec); } + + @Override + public void onDeleteCalendarEvent(int type, long id) { + if (checkBusy("delete calendar event")) { + return; + } + delegate.onDeleteCalendarEvent(type, id); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java index 393ad81a..ea2d4d7c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java @@ -388,6 +388,11 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { // not supported } + @Override + public void onDeleteCalendarEvent(int type, long id) { + // not supported + } + /** * Part of device initialization process. Do not call manually. * 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 83433496..c81b3f58 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 @@ -452,7 +452,6 @@ public class PebbleProtocol extends GBDeviceProtocol { if (isFw3x) { // 3.x notification - //return encodeTimelinePin(id, (int) ((ts + 600) & 0xffffffffL), (short) 90, PebbleIconID.TIMELINE_CALENDAR, title); // really, this is just for testing return encodeBlobdbNotification(id, (int) (ts & 0xffffffffL), title, subtitle, notificationSpec.body, notificationSpec.sourceName, hasHandle, notificationSpec.type, notificationSpec.cannedReplies); } else if (mForceProtocol || notificationSpec.type != NotificationType.EMAIL) { // 2.x notification @@ -480,7 +479,12 @@ public class PebbleProtocol extends GBDeviceProtocol { iconId = PebbleIconID.TIMELINE_CALENDAR; } - return encodeTimelinePin(id, calendarEventSpec.timestamp, (short)calendarEventSpec.durationInSeconds, iconId, calendarEventSpec.title, calendarEventSpec.description); + return encodeTimelinePin(new UUID(calendarEventSpec.type, id), calendarEventSpec.timestamp, (short) calendarEventSpec.durationInSeconds, iconId, calendarEventSpec.title, calendarEventSpec.description); + } + + @Override + public byte[] encodeDeleteCalendarEvent(int type, long id) { + return encodeBlobdb(new UUID(type, id), BLOBDB_DELETE, BLOBDB_PIN, null); } @Override @@ -761,11 +765,10 @@ public class PebbleProtocol extends GBDeviceProtocol { return buf.array(); } - private byte[] encodeTimelinePin(long id, int timestamp, short duration, int icon_id, String title, String subtitle) { + private byte[] encodeTimelinePin(UUID uuid, int timestamp, short duration, int icon_id, String title, String subtitle) { final short TIMELINE_PIN_LENGTH = 46; icon_id |= 0x80000000; - UUID uuid = new UUID(mRandom.nextLong(), id); byte attributes_count = 2; byte actions_count = 0; 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 7834161c..f6f5f78a 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 @@ -126,4 +126,11 @@ public class PebbleSupport extends AbstractSerialDeviceSupport { super.onAddCalendarEvent(calendarEventSpec); } } + + @Override + public void onDeleteCalendarEvent(int type, long id) { + if (reconnect()) { + super.onDeleteCalendarEvent(type, id); + } + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java index dee77821..18be585d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java @@ -188,9 +188,16 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport byte[] bytes = gbDeviceProtocol.encodeEnableRealtimeHeartRateMeasurement(enable); sendToDevice(bytes); } + @Override public void onAddCalendarEvent(CalendarEventSpec calendarEventSpec) { byte[] bytes = gbDeviceProtocol.encodeAddCalendarEvent(calendarEventSpec); sendToDevice(bytes); } + + @Override + public void onDeleteCalendarEvent(int type, long id) { + byte[] bytes = gbDeviceProtocol.encodeDeleteCalendarEvent(type, id); + sendToDevice(bytes); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java index 1005f980..79337b5d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java @@ -70,6 +70,10 @@ public abstract class GBDeviceProtocol { return null; } + public byte[] encodeDeleteCalendarEvent(int type, long id) { + return null; + } + public GBDeviceEvent[] decodeResponse(byte[] responseData) { return null; } diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java index 0c8056da..45eea6eb 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java @@ -136,6 +136,11 @@ public class TestDeviceSupport extends AbstractDeviceSupport { } + @Override + public void onDeleteCalendarEvent(int type, long id) { + + } + @Override public void onEnableRealtimeHeartRateMeasurement(boolean enable) { From 907ad8f27aff37ef798e7bf18540da5176c05b25 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Mon, 16 May 2016 23:48:18 +0200 Subject: [PATCH 03/58] correction regarding deletion of old pins --- .../freeyourgadget/gadgetbridge/activities/DebugActivity.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java index 6a8e539d..f52c440e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java @@ -233,9 +233,9 @@ public class DebugActivity extends GBActivity { //FIXME: dont do it here, and make another button GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_SUNRISE, 1); - GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_SUNRISE, 3); + GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_SUNRISE, 2); + GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_SUNSET, 1); GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_SUNSET, 2); - GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_SUNSET, 4); Prefs prefs = GBApplication.getPrefs(); From d5cca847804841d8eb0f2a47edf6565587ea49b5 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Fri, 20 May 2016 22:04:30 +0200 Subject: [PATCH 04/58] 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 05/58] 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 06/58] 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 07/58] 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 08/58] 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 09/58] 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 437de7f660abce9bf37015551f6e4a543b030c9f Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 22 May 2016 23:38:51 +0200 Subject: [PATCH 10/58] fix duplicate entry in strings.xml --- app/src/main/res/values/strings.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7d0a9514..658e251d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -256,5 +256,4 @@ Firmware not sent 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 11/58] 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 12/58] 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 13/58] 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 14/58] 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 15/58] 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; From c9c9b420dc6777c5c1faf70bbba7e36faabf2a92 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Tue, 24 May 2016 11:19:57 +0200 Subject: [PATCH 16/58] Pebble: Send sunrise and sunset events to the pebble every day using AlarmManager --- .../activities/DebugActivity.java | 47 ---------- .../externalevents/AlarmReceiver.java | 88 +++++++++++++++++++ .../service/DeviceCommunicationService.java | 10 +++ 3 files changed, 98 insertions(+), 47 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmReceiver.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java index f52c440e..c832148f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java @@ -230,53 +230,6 @@ public class DebugActivity extends GBActivity { @Override public void onClick(View v) { GBApplication.deviceService().onSetTime(); - - //FIXME: dont do it here, and make another button - GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_SUNRISE, 1); - GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_SUNRISE, 2); - GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_SUNSET, 1); - GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_SUNSET, 2); - - Prefs prefs = GBApplication.getPrefs(); - - float latitude = prefs.getFloat("location_latitude", 0); - float longitude = prefs.getFloat("location_longitude", 0); - final GregorianCalendar dateTimeToday = new GregorianCalendar(); - final GregorianCalendar dateTimeTomorrow = new GregorianCalendar(); - dateTimeTomorrow.add(GregorianCalendar.DAY_OF_MONTH, 1); - - GregorianCalendar[] sunriseTransitSetToday = SPA.calculateSunriseTransitSet(dateTimeToday, latitude, longitude, DeltaT.estimate(dateTimeToday)); - GregorianCalendar[] sunriseTransitSetTomorrow = SPA.calculateSunriseTransitSet(dateTimeTomorrow, latitude, longitude, DeltaT.estimate(dateTimeToday)); - - CalendarEventSpec calendarEventSpec = new CalendarEventSpec(); - calendarEventSpec.durationInSeconds = 0; - calendarEventSpec.description = null; - - calendarEventSpec.type = CalendarEventSpec.TYPE_SUNRISE; - calendarEventSpec.title = "Sunrise"; - if (sunriseTransitSetToday[0] != null) { - calendarEventSpec.id = 1; - calendarEventSpec.timestamp = (int) (sunriseTransitSetToday[0].getTimeInMillis() / 1000); - GBApplication.deviceService().onAddCalendarEvent(calendarEventSpec); - } - if (sunriseTransitSetTomorrow[0] != null) { - calendarEventSpec.id = 2; - calendarEventSpec.timestamp = (int) (sunriseTransitSetTomorrow[0].getTimeInMillis() / 1000); - GBApplication.deviceService().onAddCalendarEvent(calendarEventSpec); - } - - calendarEventSpec.type = CalendarEventSpec.TYPE_SUNSET; - calendarEventSpec.title = "Sunset"; - if (sunriseTransitSetToday[2] != null) { - calendarEventSpec.id = 1; - calendarEventSpec.timestamp = (int) (sunriseTransitSetToday[2].getTimeInMillis() / 1000); - GBApplication.deviceService().onAddCalendarEvent(calendarEventSpec); - } - if (sunriseTransitSetTomorrow[2] != null) { - calendarEventSpec.id = 2; - calendarEventSpec.timestamp = (int) (sunriseTransitSetTomorrow[2].getTimeInMillis() / 1000); - GBApplication.deviceService().onAddCalendarEvent(calendarEventSpec); - } } }); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmReceiver.java new file mode 100644 index 00000000..b725c4b7 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmReceiver.java @@ -0,0 +1,88 @@ +package nodomain.freeyourgadget.gadgetbridge.externalevents; + + +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +import net.e175.klaus.solarpositioning.DeltaT; +import net.e175.klaus.solarpositioning.SPA; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Calendar; +import java.util.GregorianCalendar; + +import nodomain.freeyourgadget.gadgetbridge.BuildConfig; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec; +import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; + +public class AlarmReceiver extends BroadcastReceiver { + private static final Logger LOG = LoggerFactory.getLogger(DeviceCommunicationService.class); + + public AlarmReceiver() { + Context context = GBApplication.getContext(); + Intent intent = new Intent("DAILY_ALARM"); + intent.setPackage(BuildConfig.APPLICATION_ID); + PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, new Intent("DAILY_ALARM"), 0); + AlarmManager am = (AlarmManager) (context.getSystemService(Context.ALARM_SERVICE)); + + am.setInexactRepeating(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis() + 10000, AlarmManager.INTERVAL_DAY, pendingIntent); + } + + @Override + public void onReceive(Context context, Intent intent) { + LOG.info("will resend sunrise and sunset events"); + + GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_SUNRISE, 1); + GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_SUNRISE, 2); + GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_SUNSET, 1); + GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_SUNSET, 2); + + Prefs prefs = GBApplication.getPrefs(); + + float latitude = prefs.getFloat("location_latitude", 0); + float longitude = prefs.getFloat("location_longitude", 0); + final GregorianCalendar dateTimeToday = new GregorianCalendar(); + final GregorianCalendar dateTimeTomorrow = new GregorianCalendar(); + dateTimeTomorrow.add(GregorianCalendar.DAY_OF_MONTH, 1); + + GregorianCalendar[] sunriseTransitSetToday = SPA.calculateSunriseTransitSet(dateTimeToday, latitude, longitude, DeltaT.estimate(dateTimeToday)); + GregorianCalendar[] sunriseTransitSetTomorrow = SPA.calculateSunriseTransitSet(dateTimeTomorrow, latitude, longitude, DeltaT.estimate(dateTimeToday)); + + CalendarEventSpec calendarEventSpec = new CalendarEventSpec(); + calendarEventSpec.durationInSeconds = 0; + calendarEventSpec.description = null; + + calendarEventSpec.type = CalendarEventSpec.TYPE_SUNRISE; + calendarEventSpec.title = "Sunrise"; + if (sunriseTransitSetToday[0] != null) { + calendarEventSpec.id = 1; + calendarEventSpec.timestamp = (int) (sunriseTransitSetToday[0].getTimeInMillis() / 1000); + GBApplication.deviceService().onAddCalendarEvent(calendarEventSpec); + } + if (sunriseTransitSetTomorrow[0] != null) { + calendarEventSpec.id = 2; + calendarEventSpec.timestamp = (int) (sunriseTransitSetTomorrow[0].getTimeInMillis() / 1000); + GBApplication.deviceService().onAddCalendarEvent(calendarEventSpec); + } + + calendarEventSpec.type = CalendarEventSpec.TYPE_SUNSET; + calendarEventSpec.title = "Sunset"; + if (sunriseTransitSetToday[2] != null) { + calendarEventSpec.id = 1; + calendarEventSpec.timestamp = (int) (sunriseTransitSetToday[2].getTimeInMillis() / 1000); + GBApplication.deviceService().onAddCalendarEvent(calendarEventSpec); + } + if (sunriseTransitSetTomorrow[2] != null) { + calendarEventSpec.id = 2; + calendarEventSpec.timestamp = (int) (sunriseTransitSetTomorrow[2].getTimeInMillis() / 1000); + GBApplication.deviceService().onAddCalendarEvent(calendarEventSpec); + } + } +} 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 4e5b73ea..ed7edc01 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -25,6 +25,7 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.externalevents.AlarmReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.BluetoothConnectReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.K9Receiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.MusicPlaybackReceiver; @@ -117,6 +118,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere private MusicPlaybackReceiver mMusicPlaybackReceiver = null; private TimeChangeReceiver mTimeChangeReceiver = null; private BluetoothConnectReceiver mBlueToothConnectReceiver = null; + private AlarmReceiver mAlarmReceiver = null; private Random mRandom = new Random(); @@ -495,6 +497,10 @@ public class DeviceCommunicationService extends Service implements SharedPrefere mBlueToothConnectReceiver = new BluetoothConnectReceiver(this); registerReceiver(mBlueToothConnectReceiver, new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED)); } + if (mAlarmReceiver == null) { + mAlarmReceiver = new AlarmReceiver(); + registerReceiver(mAlarmReceiver, new IntentFilter("DAILY_ALARM")); + } } else { if (mPhoneCallReceiver != null) { unregisterReceiver(mPhoneCallReceiver); @@ -524,6 +530,10 @@ public class DeviceCommunicationService extends Service implements SharedPrefere unregisterReceiver(mBlueToothConnectReceiver); mBlueToothConnectReceiver = null; } + if (mAlarmReceiver != null) { + unregisterReceiver(mAlarmReceiver); + mAlarmReceiver = null; + } } } From cb1ec5dccb72be35e01f7067c49717a5fa5e233b Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Tue, 24 May 2016 13:11:57 +0200 Subject: [PATCH 17/58] Make calendar event type byte instead of int Now the UUID will be constructed like this: High 64bit 0x4742474200 | type Low 64bit id --- .../freeyourgadget/gadgetbridge/devices/EventHandler.java | 2 +- .../freeyourgadget/gadgetbridge/impl/GBDeviceService.java | 2 +- .../gadgetbridge/model/CalendarEventSpec.java | 8 ++++---- .../gadgetbridge/service/DeviceCommunicationService.java | 4 ++-- .../gadgetbridge/service/ServiceDeviceSupport.java | 2 +- .../service/devices/miband/MiBandSupport.java | 2 +- .../service/devices/pebble/PebbleProtocol.java | 8 +++++--- .../service/devices/pebble/PebbleSupport.java | 2 +- .../service/serial/AbstractSerialDeviceSupport.java | 2 +- .../gadgetbridge/service/serial/GBDeviceProtocol.java | 2 +- .../gadgetbridge/service/TestDeviceSupport.java | 2 +- 11 files changed, 19 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java index d4f44101..602ca5c8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java @@ -55,5 +55,5 @@ public interface EventHandler { void onAddCalendarEvent(CalendarEventSpec calendarEventSpec); - void onDeleteCalendarEvent(int type, long id); + void onDeleteCalendarEvent(byte type, long id); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java index 6c51e6b2..2e598eac 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java @@ -238,7 +238,7 @@ public class GBDeviceService implements DeviceService { } @Override - public void onDeleteCalendarEvent(int type, long id) { + public void onDeleteCalendarEvent(byte type, long id) { Intent intent = createIntent().setAction(ACTION_DELETE_CALENDAREVENT) .putExtra(EXTRA_CALENDAREVENT_TYPE, type) .putExtra(EXTRA_CALENDAREVENT_ID, id); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/CalendarEventSpec.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/CalendarEventSpec.java index 7f52b2a2..438123e4 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/CalendarEventSpec.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/CalendarEventSpec.java @@ -1,11 +1,11 @@ package nodomain.freeyourgadget.gadgetbridge.model; public class CalendarEventSpec { - public static final int TYPE_UNKNOWN = 0; - public static final int TYPE_SUNRISE = 1; - public static final int TYPE_SUNSET = 2; + public static final byte TYPE_UNKNOWN = 0; + public static final byte TYPE_SUNRISE = 1; + public static final byte TYPE_SUNSET = 2; - public int type; + public byte type; public long id; public int timestamp; public int durationInSeconds; 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 ed7edc01..fdafa526 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -282,7 +282,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere case ACTION_ADD_CALENDAREVENT: { CalendarEventSpec calendarEventSpec = new CalendarEventSpec(); calendarEventSpec.id = intent.getLongExtra(EXTRA_CALENDAREVENT_ID, -1); - calendarEventSpec.type = intent.getIntExtra(EXTRA_CALENDAREVENT_TYPE, -1); + calendarEventSpec.type = intent.getByteExtra(EXTRA_CALENDAREVENT_TYPE, (byte) -1); calendarEventSpec.timestamp = intent.getIntExtra(EXTRA_CALENDAREVENT_TIMESTAMP, -1); calendarEventSpec.durationInSeconds = intent.getIntExtra(EXTRA_CALENDAREVENT_DURATION, -1); calendarEventSpec.title = intent.getStringExtra(EXTRA_CALENDAREVENT_TITLE); @@ -292,7 +292,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere } case ACTION_DELETE_CALENDAREVENT: { long id = intent.getLongExtra(EXTRA_CALENDAREVENT_ID, -1); - int type = intent.getIntExtra(EXTRA_CALENDAREVENT_TYPE, -1); + byte type = intent.getByteExtra(EXTRA_CALENDAREVENT_TYPE, (byte) -1); mDeviceSupport.onDeleteCalendarEvent(type, id); break; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java index 6753f27e..019722b5 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java @@ -279,7 +279,7 @@ public class ServiceDeviceSupport implements DeviceSupport { } @Override - public void onDeleteCalendarEvent(int type, long id) { + public void onDeleteCalendarEvent(byte type, long id) { if (checkBusy("delete calendar event")) { return; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java index ea2d4d7c..444e59ee 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java @@ -389,7 +389,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { } @Override - public void onDeleteCalendarEvent(int type, long id) { + public void onDeleteCalendarEvent(byte type, long id) { // not supported } 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 a3e4b02c..9901f85e 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 @@ -241,6 +241,8 @@ public class PebbleProtocol extends GBDeviceProtocol { static final byte LENGTH_UUID = 16; + static final long GB_UUID_MASK = 0x4742474200L; + // base is -5 private static final String[] hwRevisions = { // Emulator @@ -479,12 +481,12 @@ public class PebbleProtocol extends GBDeviceProtocol { iconId = PebbleIconID.TIMELINE_CALENDAR; } - return encodeTimelinePin(new UUID(calendarEventSpec.type, id), calendarEventSpec.timestamp, (short) calendarEventSpec.durationInSeconds, iconId, calendarEventSpec.title, calendarEventSpec.description); + return encodeTimelinePin(new UUID(GB_UUID_MASK | calendarEventSpec.type, id), calendarEventSpec.timestamp, (short) calendarEventSpec.durationInSeconds, iconId, calendarEventSpec.title, calendarEventSpec.description); } @Override - public byte[] encodeDeleteCalendarEvent(int type, long id) { - return encodeBlobdb(new UUID(type, id), BLOBDB_DELETE, BLOBDB_PIN, null); + public byte[] encodeDeleteCalendarEvent(byte type, long id) { + return encodeBlobdb(new UUID(GB_UUID_MASK | type, id), BLOBDB_DELETE, BLOBDB_PIN, null); } @Override 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 9414f065..b0bc3b47 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 @@ -129,7 +129,7 @@ public class PebbleSupport extends AbstractSerialDeviceSupport { } @Override - public void onDeleteCalendarEvent(int type, long id) { + public void onDeleteCalendarEvent(byte type, long id) { if (reconnect()) { super.onDeleteCalendarEvent(type, id); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java index 18be585d..78e15667 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java @@ -196,7 +196,7 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport } @Override - public void onDeleteCalendarEvent(int type, long id) { + public void onDeleteCalendarEvent(byte type, long id) { byte[] bytes = gbDeviceProtocol.encodeDeleteCalendarEvent(type, id); sendToDevice(bytes); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java index 79337b5d..a226c094 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java @@ -70,7 +70,7 @@ public abstract class GBDeviceProtocol { return null; } - public byte[] encodeDeleteCalendarEvent(int type, long id) { + public byte[] encodeDeleteCalendarEvent(byte type, long id) { return null; } diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java index 45eea6eb..8070cb1e 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java @@ -137,7 +137,7 @@ public class TestDeviceSupport extends AbstractDeviceSupport { } @Override - public void onDeleteCalendarEvent(int type, long id) { + public void onDeleteCalendarEvent(byte type, long id) { } From e3bee37b819599d869c47eccef2d3976bc302f76 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Tue, 24 May 2016 13:20:16 +0200 Subject: [PATCH 18/58] Change UUID prefix to 0x4767744272646700 --- .../gadgetbridge/service/devices/pebble/PebbleProtocol.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 9901f85e..c6f00394 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 @@ -241,7 +241,7 @@ public class PebbleProtocol extends GBDeviceProtocol { static final byte LENGTH_UUID = 16; - static final long GB_UUID_MASK = 0x4742474200L; + static final long GB_UUID_MASK = 0x4767744272646700L; // base is -5 private static final String[] hwRevisions = { From 55a40f7b062bf4fbf3e0b1cc02725b65b29b535a Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Tue, 24 May 2016 14:46:22 +0200 Subject: [PATCH 19/58] Sunset/sunrise: rotate ids and reuse the id from two days ago for tomorrow, this way we will have sunrise/sunset for 3 days while sending only sunrise/sunset per day --- .../externalevents/AlarmReceiver.java | 35 ++++++++----------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmReceiver.java index b725c4b7..e1d4066a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmReceiver.java @@ -39,21 +39,24 @@ public class AlarmReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { LOG.info("will resend sunrise and sunset events"); - GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_SUNRISE, 1); - GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_SUNRISE, 2); - GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_SUNSET, 1); - GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_SUNSET, 2); + final GregorianCalendar dateTimeTomorrow = new GregorianCalendar(); + dateTimeTomorrow.add(GregorianCalendar.DAY_OF_MONTH, 1); + + /* + * rotate ids ud reuse the id from two days ago for tomorrow, this way we will have + * sunrise /sunset for 3 days while sending only sunrise/sunset per day + */ + byte id_tomorrow = (byte) ((dateTimeTomorrow.getTimeInMillis() / (1000L * 60L * 60L * 24L)) % 3); + + GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_SUNRISE, id_tomorrow); + GBApplication.deviceService().onDeleteCalendarEvent(CalendarEventSpec.TYPE_SUNSET, id_tomorrow); Prefs prefs = GBApplication.getPrefs(); float latitude = prefs.getFloat("location_latitude", 0); float longitude = prefs.getFloat("location_longitude", 0); - final GregorianCalendar dateTimeToday = new GregorianCalendar(); - final GregorianCalendar dateTimeTomorrow = new GregorianCalendar(); - dateTimeTomorrow.add(GregorianCalendar.DAY_OF_MONTH, 1); - GregorianCalendar[] sunriseTransitSetToday = SPA.calculateSunriseTransitSet(dateTimeToday, latitude, longitude, DeltaT.estimate(dateTimeToday)); - GregorianCalendar[] sunriseTransitSetTomorrow = SPA.calculateSunriseTransitSet(dateTimeTomorrow, latitude, longitude, DeltaT.estimate(dateTimeToday)); + GregorianCalendar[] sunriseTransitSetTomorrow = SPA.calculateSunriseTransitSet(dateTimeTomorrow, latitude, longitude, DeltaT.estimate(dateTimeTomorrow)); CalendarEventSpec calendarEventSpec = new CalendarEventSpec(); calendarEventSpec.durationInSeconds = 0; @@ -61,26 +64,16 @@ public class AlarmReceiver extends BroadcastReceiver { calendarEventSpec.type = CalendarEventSpec.TYPE_SUNRISE; calendarEventSpec.title = "Sunrise"; - if (sunriseTransitSetToday[0] != null) { - calendarEventSpec.id = 1; - calendarEventSpec.timestamp = (int) (sunriseTransitSetToday[0].getTimeInMillis() / 1000); - GBApplication.deviceService().onAddCalendarEvent(calendarEventSpec); - } if (sunriseTransitSetTomorrow[0] != null) { - calendarEventSpec.id = 2; + calendarEventSpec.id = id_tomorrow; calendarEventSpec.timestamp = (int) (sunriseTransitSetTomorrow[0].getTimeInMillis() / 1000); GBApplication.deviceService().onAddCalendarEvent(calendarEventSpec); } calendarEventSpec.type = CalendarEventSpec.TYPE_SUNSET; calendarEventSpec.title = "Sunset"; - if (sunriseTransitSetToday[2] != null) { - calendarEventSpec.id = 1; - calendarEventSpec.timestamp = (int) (sunriseTransitSetToday[2].getTimeInMillis() / 1000); - GBApplication.deviceService().onAddCalendarEvent(calendarEventSpec); - } if (sunriseTransitSetTomorrow[2] != null) { - calendarEventSpec.id = 2; + calendarEventSpec.id = id_tomorrow; calendarEventSpec.timestamp = (int) (sunriseTransitSetTomorrow[2].getTimeInMillis() / 1000); GBApplication.deviceService().onAddCalendarEvent(calendarEventSpec); } From bf66c25c7f1438640941c32b37cc50c4282ff808 Mon Sep 17 00:00:00 2001 From: andre Date: Tue, 24 May 2016 19:33:12 +0200 Subject: [PATCH 20/58] MusicPlayBackReceiver set track, artist and album to the artist member of MusicSpec. Now the assignment of artist, track and album is correct --- .../externalevents/MusicPlaybackReceiver.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/MusicPlaybackReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/MusicPlaybackReceiver.java index d910e75e..67c7e8e7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/MusicPlaybackReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/MusicPlaybackReceiver.java @@ -3,6 +3,7 @@ package nodomain.freeyourgadget.gadgetbridge.externalevents; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.os.Bundle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,20 +19,13 @@ public class MusicPlaybackReceiver extends BroadcastReceiver { String artist = intent.getStringExtra("artist"); String album = intent.getStringExtra("album"); String track = intent.getStringExtra("track"); - /* - Bundle bundle = intent.getExtras(); - for (String key : bundle.keySet()) { - Object value = bundle.get(key); - LOG.info(String.format("%s %s (%s)", key, - value != null ? value.toString() : "null", value != null ? value.getClass().getName() : "no class")); - } - */ + LOG.info("Current track: " + artist + ", " + album + ", " + track); MusicSpec musicSpec = new MusicSpec(); musicSpec.artist = artist; - musicSpec.artist = album; - musicSpec.artist = track; + musicSpec.album = album; + musicSpec.track = track; GBApplication.deviceService().onSetMusicInfo(musicSpec); } From 31c15bb8b8e3210116fa59e73e05bfa5dd9fb8e9 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Tue, 24 May 2016 23:55:03 +0200 Subject: [PATCH 21/58] update changelog --- CHANGELOG.md | 1 + app/src/main/res/xml/changelog_master.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 91ce3b0e..fb97f49e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * 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 +* Pebble: fix music information being messed up * Honour "Do Not Disturb" for phone calls and SMS ####Version 0.9.7 diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml index abe77eba..30022f53 100644 --- a/app/src/main/res/xml/changelog_master.xml +++ b/app/src/main/res/xml/changelog_master.xml @@ -7,6 +7,7 @@ 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: fix music information being messed up Pebble: hopefully fix some reconnect issues From 7ef005f6a38e85a6810c9414c828664dfa6c29a5 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 26 May 2016 14:39:54 +0200 Subject: [PATCH 22/58] Allow getting the network location within pebble settings for sunrise/sunset calculation It is also possible to set the location manually On Android >=6 the required permission will be requested when pressing the button in settings. --- app/src/main/AndroidManifest.xml | 1 + .../activities/SettingsActivity.java | 43 ++++++++++++++++++- .../externalevents/AlarmReceiver.java | 5 +-- app/src/main/res/values/strings.xml | 9 +++- app/src/main/res/xml/preferences.xml | 24 ++++++----- 5 files changed, 66 insertions(+), 16 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5d0ac7d1..c72495ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -17,6 +17,7 @@ + Date and Time Sync time Sync time to device when connecting and when time or timezone changes on Android - Latitude - Longitude Theme Light @@ -77,11 +75,18 @@ Preferred Activitytracker Allow 3rd Party Android App Access Enable experimental support for Android Apps using PebbleKit + + Location + Aquire Location + Latitude + Longitude + Force Notification Protocol This option forces using the latest notification protocol depending on the firmware version. ENABLE ONLY IF YOU KNOW WHAT YOU ARE DOING! Enable untested features Enable features that are untested. ENABLE ONLY IF YOU KNOW WHAT YOU ARE DOING! Reconnection Attempts + not connected connecting connected diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index d3c3a655..43ff84f7 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -32,14 +32,6 @@ android:key="datetime_synconconnect" android:summary="@string/pref_summary_datetime_syctimeonconnect" android:title="@string/pref_title_datetime_syctimeonconnect" /> - - + + + + + Date: Thu, 26 May 2016 14:58:36 +0200 Subject: [PATCH 23/58] Reenable our discovery activity for Android 6 Now that we request location we are allowed to do a btle scan again --- .../gadgetbridge/activities/ControlCenter.java | 6 +----- .../gadgetbridge/activities/DiscoveryActivity.java | 10 ++++++++++ .../gadgetbridge/activities/SettingsActivity.java | 7 ++++--- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenter.java index 702aa134..37de8193 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenter.java @@ -353,11 +353,7 @@ public class ControlCenter extends GBActivity { } private void launchDiscoveryActivity() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - startActivity(new Intent(android.provider.Settings.ACTION_BLUETOOTH_SETTINGS)); - } else { - startActivity(new Intent(this, DiscoveryActivity.class)); - } + startActivity(new Intent(this, DiscoveryActivity.class)); } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DiscoveryActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DiscoveryActivity.java index f2ab531b..3f00ced4 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DiscoveryActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DiscoveryActivity.java @@ -1,5 +1,6 @@ package nodomain.freeyourgadget.gadgetbridge.activities; +import android.Manifest; import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; @@ -8,10 +9,12 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.Parcelable; +import android.support.v4.app.ActivityCompat; import android.view.View; import android.widget.AdapterView; import android.widget.Button; @@ -48,6 +51,7 @@ public class DiscoveryActivity extends GBActivity implements AdapterView.OnItemC case BluetoothAdapter.ACTION_DISCOVERY_FINISHED: // continue with LE scan, if available if (isScanning == Scanning.SCANNING_BT) { + checkAndRequestLocationPermission(); startDiscovery(Scanning.SCANNING_BTLE); } else { discoveryFinished(); @@ -320,6 +324,12 @@ public class DiscoveryActivity extends GBActivity implements AdapterView.OnItemC adapter.startDiscovery(); } + private void checkAndRequestLocationPermission() { + if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 0); + } + } + private Message getPostMessage(Runnable runnable) { Message m = Message.obtain(handler, runnable); m.obj = runnable; 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 c2e83c54..41d6bc55 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java @@ -129,11 +129,12 @@ public class SettingsActivity extends AbstractSettingsActivity { pref = findPreference("location_aquire"); pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { public boolean onPreferenceClick(Preference preference) { - LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); - Criteria criteria = new Criteria(); - if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(SettingsActivity.this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 0); } + + LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); + Criteria criteria = new Criteria(); String provider = locationManager.getBestProvider(criteria, false); if (provider != null) { Location location = locationManager.getLastKnownLocation(provider); From b0e0aec4651b0e490ba65fc85a36bab5df9deb50 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 26 May 2016 15:20:27 +0200 Subject: [PATCH 24/58] fix typo --- .../gadgetbridge/externalevents/BluetoothConnectReceiver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothConnectReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothConnectReceiver.java index 5282e7a5..af973861 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothConnectReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothConnectReceiver.java @@ -14,7 +14,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService; public class BluetoothConnectReceiver extends BroadcastReceiver { - private static final Logger LOG = LoggerFactory.getLogger(DeviceCommunicationService.class); + private static final Logger LOG = LoggerFactory.getLogger(BluetoothConnectReceiver.class); final DeviceCommunicationService service; From c360eb3392ca36094d55b8d29bca9f6bc773ca01 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 26 May 2016 19:03:38 +0200 Subject: [PATCH 25/58] This should fix some connection problems #274 Some APIs have become synchronous, it seems, e.g. connectGatt() -> onConnectionStateChanged() -> discoverServices() -> onServicesDiscovered() appears to happen synchronously. So connectGatt() will not return before services are discovered! So now we deal with this situation. --- .../service/btle/AbstractBTLEDeviceSupport.java | 3 +-- .../freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java | 6 ++++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEDeviceSupport.java index 04179458..26118112 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEDeviceSupport.java @@ -147,7 +147,6 @@ public abstract class AbstractBTLEDeviceSupport extends AbstractDeviceSupport im } private void gattServicesDiscovered(List discoveredGattServices) { - if (discoveredGattServices == null) { return; } @@ -180,7 +179,7 @@ public abstract class AbstractBTLEDeviceSupport extends AbstractDeviceSupport im @Override public void onServicesDiscovered(BluetoothGatt gatt) { - gattServicesDiscovered(getQueue().getSupportedGattServices()); + gattServicesDiscovered(gatt.getServices()); initializeDevice(createTransactionBuilder("Initializing device")).queue(getQueue()); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java index f6009435..4a432d0b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java @@ -308,6 +308,12 @@ public final class BtLEQueue { public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { LOG.debug("connection state change, newState: " + newState + getStatusString(status)); + synchronized (mGattMonitor) { + if (mBluetoothGatt == null) { + mBluetoothGatt = gatt; + } + } + if (!checkCorrectGattInstance(gatt, "connection state event")) { return; } From 6e33c7364a41de480727b2421756f91faa174b09 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 26 May 2016 22:21:58 +0200 Subject: [PATCH 26/58] Remove some commented code --- .../freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java index 4a432d0b..78280d09 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java @@ -156,11 +156,9 @@ public final class BtLEQueue { LOG.info("Attempting to connect to " + mGbDevice.getName()); mBluetoothAdapter.cancelDiscovery(); BluetoothDevice remoteDevice = mBluetoothAdapter.getRemoteDevice(mGbDevice.getAddress()); -// boolean result; synchronized (mGattMonitor) { // connectGatt with true doesn't really work ;( too often connection problems mBluetoothGatt = remoteDevice.connectGatt(mContext, false, internalGattCallback); -// result = mBluetoothGatt.connect(); } boolean result = mBluetoothGatt != null; if (result) { From 50b7a02ef2da979476c68e43a54a62e7802584ad Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 26 May 2016 23:46:21 +0200 Subject: [PATCH 27/58] One more attempt at fixing dynamic logging reconfiguration - moved out of GBApplication to class Logging - the main thing is: when start()ing the FileAppender again, it *must* - be configured to be non-lazy, otherwise it won't open the stream ever again. --- app/build.gradle | 5 +- .../gadgetbridge/GBApplication.java | 87 ++---------- .../freeyourgadget/gadgetbridge/Logging.java | 128 ++++++++++++++++++ .../gadgetbridge/util/FileUtils.java | 27 ++++ .../gadgetbridge/test/LoggingTest.java | 87 ++++++++++++ 5 files changed, 257 insertions(+), 77 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/Logging.java create mode 100644 app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/LoggingTest.java diff --git a/app/build.gradle b/app/build.gradle index c1e9642d..b52632f0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,6 +6,8 @@ def ABORT_ON_CHECK_FAILURE=false tasks.withType(Test) { systemProperty 'MiFirmwareDir', System.getProperty('MiFirmwareDir', null) } +// sourceSets.test.runtimeClasspath += File('src/main/assets') + android { compileSdkVersion 23 buildToolsVersion "23.0.3" @@ -42,6 +44,8 @@ android { } dependencies { +// testCompile 'ch.qos.logback:logback-classic:1.1.3' +// testCompile 'ch.qos.logback:logback-core:1.1.3' testCompile 'junit:junit:4.12' testCompile "org.mockito:mockito-core:1.9.5" @@ -100,7 +104,6 @@ task pmd(type: Pmd) { } } - task findbugs(type: FindBugs) { ignoreFailures = !ABORT_ON_CHECK_FAILURE effort = "default" diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java index 073689a8..0113effb 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java @@ -20,9 +20,6 @@ import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import android.util.TypedValue; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.File; import java.io.IOException; import java.util.HashSet; @@ -30,8 +27,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import ch.qos.logback.classic.spi.ILoggingEvent; -import ch.qos.logback.core.Appender; import nodomain.freeyourgadget.gadgetbridge.database.ActivityDatabaseHandler; import nodomain.freeyourgadget.gadgetbridge.database.DBConstants; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; @@ -62,7 +57,6 @@ public class GBApplication extends Application { //if preferences have to be migrated, increment the following and add the migration logic in migratePrefs below; see http://stackoverflow.com/questions/16397848/how-can-i-migrate-android-preferences-with-a-new-version private static final int CURRENT_PREFS_VERSION = 2; private static LimitedQueue mIDSenderLookup = new LimitedQueue(16); - private static Appender fileLogger; private static Prefs prefs; private static GBPrefs gbPrefs; /** @@ -72,6 +66,13 @@ public class GBApplication extends Application { public static final String ACTION_QUIT = "nodomain.freeyourgadget.gadgetbridge.gbapplication.action.quit"; + private static Logging logging = new Logging() { + @Override + protected String createLogDirectory() throws IOException { + File dir = FileUtils.getExternalFilesDir(); + return dir.getAbsolutePath(); + } + }; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -114,11 +115,6 @@ public class GBApplication extends Application { } setupExceptionHandler(); -// For debugging problems with the logback configuration -// LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); -// print logback's internal status -// StatusPrinter.print(lc); -// Logger logger = LoggerFactory.getLogger(GBApplication.class); deviceService = createDeviceService(); GB.environment = GBEnvironment.createDeviceEnvironment(); @@ -138,6 +134,10 @@ public class GBApplication extends Application { // db.close(); } + public static void setupLogging(boolean enabled) { + logging.setupLogging(enabled); + } + private void setupExceptionHandler() { LoggingExceptionHandler handler = new LoggingExceptionHandler(Thread.getDefaultUncaughtExceptionHandler()); Thread.setDefaultUncaughtExceptionHandler(handler); @@ -147,71 +147,6 @@ public class GBApplication extends Application { return prefs.getBoolean("log_to_file", false); } - public static void setupLogging(boolean enable) { - try { - if (fileLogger == null) { - File dir = FileUtils.getExternalFilesDir(); - // used by assets/logback.xml since the location cannot be statically determined - System.setProperty("GB_LOGFILES_DIR", dir.getAbsolutePath()); - rememberFileLogger(); - } - if (enable) { - startFileLogger(); - } else { - stopFileLogger(); - } - getLogger().info("Gadgetbridge version: " + BuildConfig.VERSION_NAME); - } catch (IOException ex) { - Log.e("GBApplication", "External files dir not available, cannot log to file", ex); - stopFileLogger(); - } - } - - private static void startFileLogger() { - if (fileLogger != null && !fileLogger.isStarted()) { - addFileLogger(fileLogger); - fileLogger.start(); - } - } - - private static void stopFileLogger() { - if (fileLogger != null && fileLogger.isStarted()) { - fileLogger.stop(); - removeFileLogger(fileLogger); - } - } - - private static void rememberFileLogger() { - ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); - fileLogger = root.getAppender("FILE"); - } - - private static void addFileLogger(Appender fileLogger) { - try { - ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); - if (!root.isAttached(fileLogger)) { - root.addAppender(fileLogger); - } - } catch (Throwable ex) { - Log.e("GBApplication", "Error adding logger FILE appender", ex); - } - } - - private static void removeFileLogger(Appender fileLogger) { - try { - ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); - if (root.isAttached(fileLogger)) { - root.detachAppender(fileLogger); - } - } catch (Throwable ex) { - Log.e("GBApplication", "Error removing logger FILE appender", ex); - } - } - - private static Logger getLogger() { - return LoggerFactory.getLogger(GBApplication.class); - } - public static Context getContext() { return context; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/Logging.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/Logging.java new file mode 100644 index 00000000..7ea3c8e9 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/Logging.java @@ -0,0 +1,128 @@ +package nodomain.freeyourgadget.gadgetbridge; + +import android.util.Log; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.Appender; +import ch.qos.logback.core.FileAppender; +import ch.qos.logback.core.encoder.Encoder; +import ch.qos.logback.core.encoder.LayoutWrappingEncoder; +import ch.qos.logback.core.util.StatusPrinter; + +public abstract class Logging { + public static final String PROP_LOGFILES_DIR = "GB_LOGFILES_DIR"; + + private FileAppender fileLogger; + + public void setupLogging(boolean enable) { + try { + if (fileLogger == null) { + init(); + } + if (enable) { + startFileLogger(); + } else { + stopFileLogger(); + } + getLogger().info("Gadgetbridge version: " + BuildConfig.VERSION_NAME); + } catch (IOException ex) { + Log.e("GBApplication", "External files dir not available, cannot log to file", ex); + stopFileLogger(); + } + } + + public void debugLoggingConfiguration() { + // For debugging problems with the logback configuration + LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); + // print logback's internal status + StatusPrinter.print(lc); +// Logger logger = LoggerFactory.getLogger(Logging.class); + } + + protected abstract String createLogDirectory() throws IOException; + + protected void init() throws IOException { + String dir = createLogDirectory(); + if (dir == null) { + throw new IllegalArgumentException("log directory must not be null"); + } + // used by assets/logback.xml since the location cannot be statically determined + System.setProperty(PROP_LOGFILES_DIR, dir); + rememberFileLogger(); + } + + private Logger getLogger() { + return LoggerFactory.getLogger(Logging.class); + } + + private void startFileLogger() { + if (fileLogger != null && !fileLogger.isStarted()) { + addFileLogger(fileLogger); + fileLogger.setLazy(false); // hack to make sure that start() actually opens the file + fileLogger.start(); + } + } + + private void stopFileLogger() { + if (fileLogger != null && fileLogger.isStarted()) { + fileLogger.stop(); + removeFileLogger(fileLogger); + } + } + + private void rememberFileLogger() { + ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); + fileLogger = (FileAppender) root.getAppender("FILE"); + } + + private void addFileLogger(Appender fileLogger) { + try { + ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); + if (!root.isAttached(fileLogger)) { + root.addAppender(fileLogger); + } + } catch (Throwable ex) { + Log.e("GBApplication", "Error adding logger FILE appender", ex); + } + } + + private void removeFileLogger(Appender fileLogger) { + try { + ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); + if (root.isAttached(fileLogger)) { + root.detachAppender(fileLogger); + } + } catch (Throwable ex) { + Log.e("GBApplication", "Error removing logger FILE appender", ex); + } + } + + public FileAppender getFileLogger() { + return fileLogger; + } + + public boolean setImmediateFlush(boolean enable) { + FileAppender fileLogger = getFileLogger(); + Encoder encoder = fileLogger.getEncoder(); + if (encoder instanceof LayoutWrappingEncoder) { + ((LayoutWrappingEncoder) encoder).setImmediateFlush(enable); + return true; + } + return false; + } + + public boolean isImmediateFlush() { + FileAppender fileLogger = getFileLogger(); + Encoder encoder = fileLogger.getEncoder(); + if (encoder instanceof LayoutWrappingEncoder) { + return ((LayoutWrappingEncoder) encoder).isImmediateFlush(); + } + return false; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/FileUtils.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/FileUtils.java index b354edb7..470ef392 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/FileUtils.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/FileUtils.java @@ -182,4 +182,31 @@ public class FileUtils { } return out.toByteArray(); } + + public static boolean deleteRecursively(File dir) { + if (!dir.exists()) { + return true; + } + if (dir.isFile()) { + return dir.delete(); + } + for (File sub : dir.listFiles()) { + if (!deleteRecursively(sub)) { + return false; + } + } + return dir.delete(); + } + + public static File createTempDir(String prefix) throws IOException { + File parent = new File(System.getProperty("java.io.tmpdir", "/tmp")); + for (int i = 1; i < 100; i++) { + String name = prefix + (int) (Math.random() * 100000); + File dir = new File(parent, name); + if (dir.mkdirs()) { + return dir; + } + } + throw new IOException("Cannot create temporary directory in " + parent); + } } \ No newline at end of file diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/LoggingTest.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/LoggingTest.java new file mode 100644 index 00000000..3b68430a --- /dev/null +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/LoggingTest.java @@ -0,0 +1,87 @@ +package nodomain.freeyourgadget.gadgetbridge.test; + +import android.support.annotation.NonNull; + +import junit.framework.AssertionFailedError; + +import org.junit.After; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; + +import nodomain.freeyourgadget.gadgetbridge.Logging; +import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertTrue; +import static junit.framework.Assert.fail; + +public class LoggingTest { + + @BeforeClass + public static void setupSuite() { + System.setProperty("logback.configurationFile", "logback.xml"); + } + + private Logging logging = new Logging() { + @Override + protected String createLogDirectory() throws IOException { + File dir = ensureLogFilesDir(); + return dir.getAbsolutePath(); + } + + @NonNull + private File ensureLogFilesDir() throws IOException { + return FileUtils.createTempDir("logfiles"); + } + }; + + @After + public void tearDown() { + assertTrue(FileUtils.deleteRecursively(getLogFilesDir())); + } + + @NonNull + private File getLogFilesDir() { + String dirName = System.getProperty(Logging.PROP_LOGFILES_DIR); + if (dirName != null && dirName.length() > 5) { + File dir = new File(dirName); + return dir; + } + fail("Property " + Logging.PROP_LOGFILES_DIR + " has invalid value: " + dirName); + return null; // not reached + } + + @Test + public void testToggleLogging() { + try { + File dir = getLogFilesDir(); + } catch (AssertionFailedError ignored) { + // expected, as not yet set up + } + + try { + logging.setupLogging(true); + File dir = getLogFilesDir(); + assertEquals(1, dir.list().length); + assertNotNull(logging.getFileLogger()); + assertTrue(logging.getFileLogger().isStarted()); + + logging.setupLogging(false); + assertNotNull(logging.getFileLogger()); + assertFalse(logging.getFileLogger().isStarted()); + + logging.setupLogging(true); + assertNotNull(logging.getFileLogger()); + assertTrue(logging.getFileLogger().isStarted()); + } catch (AssertionFailedError ex) { + logging.debugLoggingConfiguration(); + System.err.println(System.getProperty("java.class.path")); + throw ex; + } + } +} From 2d49ce505a8676a5650d9581ef5f86579c8463b7 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 26 May 2016 23:48:05 +0200 Subject: [PATCH 28/58] Set state to "Waiting for reconnect" for BTLE devices --- .../freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java index 78280d09..fc7358a8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java @@ -221,7 +221,11 @@ public final class BtLEQueue { private boolean maybeReconnect() { if (mAutoReconnect && mBluetoothGatt != null) { LOG.info("Enabling automatic ble reconnect..."); - return mBluetoothGatt.connect(); + boolean result = mBluetoothGatt.connect(); + if (result) { + setDeviceConnectionState(State.WAITING_FOR_RECONNECT); + } + return result; } return false; } From 8970bbe04490b85ee669c0b5ca03224bf7d72760 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 28 May 2016 11:32:36 +0200 Subject: [PATCH 29/58] display device address in info menu (IP:PORT / MAC) --- .../nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java index 1e46d978..25275534 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java @@ -42,6 +42,7 @@ public class GBDevice implements Parcelable { public static final String EXTRA_DEVICE = "device"; private static final String DEVINFO_HW_VER = "HW: "; private static final String DEVINFO_FW_VER = "FW: "; + private static final String DEVINFO_ADDR = "ADDR: "; private final String mName; private final String mAddress; private final DeviceType mDeviceType; @@ -346,6 +347,9 @@ public class GBDevice implements Parcelable { if (mFirmwareVersion != null) { result.add(new GenericItem(DEVINFO_FW_VER, mFirmwareVersion)); } + if (mAddress != null) { + result.add(new GenericItem(DEVINFO_ADDR, mAddress)); + } Collections.sort(result); return result; } From a13cd9d951dc57363acb96795793ceea81e44290 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 29 May 2016 20:47:16 +0200 Subject: [PATCH 30/58] update changelog, bump version to 0.10.0 reasons for the bump are - new permissing - first contact with the timeline, although is is not very useful --- CHANGELOG.md | 6 ++++++ app/build.gradle | 4 ++-- app/src/main/res/xml/changelog_master.xml | 6 ++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb97f49e..ce28ad61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ ###Changelog +####Version 0.10.0 +* Pebble: option to send sunrise and sunset events to timeline +* Mi Band: BLE connection fixes +* Fixes for enabling logging at whithout restarting Gadgetbridge +* Re-enable device paring activity on Android 6 (BLE scanning needs the location preference) + ####Version 0.9.8 * Pebble: fix more reconnnect issues * Pebble: fix deep sleep not being detected with Firmware 3.12 when using Pebble Health diff --git a/app/build.gradle b/app/build.gradle index b52632f0..f6cd378f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,8 +18,8 @@ android { targetSdkVersion 23 // note: always bump BOTH versionCode and versionName! - versionName "0.9.8" - versionCode 52 + versionName "0.10.0" + versionCode 53 } buildTypes { release { diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml index 30022f53..31af521e 100644 --- a/app/src/main/res/xml/changelog_master.xml +++ b/app/src/main/res/xml/changelog_master.xml @@ -1,5 +1,11 @@ + + Pebble: option to send sunrise and sunset events to timeline + Mi Band: BLE connection fixes + Fixes for enabling logging at whithout restarting Gadgetbridge + Re-enable device paring activity on Android 6 (BLE scanning needs the location preference) + Pebble: fix more reconnnect issues Pebble: fix deep sleep not being detected with Firmware 3.12 when using Pebble Health From 2b88720f83170a70a35349ed15160e00a65dd242 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 29 May 2016 20:50:05 +0200 Subject: [PATCH 31/58] fix xml changelog and add missing entry --- CHANGELOG.md | 1 + app/src/main/res/xml/changelog_master.xml | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce28ad61..de9baf10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * Mi Band: BLE connection fixes * Fixes for enabling logging at whithout restarting Gadgetbridge * Re-enable device paring activity on Android 6 (BLE scanning needs the location preference) +* Display device address in device info ####Version 0.9.8 * Pebble: fix more reconnnect issues diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml index 31af521e..b2b47ee2 100644 --- a/app/src/main/res/xml/changelog_master.xml +++ b/app/src/main/res/xml/changelog_master.xml @@ -1,10 +1,11 @@ - Pebble: option to send sunrise and sunset events to timeline - Mi Band: BLE connection fixes - Fixes for enabling logging at whithout restarting Gadgetbridge - Re-enable device paring activity on Android 6 (BLE scanning needs the location preference) + Pebble: option to send sunrise and sunset events to timeline + Mi Band: BLE connection fixes + Fixes for enabling logging at whithout restarting Gadgetbridge + Re-enable device paring activity on Android 6 (BLE scanning needs the location preference) + Display device address in device info Pebble: fix more reconnnect issues From c9aad271dab2dcca91af4b740ffbffaabb99644c Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 29 May 2016 20:53:25 +0200 Subject: [PATCH 32/58] update translations from transifex (thanks!) --- app/src/main/res/values-de/strings.xml | 2 +- app/src/main/res/values-ja/strings.xml | 6 +++++- app/src/main/res/values-ko/strings.xml | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 1588000a..dbd00b3f 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -28,6 +28,7 @@ Einstellungen Allgemeine Einstellungen Verbinde, wenn Bluetooth eingeschaltet wird + Verbindungen automatisch wiederherstellen Bevorzugter Audioplayer Standard Datum und Zeit @@ -231,5 +232,4 @@ Firmware wurde nicht gesendet Herzfrequenz Herzfrequenz - Verbindungen automatisch wiederherstellen diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index f4013879..2eaf1852 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -28,6 +28,7 @@ 設定 一般設定 Bluetoothがオンになったときにデバイスに接続 + 自動的に再接続 お好みのオーディオプレイヤー デフォルト 日付と時刻 @@ -59,6 +60,10 @@ お好みのアクティビティ トラッカー 第三者のアンドロイドアップにアクセス権利を与える PebbleKitを使用してAndroidアプリ用の実験的なサポートを有効にします + 場所 + 場所の取得 + 緯度 + 経度 通知プロトコルを強制する このオプションを指定すると、ファームウェアのバージョンに応じて強制的に最新の通知プロトコルを使用します。何をしているかわかっている場合のみ有効にしてください! 未テストの機能を有効にする @@ -231,5 +236,4 @@ ファームウェアを送信しませんでした 心拍数 心拍数 - 自動的に再接続 diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 2afb4a02..b3735145 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -27,6 +27,7 @@ 설정 일반 설정 블루투스가 켜지면 기기에 접속하기 + 자동으로 재연결 선호하는 오디오 플레이어 기본값 날짜와 시간 @@ -224,5 +225,4 @@ 펌웨어가 전송되지 않음 심박수 심박수 - 자동으로 재연결 From 2e8d96e9954d31d5a4494c00bd7596b34b79a393 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 29 May 2016 21:29:27 +0200 Subject: [PATCH 33/58] add option to enable sunrise/sunset on the timeline Also fix a small type Aquire -> Acquire --- .../gadgetbridge/externalevents/AlarmReceiver.java | 4 ++++ app/src/main/res/values/strings.xml | 5 ++++- app/src/main/res/xml/preferences.xml | 6 ++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmReceiver.java index d510ffc0..edf0a386 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmReceiver.java @@ -36,6 +36,10 @@ public class AlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { + if (!GBApplication.getPrefs().getBoolean("send_sunrise_sunset", false)) { + LOG.info("won't send sunrise and sunset events (disabled in preferences)"); + return; + } LOG.info("will resend sunrise and sunset events"); final GregorianCalendar dateTimeTomorrow = new GregorianCalendar(); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0c17912d..53a01068 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -76,8 +76,11 @@ Allow 3rd Party Android App Access Enable experimental support for Android Apps using PebbleKit + Sunrise and Sunset + Send sunrise and sunset times based on the location to the pebble timeline + Location - Aquire Location + Acquire Location Latitude Longitude diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 43ff84f7..667f5184 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -215,6 +215,10 @@ android:key="pebble_activitytracker" android:title="@string/pref_title_pebble_activitytracker" android:summary="%s" /> + @@ -222,10 +226,12 @@ android:key="location_aquire" android:title="@string/pref_title_location_aquire"/> From af14fb4f905881ad64406c9de8805441a76ca9af Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 29 May 2016 21:40:56 +0200 Subject: [PATCH 34/58] limit max charaters to longiute and latitude to 7 --- app/src/main/res/xml/preferences.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 667f5184..39aac559 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -226,11 +226,13 @@ android:key="location_aquire" android:title="@string/pref_title_location_aquire"/> Date: Sun, 29 May 2016 21:44:43 +0200 Subject: [PATCH 35/58] make sure to only reconnect when device is in "waiting for reconnect state" --- .../gadgetbridge/externalevents/BluetoothConnectReceiver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothConnectReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothConnectReceiver.java index af973861..1fa0364f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothConnectReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothConnectReceiver.java @@ -32,7 +32,7 @@ public class BluetoothConnectReceiver extends BroadcastReceiver { GBDevice gbDevice = service.getGBDevice(); if (gbDevice != null) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); - if (device.getAddress().equals(gbDevice.getAddress())) { + if (device.getAddress().equals(gbDevice.getAddress()) && gbDevice.getState() == GBDevice.State.WAITING_FOR_RECONNECT) { LOG.info("will connect to " + gbDevice.getName()); GBApplication.deviceService().connect(); } else { From 33da6c29256ed1d389c7cdb1ff0ab8ca166e3232 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 29 May 2016 22:58:25 +0200 Subject: [PATCH 36/58] Pebble: make sure that "waiting for reconnect" state is set when initial connect fails --- .../devices/pebble/PebbleIoThread.java | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) 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 a14fb496..a67be4c0 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 @@ -161,6 +161,8 @@ public class PebbleIoThread extends GBDeviceIoThread { @Override protected boolean connect(String btDeviceAddress) { GBDevice.State originalState = gbDevice.getState(); + gbDevice.setState(GBDevice.State.CONNECTING); + gbDevice.sendDeviceUpdateIntent(getContext()); try { // contains only one ":"? then it is addr:port int firstColon = btDeviceAddress.indexOf(":"); @@ -188,6 +190,8 @@ public class PebbleIoThread extends GBDeviceIoThread { } catch (IOException e) { e.printStackTrace(); gbDevice.setState(originalState); + gbDevice.sendDeviceUpdateIntent(getContext()); + mInStream = null; mOutStream = null; mBtSocket = null; @@ -197,12 +201,8 @@ public class PebbleIoThread extends GBDeviceIoThread { mPebbleProtocol.setForceProtocol(prefs.getBoolean("pebble_force_protocol", false)); mIsConnected = true; - if (originalState == GBDevice.State.WAITING_FOR_RECONNECT) { - gbDevice.setState(GBDevice.State.INITIALIZED); - } else { - gbDevice.setState(GBDevice.State.CONNECTED); - write(mPebbleProtocol.encodeFirmwareVersionReq()); - } + write(mPebbleProtocol.encodeFirmwareVersionReq()); + gbDevice.setState(GBDevice.State.CONNECTED); gbDevice.sendDeviceUpdateIntent(getContext()); return true; @@ -210,15 +210,18 @@ public class PebbleIoThread extends GBDeviceIoThread { @Override public void run() { - gbDevice.setState(GBDevice.State.CONNECTING); - gbDevice.sendDeviceUpdateIntent(getContext()); - mIsConnected = connect(gbDevice.getAddress()); - enablePebbleKitReceiver(mIsConnected); - mQuit = !mIsConnected; // quit if not connected + if (!mIsConnected) { + if (GBApplication.getGBPrefs().getAutoReconnect()) { + gbDevice.setState(GBDevice.State.WAITING_FOR_RECONNECT); + gbDevice.sendDeviceUpdateIntent(getContext()); + } + return; + } byte[] buffer = new byte[8192]; - + enablePebbleKitReceiver(true); + mQuit = false; while (!mQuit) { try { if (mIsInstalling) { @@ -361,8 +364,6 @@ public class PebbleIoThread extends GBDeviceIoThread { mIsConnected = false; int reconnectAttempts = prefs.getInt("pebble_reconnect_attempts", 10); if (!mQuit && GBApplication.getGBPrefs().getAutoReconnect() && reconnectAttempts > 0) { - gbDevice.setState(GBDevice.State.CONNECTING); - gbDevice.sendDeviceUpdateIntent(getContext()); int delaySeconds = 1; while (reconnectAttempts-- > 0 && !mQuit && !mIsConnected) { LOG.info("Trying to reconnect (attempts left " + reconnectAttempts + ")"); From f2cbee39f1e63749ffedc8a20c7b0658d5fc837c Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 29 May 2016 23:02:00 +0200 Subject: [PATCH 37/58] update changelog again actually the last commit is responsible for the fix (even though it is not mentioned in the commit log) --- CHANGELOG.md | 1 + app/src/main/res/xml/changelog_master.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index de9baf10..f1563a43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ###Changelog ####Version 0.10.0 * Pebble: option to send sunrise and sunset events to timeline +* Pebble: fix datalog session not being registered after a reconnect * Mi Band: BLE connection fixes * Fixes for enabling logging at whithout restarting Gadgetbridge * Re-enable device paring activity on Android 6 (BLE scanning needs the location preference) diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml index b2b47ee2..3a4c8fb7 100644 --- a/app/src/main/res/xml/changelog_master.xml +++ b/app/src/main/res/xml/changelog_master.xml @@ -2,6 +2,7 @@ Pebble: option to send sunrise and sunset events to timeline + Pebble: fix datalog session not being registered after a reconnect Mi Band: BLE connection fixes Fixes for enabling logging at whithout restarting Gadgetbridge Re-enable device paring activity on Android 6 (BLE scanning needs the location preference) From b71597800a6e16152968fb25d2d6b4a960919f7f Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 29 May 2016 23:24:16 +0200 Subject: [PATCH 38/58] Pebble: set device to reconnecting state when actively reconnecting It makes it easier to watch connection attempts and the delay between them in control center. --- .../gadgetbridge/service/devices/pebble/PebbleIoThread.java | 3 +++ 1 file changed, 3 insertions(+) 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 a67be4c0..fcc19641 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 @@ -364,6 +364,9 @@ public class PebbleIoThread extends GBDeviceIoThread { mIsConnected = false; int reconnectAttempts = prefs.getInt("pebble_reconnect_attempts", 10); if (!mQuit && GBApplication.getGBPrefs().getAutoReconnect() && reconnectAttempts > 0) { + gbDevice.setState(GBDevice.State.WAITING_FOR_RECONNECT); + gbDevice.sendDeviceUpdateIntent(getContext()); + int delaySeconds = 1; while (reconnectAttempts-- > 0 && !mQuit && !mIsConnected) { LOG.info("Trying to reconnect (attempts left " + reconnectAttempts + ")"); From 0231e83ea3dc0243814e16b965a62ca5e48dc870 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Tue, 31 May 2016 00:07:24 +0200 Subject: [PATCH 39/58] try to fix duplicate/missing surise/sunset pins --- .../gadgetbridge/externalevents/AlarmReceiver.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmReceiver.java index edf0a386..bd121c6f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmReceiver.java @@ -43,6 +43,10 @@ public class AlarmReceiver extends BroadcastReceiver { LOG.info("will resend sunrise and sunset events"); final GregorianCalendar dateTimeTomorrow = new GregorianCalendar(); + dateTimeTomorrow.set(Calendar.HOUR, 0); + dateTimeTomorrow.set(Calendar.MINUTE, 0); + dateTimeTomorrow.set(Calendar.SECOND, 0); + dateTimeTomorrow.set(Calendar.MILLISECOND, 0); dateTimeTomorrow.add(GregorianCalendar.DAY_OF_MONTH, 1); /* From 42acb8915a071e09b6ab2f06fd3308e7c43cdb13 Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Tue, 31 May 2016 12:24:28 +0200 Subject: [PATCH 40/58] Pass the integer keys to pebble, even if they are not within the known app keys. Requested in #251 --- .../activities/ExternalPebbleJSActivity.java | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ExternalPebbleJSActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ExternalPebbleJSActivity.java index 7dba008b..a5181dcc 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ExternalPebbleJSActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ExternalPebbleJSActivity.java @@ -22,6 +22,7 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.util.Iterator; +import java.util.Scanner; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.GBApplication; @@ -138,19 +139,36 @@ public class ExternalPebbleJSActivity extends GBActivity { try { JSONObject in = new JSONObject(msg); JSONObject out = new JSONObject(); - String cur_key; + String inKey, outKey; + boolean passKey = false; for (Iterator key = in.keys(); key.hasNext(); ) { - cur_key = key.next(); - int pebbleAppIndex = knownKeys.optInt(cur_key); + passKey = false; + inKey = key.next(); + outKey = null; + int pebbleAppIndex = knownKeys.optInt(inKey); if (pebbleAppIndex != 0) { - Object obj = in.get(cur_key); + passKey = true; + outKey = String.valueOf(pebbleAppIndex); + + } else { + //do not discard integer keys (see https://developer.pebble.com/guides/communication/using-pebblekit-js/ ) + Scanner scanner = new Scanner(inKey); + if (scanner.hasNextInt() && inKey.equals("" + scanner.nextInt())) { + passKey = true; + outKey = inKey; + } + } + + if (passKey && outKey != null) { + Object obj = in.get(inKey); if (obj instanceof Boolean) { obj = ((Boolean) obj) ? "true" : "false"; } - out.put(String.valueOf(pebbleAppIndex), obj); + out.put(outKey, obj); } else { - GB.toast("Discarded key " + cur_key + ", not found in the local configuration.", Toast.LENGTH_SHORT, GB.WARN); + GB.toast("Discarded key " + inKey + ", not found in the local configuration and is not an integer key.", Toast.LENGTH_SHORT, GB.WARN); } + } LOG.info(out.toString()); GBApplication.deviceService().onAppConfiguration(appUuid, out.toString()); From a15d07858ec743e983d90816bab4e2bed27636ae Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Tue, 31 May 2016 13:03:15 +0200 Subject: [PATCH 41/58] Sunset/Sunrise: always use UTC timezone for calendar operations --- .../gadgetbridge/externalevents/AlarmReceiver.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmReceiver.java index bd121c6f..e9470d31 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmReceiver.java @@ -15,6 +15,7 @@ import org.slf4j.LoggerFactory; import java.util.Calendar; import java.util.GregorianCalendar; +import java.util.TimeZone; import nodomain.freeyourgadget.gadgetbridge.BuildConfig; import nodomain.freeyourgadget.gadgetbridge.GBApplication; @@ -42,7 +43,7 @@ public class AlarmReceiver extends BroadcastReceiver { } LOG.info("will resend sunrise and sunset events"); - final GregorianCalendar dateTimeTomorrow = new GregorianCalendar(); + final GregorianCalendar dateTimeTomorrow = new GregorianCalendar(TimeZone.getTimeZone("UTC")); dateTimeTomorrow.set(Calendar.HOUR, 0); dateTimeTomorrow.set(Calendar.MINUTE, 0); dateTimeTomorrow.set(Calendar.SECOND, 0); From 9da050c51ddfc26450e94bf23fe781a057fbb9f8 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Tue, 31 May 2016 13:05:55 +0200 Subject: [PATCH 42/58] update changelog --- CHANGELOG.md | 2 +- app/src/main/res/xml/changelog_master.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1563a43..c34cdbdc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ ###Changelog ####Version 0.10.0 * Pebble: option to send sunrise and sunset events to timeline -* Pebble: fix datalog session not being registered after a reconnect +* Pebble: fix problems with unknown app keys while configuring watchfaces * Mi Band: BLE connection fixes * Fixes for enabling logging at whithout restarting Gadgetbridge * Re-enable device paring activity on Android 6 (BLE scanning needs the location preference) diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml index 3a4c8fb7..a4918548 100644 --- a/app/src/main/res/xml/changelog_master.xml +++ b/app/src/main/res/xml/changelog_master.xml @@ -2,7 +2,7 @@ Pebble: option to send sunrise and sunset events to timeline - Pebble: fix datalog session not being registered after a reconnect + Pebble: fix problems with unknown app keys while configuring watchfaces Mi Band: BLE connection fixes Fixes for enabling logging at whithout restarting Gadgetbridge Re-enable device paring activity on Android 6 (BLE scanning needs the location preference) From 1dd0965ae118d803d788e8f79060805a90e6f49f Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Tue, 31 May 2016 13:07:11 +0200 Subject: [PATCH 43/58] update Italian traduzione from transifex --- app/src/main/res/values-it/strings.xml | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 3f1e3135..3f0dc77a 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -14,6 +14,7 @@ Gestione app Cancella + Cancella e rimuovi dalla cache Blocco notifiche @@ -27,11 +28,15 @@ Impostazioni Impostazioni globali Collegati al dispositivo quando il bluetooth viene acceso + Riconessione automatica Applicazione musicale preferita Default Data e ora Sincronizza l\'ora Sincronizza l\'orario al collegamento oppure quando viene cambiata l\'ora / il fuso orario in android. + Tema + Chiaro + Scuro Notifiche Ripetizioni Chiamate telefoniche @@ -41,6 +46,8 @@ Supporto per applicazioni che inviano le notifiche a Pebble usando Intents. Può essere usato per Conversations. Notifiche generiche … anche se lo schermo è acceso + Non disturbare + Non inviare notifiche nei periodi configurati come \"non disturbare\" sempre se lo schermo è spento mai @@ -53,6 +60,12 @@ Tracker delle attività preferito Consenti accesso ad altre applicazioni Attiva l\'accesso sperimentale ad applicazioni Android che usano PebbleKit + Alba e tramonto + Mostra gli orari calcolati per l\'alba e il tramonto sulla timeline + Posizione + Acquisisci posizione + Latitudin + Longitudin Forza protocollo delle notifiche Questa opzione forza l\'utilizzo della versione più recente delle notifiche in dipendenza del firmware del tuo dispositivo. ABILITALO SOLO SE SAI COSA STAI FACENDO! Abilita funzionalità non testate @@ -70,6 +83,9 @@ Notifica di prova creata da Gadgetbridge Bluetooth non supportato. Bluetooth disabilitato. + tocca il dispositivo connesso per gestire le App + tocca il dispositivo connesso per visualizzare l\'attività + tocca il dispositivo a cui connettersi Impossibile connettersi. Indirizzo BT non valido? Gadgetbridge in esecuzione installazione del binario %1$d/%2$d @@ -100,11 +116,13 @@ 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. Se non vedi il tuo dispositivo entro un paio di minuti, riprova dopo avere riavviato il dispositivo Android. 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 @@ -178,6 +196,8 @@ 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. + Utilizza la modalità a bassa latenza per gli aggiornamenti del firmware + Può essere utile quando l\'aggiornamento del firmware fallisce Storico dei passi Passi/minuto Passi totali @@ -193,6 +213,7 @@ Firmware non compatibile Questo firmware non è compatibile con il dispositivo Sveglie da riservare per i prossimi eventi del calendario + Utilizza il sensore del battito cardiaco per migliorare il riconoscimento del sonno in attesa di riconessione Re-installazion Informazioni sull\'utilizzatore @@ -211,4 +232,10 @@ Impostata sveglia per %1$02d:%2$02d HW: %1$s FW: %1$s + Errore durante la creazione della directory per i file di log: %1$s + HR: + Aggiornamento firmware in corso + Firmware non inviato + Battito cardiaco + Battito cardiaco From a9d74b52f88c88de9137d05f0e619cf2e3dcfbd6 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Tue, 31 May 2016 13:34:29 +0200 Subject: [PATCH 44/58] =?UTF-8?q?update=20German=20=C3=BCbersetzung?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/res/values-de/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index dbd00b3f..9d337f73 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -60,6 +60,12 @@ Bevorzugter Aktivitätstracker Erlaube Zugriff von anderen Android Apps Experimentelle Unterstützung für Android Apps, die PebbleKit benutzen + Sonnenauf- und -untergang + Sende Sonnenauf- und -untergangszeiten abhänging vom Standort auf die Pebble Timeline + Standort + Standort Bestimmen + Breitengrad + Längengrad Benachrichtigungsprotokoll erzwingen Diese Option erzwingt das neuste Benachrichtigungsprotokoll abhängig von der Firmwareversion. NUR EINSCHALTEN, WENN DU WEISST WAS DU TUST! Ungetestete Features freischalten From 19d7c035454c48f7a5ca16b7549d70002f816f3e Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Tue, 31 May 2016 14:18:45 +0200 Subject: [PATCH 45/58] Pebble: get rid of log spamming when changing applications (unhandled message) --- .../gadgetbridge/service/devices/pebble/PebbleProtocol.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 c6f00394..f44f8dba 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 @@ -1826,7 +1826,7 @@ public class PebbleProtocol extends GBDeviceProtocol { LOG.info(ENDPOINT_NAME + ": (cmd:" + command + ")" + uuid); break; } - return null; + return new GBDeviceEvent[]{null}; } private GBDeviceEvent decodeBlobDb(ByteBuffer buf) { From 9a106667d25b3f147c7ec366b0824e3ac4f86d82 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Tue, 31 May 2016 22:33:38 +0200 Subject: [PATCH 46/58] Setting the wear location appears to fail for amazfit #274 So as a test, disable that for amazfit. Let's see what happens next. --- .../service/devices/miband/MiBandSupport.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java index 444e59ee..527f704d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java @@ -361,10 +361,18 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { LOG.info("Attempting to set wear location..."); BluetoothGattCharacteristic characteristic = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT); if (characteristic != null) { - int location = MiBandCoordinator.getWearLocation(getDevice().getAddress()); - transaction.write(characteristic, new byte[]{ - MiBandService.COMMAND_SET_WEAR_LOCATION, - (byte) location + transaction.add(new ConditionalWriteAction() { + @Override + protected byte[] checkCondition() { + if (getDeviceInfo() != null && getDeviceInfo().isAmazFit()) { + return null; + } + int location = MiBandCoordinator.getWearLocation(getDevice().getAddress()); + return new byte[]{ + MiBandService.COMMAND_SET_WEAR_LOCATION, + (byte) location + }; + } }); } else { LOG.info("Unable to set Wear Location"); From 2e6536555b806225d7304fedbed730a01f5ff512 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Tue, 31 May 2016 22:56:22 +0200 Subject: [PATCH 47/58] Fix previous commit (compile!) --- .../gadgetbridge/service/devices/miband/MiBandSupport.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java index 527f704d..72d5bc8b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java @@ -361,7 +361,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { LOG.info("Attempting to set wear location..."); BluetoothGattCharacteristic characteristic = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT); if (characteristic != null) { - transaction.add(new ConditionalWriteAction() { + transaction.add(new ConditionalWriteAction(characteristic) { @Override protected byte[] checkCondition() { if (getDeviceInfo() != null && getDeviceInfo().isAmazFit()) { From df4ae49b7214d756418994cf8556564107b7b6db Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Tue, 31 May 2016 23:58:46 +0200 Subject: [PATCH 48/58] update Japanese translation from transifex (thanks!) --- app/src/main/res/values-ja/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 2eaf1852..ccdfc41a 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -60,6 +60,8 @@ お好みのアクティビティ トラッカー 第三者のアンドロイドアップにアクセス権利を与える PebbleKitを使用してAndroidアプリ用の実験的なサポートを有効にします + 日の出と日の入り + 場所に基づいて、Pebble のタイムラインに日の出・日の入りの時間を送ります 場所 場所の取得 緯度 From 60fc29cc4d2e280558216587b781bede4ac18f43 Mon Sep 17 00:00:00 2001 From: Szymon Tomasz Stefanek Date: Fri, 3 Jun 2016 04:43:12 +0200 Subject: [PATCH 49/58] Add support for shifting the device time by N hours to allow for sleep data gathering of shift workers --- .../gadgetbridge/devices/miband/MiBandConst.java | 1 + .../devices/miband/MiBandCoordinator.java | 5 +++++ .../devices/miband/MiBandDateConverter.java | 16 ++++++++++++++++ .../miband/MiBandPreferencesActivity.java | 2 ++ app/src/main/res/values-it/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + app/src/main/res/xml/miband_preferences.xml | 8 ++++++++ 7 files changed, 34 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandConst.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandConst.java index 8379d75b..2e4ceb34 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandConst.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandConst.java @@ -16,6 +16,7 @@ public final class MiBandConst { public static final String PREF_MIBAND_DONT_ACK_TRANSFER = "mi_dont_ack_transfer"; public static final String PREF_MIBAND_RESERVE_ALARM_FOR_CALENDAR = "mi_reserve_alarm_calendar"; public static final String PREF_MIBAND_USE_HR_FOR_SLEEP_DETECTION = "mi_hr_sleep_detection"; + public static final String PREF_MIBAND_DEVICE_TIME_OFFSET_HOURS = "mi_device_time_offset_hours"; public static final String ORIGIN_SMS = "sms"; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandCoordinator.java index c4e8e83c..505d3530 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandCoordinator.java @@ -140,6 +140,11 @@ public class MiBandCoordinator extends AbstractDeviceCoordinator { return location; } + public static int getDeviceTimeOffsetHours() throws IllegalArgumentException { + Prefs prefs = GBApplication.getPrefs(); + return prefs.getInt(MiBandConst.PREF_MIBAND_DEVICE_TIME_OFFSET_HOURS, 0); + } + public static boolean getHeartrateSleepSupport(String miBandAddress) throws IllegalArgumentException { Prefs prefs = GBApplication.getPrefs(); return prefs.getBoolean(MiBandConst.PREF_MIBAND_USE_HR_FOR_SLEEP_DETECTION, false); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandDateConverter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandDateConverter.java index 88a5e230..e41cf9be 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandDateConverter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandDateConverter.java @@ -40,6 +40,10 @@ public class MiBandDateConverter { value[offset + 4], value[offset + 5]); + int offsetInHours = MiBandCoordinator.getDeviceTimeOffsetHours(); + if(offsetInHours != 0) + timestamp.add(Calendar.HOUR_OF_DAY,-offsetInHours); + return timestamp; } @@ -53,6 +57,18 @@ public class MiBandDateConverter { * @return */ public static byte[] calendarToRawBytes(Calendar timestamp) { + + // The mi-band device currently records sleep + // only if it happens after 10pm and before 7am. + // The offset is used to trick the device to record sleep + // in non-standard hours. + // If you usually sleep, say, from 6am to 2pm, set the + // shift to -8, so at 6am the device thinks it's still 10pm + // of the day before. + int offsetInHours = MiBandCoordinator.getDeviceTimeOffsetHours(); + if(offsetInHours != 0) + timestamp.add(Calendar.HOUR_OF_DAY,offsetInHours); + return new byte[]{ (byte) (timestamp.get(Calendar.YEAR) - 2000), (byte) timestamp.get(Calendar.MONTH), diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPreferencesActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPreferencesActivity.java index e49ae1ab..7fb29ce9 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPreferencesActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPreferencesActivity.java @@ -16,6 +16,7 @@ import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.OR import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.ORIGIN_PEBBLEMSG; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.ORIGIN_SMS; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_ADDRESS; +import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_DEVICE_TIME_OFFSET_HOURS; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_DONT_ACK_TRANSFER; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_FITNESS_GOAL; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_RESERVE_ALARM_FOR_CALENDAR; @@ -62,6 +63,7 @@ public class MiBandPreferencesActivity extends AbstractSettingsActivity { PREF_MIBAND_ADDRESS, PREF_MIBAND_FITNESS_GOAL, PREF_MIBAND_RESERVE_ALARM_FOR_CALENDAR, + PREF_MIBAND_DEVICE_TIME_OFFSET_HOURS, getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_SMS), getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_INCOMING_CALL), getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_K9MAIL), diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 3f0dc77a..6ca7ee3b 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -238,4 +238,5 @@ Firmware non inviato Battito cardiaco Battito cardiaco + Offset orologio del dispositivo in ore (per l\'identificazione del sonno dei lavoratori a turni) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 53a01068..5d2a1453 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -237,6 +237,7 @@ This firmware is not compatible with the device Alarms to reserve for upcoming events Use Heartrate Sensor to improve sleep detection + Device time offset in hours (for detecting sleep of shift workers) waiting for reconnect Reinstall diff --git a/app/src/main/res/xml/miband_preferences.xml b/app/src/main/res/xml/miband_preferences.xml index 37e5d777..54888426 100644 --- a/app/src/main/res/xml/miband_preferences.xml +++ b/app/src/main/res/xml/miband_preferences.xml @@ -35,6 +35,14 @@ android:defaultValue="false" android:key="mi_hr_sleep_detection" android:title="@string/miband_prefs_hr_sleep_detection" /> + + + Date: Fri, 3 Jun 2016 10:56:11 +0200 Subject: [PATCH 50/58] Update README.md fix pebble wiki article Update README.md fix the link to the pebble wiki article --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9367cd44..14d11636 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ need to create an account and transmit any of your data to the vendor's servers. 2. Start Gadgetbridge, tap on the device you want to connect to 3. To test, choose "Debug" from the menu and play around -For more information read [this wiki article](https://github.com/Freeyourgadget/Gadgetbridge/wiki/Getting-Started-(Pebble)) +For more information read [this wiki article](https://github.com/Freeyourgadget/Gadgetbridge/wiki/Pebble-Getting-Started) ## Features (Mi Band) From edb7471e0c79146cb07ee39cf61f5bf797bcaf7f Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Sat, 4 Jun 2016 17:14:29 +0200 Subject: [PATCH 51/58] Added a paragraph about questions In the hope this helps for issue #319 --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 14d11636..6f888ce8 100644 --- a/README.md +++ b/README.md @@ -103,10 +103,14 @@ Contributions are welcome, be it feedback, bugreports, documentation, translatio 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. -Please do not use the issue tracker as a forum, do not ask for ETAs and read the issue conversation before posting. +Translations can be contributed via https://www.transifex.com/projects/p/gadgetbridge/resource/strings/ or manually. -Translations can be contributed via https://www.transifex.com/projects/p/gadgetbridge/resource/strings/ or -manually. +## Do you have further questions or feedback? + +Feel free to open an issue on our issue tracker, but please: +- do not use the issue tracker as a forum, do not ask for ETAs and read the issue conversation before posting +- use the search functionality to ensure that your questions wasn't already answered. Don't forget to check the **closed** issues as well! +- remember that this is a community project, people are contributing in their free time because they like doing so: don't take the fun away! Be kind and constructive. ## Having problems? From 968d15c8d8143af66f4a2e1d7af3d8e73f1daf79 Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Sat, 4 Jun 2016 18:21:49 +0200 Subject: [PATCH 52/58] Keep the pebble health data on the pebble watch if the activity provider is not pebble Health. This will nack all pebble health datalog messages. As mentioned in #322, this would allow to use multiple android device without secondary devices "sipping" the health data from the watch. --- .../DatalogSessionHealthOverlayData.java | 6 +++++- .../pebble/DatalogSessionHealthSleep.java | 7 ++++++- .../pebble/DatalogSessionHealthSteps.java | 6 +++++- .../pebble/DatalogSessionPebbleHealth.java | 20 +++++++++++++++++++ 4 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionPebbleHealth.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 index b7d42544..35d84be2 100644 --- 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 @@ -13,7 +13,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.pebble.HealthSampleProvider; import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind; import nodomain.freeyourgadget.gadgetbridge.util.GB; -class DatalogSessionHealthOverlayData extends DatalogSession { +class DatalogSessionHealthOverlayData extends DatalogSessionPebbleHealth { private static final Logger LOG = LoggerFactory.getLogger(DatalogSessionHealthOverlayData.class); @@ -26,6 +26,10 @@ class DatalogSessionHealthOverlayData extends DatalogSession { public boolean handleMessage(ByteBuffer datalogMessage, int length) { LOG.info("DATALOG " + taginfo + GB.hexdump(datalogMessage.array(), datalogMessage.position(), length)); + if (!isPebbleHealthEnabled()) { + return false; + } + int initialPosition = datalogMessage.position(); int beginOfRecordPosition; short recordVersion; //probably 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 2162f9d5..455e6459 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 @@ -13,7 +13,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.pebble.HealthSampleProvider; import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind; import nodomain.freeyourgadget.gadgetbridge.util.GB; -class DatalogSessionHealthSleep extends DatalogSession { +class DatalogSessionHealthSleep extends DatalogSessionPebbleHealth { private static final Logger LOG = LoggerFactory.getLogger(DatalogSessionHealthSleep.class); @@ -25,6 +25,11 @@ class DatalogSessionHealthSleep extends DatalogSession { @Override public boolean handleMessage(ByteBuffer datalogMessage, int length) { LOG.info("DATALOG " + taginfo + GB.hexdump(datalogMessage.array(), datalogMessage.position(), length)); + + if (!isPebbleHealthEnabled()) { + return false; + } + int initialPosition = datalogMessage.position(); int beginOfRecordPosition; short recordVersion; //probably diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSteps.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSteps.java index f89f0363..06151d7a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSteps.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSteps.java @@ -16,7 +16,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; import nodomain.freeyourgadget.gadgetbridge.util.GB; -public class DatalogSessionHealthSteps extends DatalogSession { +public class DatalogSessionHealthSteps extends DatalogSessionPebbleHealth { private static final Logger LOG = LoggerFactory.getLogger(DatalogSessionHealthSteps.class); @@ -29,6 +29,10 @@ public class DatalogSessionHealthSteps extends DatalogSession { public boolean handleMessage(ByteBuffer datalogMessage, int length) { LOG.info("DATALOG " + taginfo + GB.hexdump(datalogMessage.array(), datalogMessage.position(), length)); + if (!isPebbleHealthEnabled()) { + return false; + } + int timestamp; byte recordLength, recordNum; short recordVersion; //probably diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionPebbleHealth.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionPebbleHealth.java new file mode 100644 index 00000000..acbbe9f7 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionPebbleHealth.java @@ -0,0 +1,20 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble; + +import java.util.UUID; + +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; + +abstract class DatalogSessionPebbleHealth extends DatalogSession { + + DatalogSessionPebbleHealth(byte id, UUID uuid, int tag, byte itemType, short itemSize) { + super(id, uuid, tag, itemType, itemSize); + } + + protected boolean isPebbleHealthEnabled() { + Prefs prefs = GBApplication.getPrefs(); + int activityTracker = prefs.getInt("pebble_activitytracker", SampleProvider.PROVIDER_PEBBLE_HEALTH); + return (activityTracker == SampleProvider.PROVIDER_PEBBLE_HEALTH); + } +} \ No newline at end of file From 321707af8f3016c6aa0a602d644e71fa7fc1a0f4 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 4 Jun 2016 21:33:38 +0200 Subject: [PATCH 53/58] Pebble: ignore incoming misfit data if misfit is not set as the preferred activty tracker --- .../devices/pebble/AppMessageHandlerMisfit.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMisfit.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMisfit.java index daa0b020..f98452c9 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMisfit.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMisfit.java @@ -17,9 +17,11 @@ import nodomain.freeyourgadget.gadgetbridge.GBException; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; +import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; import nodomain.freeyourgadget.gadgetbridge.devices.pebble.MisfitSampleProvider; import nodomain.freeyourgadget.gadgetbridge.impl.GBActivitySample; import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class AppMessageHandlerMisfit extends AppMessageHandler { @@ -41,8 +43,19 @@ public class AppMessageHandlerMisfit extends AppMessageHandler { private final MisfitSampleProvider sampleProvider = new MisfitSampleProvider(); + private boolean isMisfitEnabled() { + Prefs prefs = GBApplication.getPrefs(); + int activityTracker = prefs.getInt("pebble_activitytracker", SampleProvider.PROVIDER_PEBBLE_HEALTH); + return (activityTracker == SampleProvider.PROVIDER_PEBBLE_MISFIT); + } + @Override public GBDeviceEvent[] handleMessage(ArrayList> pairs) { + + if (!isMisfitEnabled()) { + return new GBDeviceEvent[] {null}; + } + for (Pair pair : pairs) { switch (pair.first) { case KEY_INCOMING_DATA_BEGIN: From 9d3f3c57cd68408e453fbdd86ae26ed1ce1cea5a Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 4 Jun 2016 21:50:26 +0200 Subject: [PATCH 54/58] Pebble: make disabling of appmessage handlers more generic Also disable morpheuz handler if morpheuz is not the chosen activity tracker .... and bump reported version to 3.12 to match the latest pebble release --- .../service/devices/pebble/AppMessageHandler.java | 4 ++++ .../devices/pebble/AppMessageHandlerMisfit.java | 8 ++------ .../devices/pebble/AppMessageHandlerMorpheuz.java | 8 ++++++++ .../service/devices/pebble/PebbleProtocol.java | 14 +++++++++----- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandler.java index 26d55f73..710178f9 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandler.java @@ -17,6 +17,10 @@ public class AppMessageHandler { mPebbleProtocol = pebbleProtocol; } + public boolean isEnabled() { + return true; + } + public UUID getUUID() { return mUUID; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMisfit.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMisfit.java index f98452c9..2e33b4a5 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMisfit.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMisfit.java @@ -43,7 +43,8 @@ public class AppMessageHandlerMisfit extends AppMessageHandler { private final MisfitSampleProvider sampleProvider = new MisfitSampleProvider(); - private boolean isMisfitEnabled() { + @Override + public boolean isEnabled() { Prefs prefs = GBApplication.getPrefs(); int activityTracker = prefs.getInt("pebble_activitytracker", SampleProvider.PROVIDER_PEBBLE_HEALTH); return (activityTracker == SampleProvider.PROVIDER_PEBBLE_MISFIT); @@ -51,11 +52,6 @@ public class AppMessageHandlerMisfit extends AppMessageHandler { @Override public GBDeviceEvent[] handleMessage(ArrayList> pairs) { - - if (!isMisfitEnabled()) { - return new GBDeviceEvent[] {null}; - } - for (Pair pair : pairs) { switch (pair.first) { case KEY_INCOMING_DATA_BEGIN: diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMorpheuz.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMorpheuz.java index 3c6517d6..a9f1d9cb 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMorpheuz.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMorpheuz.java @@ -18,6 +18,7 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSleepMonitorResult; import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; import nodomain.freeyourgadget.gadgetbridge.devices.pebble.MorpheuzSampleProvider; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class AppMessageHandlerMorpheuz extends AppMessageHandler { @@ -56,6 +57,13 @@ public class AppMessageHandlerMorpheuz extends AppMessageHandler { return mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs); } + @Override + public boolean isEnabled() { + Prefs prefs = GBApplication.getPrefs(); + int activityTracker = prefs.getInt("pebble_activitytracker", SampleProvider.PROVIDER_PEBBLE_HEALTH); + return (activityTracker == SampleProvider.PROVIDER_PEBBLE_MORPHEUZ); + } + @Override public GBDeviceEvent[] handleMessage(ArrayList> pairs) { int ctrl_message = 0; 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 f44f8dba..6938c45c 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 @@ -1258,10 +1258,10 @@ public class PebbleProtocol extends GBDeviceProtocol { buf.put(PHONEVERSION_APPVERSION_MAGIC); buf.put((byte) 3); // major - buf.put((byte) 8); // minor - buf.put((byte) 1); // patch + buf.put((byte) 12); // minor + buf.put((byte) 0); // patch buf.order(ByteOrder.LITTLE_ENDIAN); - buf.putLong(0x00000000000000af); //flags + buf.putLong(0x00000000000001af); //flags return buf.array(); } @@ -2116,8 +2116,12 @@ public class PebbleProtocol extends GBDeviceProtocol { AppMessageHandler handler = mAppMessageHandlers.get(uuid); if (handler != null) { - ArrayList> dict = decodeDict(buf); - devEvts = handler.handleMessage(dict); + if (handler.isEnabled()) { + ArrayList> dict = decodeDict(buf); + devEvts = handler.handleMessage(dict); + } else { + devEvts = new GBDeviceEvent[]{null}; + } } else { try { devEvts = decodeDictToJSONAppMessage(uuid, buf); From 0fb664c1410b957cae028143eb152d72e35ec9f7 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 5 Jun 2016 14:33:09 +0200 Subject: [PATCH 55/58] allow to switch languages at runtime --- .../gadgetbridge/activities/GBActivity.java | 22 ++++++++++++++ app/src/main/res/values/arrays.xml | 30 +++++++++++++++++++ app/src/main/res/values/strings.xml | 2 ++ app/src/main/res/xml/preferences.xml | 7 +++++ 4 files changed, 61 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/GBActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/GBActivity.java index 39c972ea..dd9c2599 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/GBActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/GBActivity.java @@ -1,14 +1,33 @@ package nodomain.freeyourgadget.gadgetbridge.activities; +import android.content.res.Configuration; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; +import java.util.Locale; + import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class GBActivity extends AppCompatActivity { + private void setLanguage(String language) { + Locale locale; + if (language.equals("default")) { + locale = Locale.getDefault(); + } else { + locale = new Locale(language); + } + Configuration config = new Configuration(); + config.locale = locale; + + // FIXME: I have no idea what I am doing + getApplicationContext().getResources().updateConfiguration(config, getApplicationContext().getResources().getDisplayMetrics()); + getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics()); + } + @Override protected void onCreate(Bundle savedInstanceState) { if (GBApplication.isDarkThemeEnabled()) { @@ -17,6 +36,9 @@ public class GBActivity extends AppCompatActivity { setTheme(R.style.GadgetbridgeTheme); } + Prefs prefs = GBApplication.getPrefs(); + String language = prefs.getString("language", "default"); + setLanguage(language); super.onCreate(savedInstanceState); } } diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 937c29f2..8cf1b287 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -11,6 +11,36 @@ light dark + + System Default + Deutsch + English + Español + Français + Polski + Русский + Tiếng Việt + Türkçe + Українська + 한국어 + 日本語 + + + + default + de + en + es + fr + pl + ru + vi + tr + uk + ko + ja + + @string/always @string/when_screen_off diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 53a01068..99275ef8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -47,6 +47,8 @@ Light Dark + Language + Notifications Repetitions Phone Calls diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 39aac559..aa784331 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -23,6 +23,13 @@ android:entryValues="@array/pref_theme_values" android:defaultValue="@string/pref_theme_value_light" android:summary="%s" /> + Date: Sun, 5 Jun 2016 22:27:02 +0200 Subject: [PATCH 56/58] Basic support for Mi Band 2 #323, untested --- .../gadgetbridge/devices/miband/MiBandConst.java | 1 + .../gadgetbridge/service/devices/miband/DeviceInfo.java | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandConst.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandConst.java index 2e4ceb34..ca8b9e64 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandConst.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandConst.java @@ -28,6 +28,7 @@ public final class MiBandConst { public static final String MI_1A = "1A"; public static final String MI_1S = "1S"; public static final String MI_AMAZFIT = "Amazfit"; + public static final String MI_PRO = "2"; public static int getNotificationPrefIntValue(String pref, String origin, Prefs prefs, int defaultValue) { String key = getNotificationPrefKey(pref, origin); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/DeviceInfo.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/DeviceInfo.java index 3ba149df..c1c36258 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/DeviceInfo.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/DeviceInfo.java @@ -83,7 +83,7 @@ public class DeviceInfo extends AbstractInfo { } public boolean supportsHeartrate() { - return isMili1S() || (test1AHRMode && isMili1A()); + return isMiliPro() || isMili1S() || (test1AHRMode && isMili1A()); } @Override @@ -116,6 +116,10 @@ public class DeviceInfo extends AbstractInfo { return hwVersion == 6; } + public boolean isMiliPro() { + return hwVersion == 8 || (feature == 8 && appearance == 0); + } + public String getHwVersion() { if (isMili1()) { return MiBandConst.MI_1; @@ -129,6 +133,9 @@ public class DeviceInfo extends AbstractInfo { if (isAmazFit()) { return MiBandConst.MI_AMAZFIT; } + if (isMiliPro()) { + return MiBandConst.MI_PRO; + } return "?"; } } From cb4dcf9fa6c6001b6055838829431f48dbc2325d Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Sun, 5 Jun 2016 22:33:24 +0200 Subject: [PATCH 57/58] Disable LoggingTest, fixes travis failures --- .../freeyourgadget/gadgetbridge/test/LoggingTest.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/LoggingTest.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/LoggingTest.java index 3b68430a..0a3554bd 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/LoggingTest.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/LoggingTest.java @@ -6,6 +6,7 @@ import junit.framework.AssertionFailedError; import org.junit.After; import org.junit.BeforeClass; +import org.junit.Ignore; import org.junit.Test; import java.io.File; @@ -20,6 +21,12 @@ import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; +/** + * Tests dynamic enablement and disablement of file appenders. + * Test is currently disabled because logback-android does not work + * inside a plain junit test. + */ +@Ignore public class LoggingTest { @BeforeClass From 2b6ee419704357895abf7d3f411be6270f96eb83 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Sun, 5 Jun 2016 22:37:42 +0200 Subject: [PATCH 58/58] Add logging of heartrate values #318 --- .../gadgetbridge/service/devices/miband/MiBandSupport.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java index 72d5bc8b..fd00d02a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java @@ -853,6 +853,9 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { private void handleHeartrate(byte[] value) { if (value.length == 2 && value[0] == 6) { int hrValue = (value[1] & 0xff); + if (LOG.isDebugEnabled()) { + LOG.debug("heart rate: " + hrValue); + } Intent intent = new Intent(DeviceService.ACTION_HEARTRATE_MEASUREMENT) .putExtra(DeviceService.EXTRA_HEART_RATE_VALUE, hrValue) .putExtra(DeviceService.EXTRA_TIMESTAMP, System.currentTimeMillis());