From 2d3907b0f0cfca4d25682e7d09a889404a834936 Mon Sep 17 00:00:00 2001 From: ivanovlev Date: Fri, 27 Jan 2017 23:16:19 +0300 Subject: [PATCH 01/53] Fix issue #522 : Transliterate Caller Name --- .../gadgetbridge/impl/GBDeviceService.java | 34 +++++++++++++++- .../gadgetbridge/model/DeviceService.java | 1 + .../service/DeviceCommunicationService.java | 40 ++----------------- .../gadgetbridge/util/JavaExtensions.java | 15 +++++++ .../gadgetbridge/util/LanguageUtils.java | 23 +++++++++-- 5 files changed, 71 insertions(+), 42 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/JavaExtensions.java 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 6f217b5d1..c8f839267 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java @@ -3,7 +3,9 @@ package nodomain.freeyourgadget.gadgetbridge.impl; import android.app.Service; import android.content.Context; import android.content.Intent; +import android.database.Cursor; import android.net.Uri; +import android.provider.ContactsContract; import android.support.annotation.Nullable; import java.util.ArrayList; @@ -21,6 +23,8 @@ import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService; import nodomain.freeyourgadget.gadgetbridge.util.LanguageUtils; +import static nodomain.freeyourgadget.gadgetbridge.util.JavaExtensions.coalesce; + public class GBDeviceService implements DeviceService { protected final Context mContext; private final Class mServiceClass; @@ -32,6 +36,7 @@ public class GBDeviceService implements DeviceService { EXTRA_NOTIFICATION_BODY, EXTRA_NOTIFICATION_SOURCENAME, EXTRA_CALL_PHONENUMBER, + EXTRA_CALL_DISPLAYNAME, EXTRA_MUSIC_ARTIST, EXTRA_MUSIC_ALBUM, EXTRA_MUSIC_TRACK, @@ -111,7 +116,7 @@ public class GBDeviceService implements DeviceService { Intent intent = createIntent().setAction(ACTION_NOTIFICATION) .putExtra(EXTRA_NOTIFICATION_FLAGS, notificationSpec.flags) .putExtra(EXTRA_NOTIFICATION_PHONENUMBER, notificationSpec.phoneNumber) - .putExtra(EXTRA_NOTIFICATION_SENDER, notificationSpec.sender) + .putExtra(EXTRA_NOTIFICATION_SENDER, coalesce(notificationSpec.sender, getContactDisplayNameByNumber(notificationSpec.phoneNumber))) .putExtra(EXTRA_NOTIFICATION_SUBJECT, notificationSpec.subject) .putExtra(EXTRA_NOTIFICATION_TITLE, notificationSpec.title) .putExtra(EXTRA_NOTIFICATION_BODY, notificationSpec.body) @@ -144,9 +149,9 @@ public class GBDeviceService implements DeviceService { @Override public void onSetCallState(CallSpec callSpec) { - // name is actually ignored and provided by the service itself... Intent intent = createIntent().setAction(ACTION_CALLSTATE) .putExtra(EXTRA_CALL_PHONENUMBER, callSpec.number) + .putExtra(EXTRA_CALL_DISPLAYNAME, coalesce(callSpec.name, getContactDisplayNameByNumber(callSpec.number))) .putExtra(EXTRA_CALL_COMMAND, callSpec.command); invokeService(intent); } @@ -332,4 +337,29 @@ public class GBDeviceService implements DeviceService { .putExtra(EXTRA_WEATHER_TOMORROWCONDITIONCODE, weatherSpec.tomorrowConditionCode); invokeService(intent); } + + /** + * Returns contact DisplayName by call number + * @param number contact number + * @return contact DisplayName, if found it + */ + private String getContactDisplayNameByNumber(String number) { + Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)); + String name = number; + + if (number == null || number.equals("")) { + return name; + } + + try (Cursor contactLookup = mContext.getContentResolver().query(uri, null, null, null, null)) { + if (contactLookup != null && contactLookup.getCount() > 0) { + contactLookup.moveToNext(); + name = contactLookup.getString(contactLookup.getColumnIndex(ContactsContract.Data.DISPLAY_NAME)); + } + } catch (SecurityException e) { + // ignore, just return name below + } + + return name; + } } 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 a7be20f89..9177b077b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java @@ -60,6 +60,7 @@ public interface DeviceService extends EventHandler { String EXTRA_VIBRATION_INTENSITY = "vibration_intensity"; String EXTRA_CALL_COMMAND = "call_command"; String EXTRA_CALL_PHONENUMBER = "call_phonenumber"; + String EXTRA_CALL_DISPLAYNAME = "call_displayname"; String EXTRA_CANNEDMESSAGES = "cannedmessages"; String EXTRA_CANNEDMESSAGES_TYPE = "cannedmessages_type"; String EXTRA_MUSIC_ARTIST = "music_artist"; 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 336e0a927..1dd3934c3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -8,10 +8,8 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; -import android.database.Cursor; import android.net.Uri; import android.os.IBinder; -import android.provider.ContactsContract; import android.support.annotation.Nullable; import android.support.v4.content.LocalBroadcastManager; import android.widget.Toast; @@ -97,6 +95,7 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_CAL 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_DISPLAYNAME; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_CALL_PHONENUMBER; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_CANNEDMESSAGES; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_CANNEDMESSAGES_TYPE; @@ -332,8 +331,6 @@ public class DeviceCommunicationService extends Service implements SharedPrefere notificationSpec.flags = intent.getIntExtra(EXTRA_NOTIFICATION_FLAGS, 0); if (notificationSpec.type == NotificationType.GENERIC_SMS && notificationSpec.phoneNumber != null) { - notificationSpec.sender = getContactDisplayNameByNumber(notificationSpec.phoneNumber); - notificationSpec.id = mRandom.nextInt(); // FIXME: add this in external SMS Receiver? GBApplication.getIDSenderLookup().add(notificationSpec.id, notificationSpec.phoneNumber); } @@ -412,18 +409,10 @@ public class DeviceCommunicationService extends Service implements SharedPrefere break; } case ACTION_CALLSTATE: - int command = intent.getIntExtra(EXTRA_CALL_COMMAND, CallSpec.CALL_UNDEFINED); - - String phoneNumber = intent.getStringExtra(EXTRA_CALL_PHONENUMBER); - String callerName = null; - if (phoneNumber != null) { - callerName = getContactDisplayNameByNumber(phoneNumber); - } - CallSpec callSpec = new CallSpec(); - callSpec.command = command; - callSpec.number = phoneNumber; - callSpec.name = callerName; + callSpec.command = intent.getIntExtra(EXTRA_CALL_COMMAND, CallSpec.CALL_UNDEFINED); + callSpec.number = intent.getStringExtra(EXTRA_CALL_PHONENUMBER); + callSpec.name = intent.getStringExtra(EXTRA_CALL_DISPLAYNAME); mDeviceSupport.onSetCallState(callSpec); break; case ACTION_SETCANNEDMESSAGES: @@ -687,27 +676,6 @@ public class DeviceCommunicationService extends Service implements SharedPrefere return null; } - - private String getContactDisplayNameByNumber(String number) { - Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)); - String name = number; - - if (number == null || number.equals("")) { - return name; - } - - try (Cursor contactLookup = getContentResolver().query(uri, null, null, null, null)) { - if (contactLookup != null && contactLookup.getCount() > 0) { - contactLookup.moveToNext(); - name = contactLookup.getString(contactLookup.getColumnIndex(ContactsContract.Data.DISPLAY_NAME)); - } - } catch (SecurityException e) { - // ignore, just return name below - } - - return name; - } - @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (GBPrefs.AUTO_RECONNECT.equals(key)) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/JavaExtensions.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/JavaExtensions.java new file mode 100644 index 000000000..cd4b37cc2 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/JavaExtensions.java @@ -0,0 +1,15 @@ +package nodomain.freeyourgadget.gadgetbridge.util; + +public class JavaExtensions { + + /** + * Equivalent c# '??' operator + * @param one first value + * @param two second value + * @return first if not null, or second if first is null + */ + public static T coalesce(T one, T two) + { + return one != null ? one : two; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/LanguageUtils.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/LanguageUtils.java index 59d7aa817..a19d79d98 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/LanguageUtils.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/LanguageUtils.java @@ -23,13 +23,20 @@ public class LanguageUtils { } }; - //check transliterate option status + /** + * Checks the status of transliteration option + * @return true if transliterate option is On, and false, if Off or not exist + */ public static boolean transliterate() { return GBApplication.getPrefs().getBoolean("transliteration", false); } - //replace unsupported symbols to english analog + /** + * Replaces unsupported symbols to english + * @param txt input text + * @return transliterated text + */ public static String transliterate(String txt){ if (txt == null || txt.isEmpty()) { return txt; @@ -47,7 +54,11 @@ public class LanguageUtils { return flattenToAscii(message.toString()); } - //replace unsupported symbol to english analog text + /** + * Replaces unsupported symbol to english by {@code transliterateMap} + * @param c input char + * @return replacement text + */ private static String transliterate(char c){ char lowerChar = Character.toLowerCase(c); @@ -65,7 +76,11 @@ public class LanguageUtils { return String.valueOf(c); } - //convert diacritic + /** + * Converts the diacritics + * @param string input text + * @return converted text + */ private static String flattenToAscii(String string) { string = Normalizer.normalize(string, Normalizer.Form.NFD); return string.replaceAll("\\p{M}", ""); From 4c48b473ac41fb953b49134d2df7046ef4da1f4f Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Sat, 28 Jan 2017 22:17:41 +0100 Subject: [PATCH 02/53] Show device type in GBDeviceCandidate.toString() --- .../freeyourgadget/gadgetbridge/impl/GBDeviceCandidate.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceCandidate.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceCandidate.java index cec517a64..c6d561149 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceCandidate.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceCandidate.java @@ -127,7 +127,7 @@ public class GBDeviceCandidate implements Parcelable { deviceName = (String) method.invoke(device); } } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ignore) { - LOG.info("Could not get device alias for " + deviceName); + LOG.info("Could not get device alias for " + device.getName()); } if (deviceName == null || deviceName.length() == 0) { deviceName = device.getName(); @@ -167,6 +167,6 @@ public class GBDeviceCandidate implements Parcelable { @Override public String toString() { - return getName() + ": " + getMacAddress(); + return getName() + ": " + getMacAddress() + " (" + getDeviceType() + ")"; } } From 6c16b4fb15182080369a064482667017b7e8a2d9 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Sat, 28 Jan 2017 22:43:48 +0100 Subject: [PATCH 03/53] Updated initial array list size to reflect reality --- .../nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java index 9e2ebb41e..82791f62c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java @@ -166,7 +166,7 @@ public class DeviceHelper { } private List createCoordinators() { - List result = new ArrayList<>(2); + List result = new ArrayList<>(); result.add(new MiBand2Coordinator()); // Note: MiBand2 must come before MiBand because detection is hacky, atm result.add(new MiBandCoordinator()); result.add(new PebbleCoordinator()); From ec6a8b6743dcda64ac0b26c13ea5c30b3a8bf5a0 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Sat, 28 Jan 2017 22:52:22 +0100 Subject: [PATCH 04/53] MI: some more logging --- .../gadgetbridge/activities/DiscoveryActivity.java | 2 ++ .../devices/miband/MiBandPairingActivity.java | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) 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 8016041e2..e42f1bd85 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DiscoveryActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DiscoveryActivity.java @@ -293,6 +293,7 @@ public class DiscoveryActivity extends GBActivity implements AdapterView.OnItemC DeviceType deviceType = DeviceHelper.getInstance().getSupportedType(candidate); if (deviceType.isSupported()) { candidate.setDeviceType(deviceType); + LOG.info("Recognized supported device: " + candidate); int index = deviceCandidates.indexOf(candidate); if (index >= 0) { deviceCandidates.set(index, candidate); // replace @@ -506,6 +507,7 @@ public class DiscoveryActivity extends GBActivity implements AdapterView.OnItemC stopDiscovery(); DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(deviceCandidate); + LOG.info("Using device candidate " + deviceCandidate + " with coordinator: " + coordinator.getClass()); Class pairingActivity = coordinator.getPairingActivity(); if (pairingActivity != null) { Intent intent = new Intent(this, pairingActivity); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPairingActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPairingActivity.java index 9f825a7b2..1aae81608 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPairingActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPairingActivity.java @@ -33,7 +33,7 @@ public class MiBandPairingActivity extends GBActivity { private static final Logger LOG = LoggerFactory.getLogger(MiBandPairingActivity.class); private static final int REQ_CODE_USER_SETTINGS = 52; - private static final String STATE_MIBAND_ADDRESS = "mibandMacAddress"; + private static final String STATE_DEVICE_CANDIDATE = "stateDeviceCandidate"; private static final long DELAY_AFTER_BONDING = 1000; // 1s private TextView message; private boolean isPairing; @@ -103,7 +103,7 @@ public class MiBandPairingActivity extends GBActivity { Intent intent = getIntent(); deviceCandidate = intent.getParcelableExtra(DeviceCoordinator.EXTRA_DEVICE_CANDIDATE); if (deviceCandidate == null && savedInstanceState != null) { - deviceCandidate = savedInstanceState.getParcelable(STATE_MIBAND_ADDRESS); + deviceCandidate = savedInstanceState.getParcelable(STATE_DEVICE_CANDIDATE); } if (deviceCandidate == null) { Toast.makeText(this, getString(R.string.message_cannot_pair_no_mac), Toast.LENGTH_SHORT).show(); @@ -125,13 +125,13 @@ public class MiBandPairingActivity extends GBActivity { @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); - outState.putParcelable(STATE_MIBAND_ADDRESS, deviceCandidate); + outState.putParcelable(STATE_DEVICE_CANDIDATE, deviceCandidate); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); - deviceCandidate = savedInstanceState.getParcelable(STATE_MIBAND_ADDRESS); + deviceCandidate = savedInstanceState.getParcelable(STATE_DEVICE_CANDIDATE); } @Override From 2ae4497261b7c919e24b10087c3e1f94c45c80ed Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Sat, 28 Jan 2017 23:24:02 +0100 Subject: [PATCH 05/53] Mi2: the only reason I can see for detecting MiBandSupport for Mi2 Fixes #529, hopefully --- .../gadgetbridge/devices/miband/MiBand2Coordinator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBand2Coordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBand2Coordinator.java index 3ba9e543f..7fd8ad990 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBand2Coordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBand2Coordinator.java @@ -54,12 +54,12 @@ public class MiBand2Coordinator extends MiBandCoordinator { // and a heuristic for now try { BluetoothDevice device = candidate.getDevice(); - if (isHealthWearable(device)) { +// if (isHealthWearable(device)) { String name = device.getName(); if (name != null && name.equalsIgnoreCase(MiBandConst.MI_BAND2_NAME)) { return DeviceType.MIBAND2; } - } +// } } catch (Exception ex) { LOG.error("unable to check device support", ex); } From b157f84b83aae901d54ce4c8fd0e8cb236b1b6cb Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Sun, 29 Jan 2017 22:56:56 +0100 Subject: [PATCH 06/53] Log connection attempt when BT is turned on --- .../externalevents/BluetoothStateChangeReceiver.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothStateChangeReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothStateChangeReceiver.java index 0e639733f..0934d3d75 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothStateChangeReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothStateChangeReceiver.java @@ -6,11 +6,17 @@ import android.content.Context; import android.content.Intent; import android.support.v4.content.LocalBroadcastManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager; +import nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.PebbleIoThread; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class BluetoothStateChangeReceiver extends BroadcastReceiver { + private static final Logger LOG = LoggerFactory.getLogger(BluetoothStateChangeReceiver.class); + @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); @@ -26,6 +32,7 @@ public class BluetoothStateChangeReceiver extends BroadcastReceiver { return; } + LOG.info("Bluetooth turned on => connecting..."); GBApplication.deviceService().connect(); } else if (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1) == BluetoothAdapter.STATE_OFF) { GBApplication.quit(); From d030ad940024392beabeaaf7e01029d6738d4598 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Sun, 29 Jan 2017 23:06:40 +0100 Subject: [PATCH 07/53] Ups, remove accidental import from C&P --- .../externalevents/BluetoothStateChangeReceiver.java | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothStateChangeReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothStateChangeReceiver.java index 0934d3d75..4d5018cb7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothStateChangeReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothStateChangeReceiver.java @@ -11,7 +11,6 @@ import org.slf4j.LoggerFactory; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager; -import nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.PebbleIoThread; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class BluetoothStateChangeReceiver extends BroadcastReceiver { From f79e8f88339e559152baa7e6efa3f8703b6f5eda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joa=CC=83o=20Paulo=20Barraca?= Date: Mon, 30 Jan 2017 23:37:47 +0000 Subject: [PATCH 08/53] HPlus: Working alarms and small cleanup --- .../devices/hplus/HPlusConstants.java | 3 +- .../devices/hplus/HPlusCoordinator.java | 16 +--- .../devices/hplus/MakibesF68Coordinator.java | 6 ++ .../service/devices/hplus/HPlusSupport.java | 86 ++++--------------- 4 files changed, 25 insertions(+), 86 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusConstants.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusConstants.java index 73515ee7f..892b8c722 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusConstants.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusConstants.java @@ -38,7 +38,8 @@ public final class HPlusConstants { public static final byte[] CMD_SET_PREF_START = new byte[]{0x4f, 0x5a}; public static final byte[] CMD_SET_PREF_START1 = new byte[]{0x4d}; - public static final byte CMD_SET_ALARM = 0x4c; + //public static final byte CMD_SET_ALARM = 0x4c; Unknown + public static final byte CMD_SET_ALARM = 0x0c; public static final byte CMD_SET_LANGUAGE = 0x22; public static final byte CMD_SET_TIMEMODE = 0x47; public static final byte CMD_SET_UNITS = 0x48; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusCoordinator.java index 8495e6643..53f35e325 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusCoordinator.java @@ -138,19 +138,13 @@ public class HPlusCoordinator extends AbstractDeviceCoordinator { qb.where(HPlusHealthActivitySampleDao.Properties.DeviceId.eq(deviceId)).buildDelete().executeDeleteWithoutDetachingEntities(); } - public static int getFitnessGoal(String address) throws IllegalArgumentException { - ActivityUser activityUser = new ActivityUser(); - - return activityUser.getStepsGoal(); - } - public static byte getLanguage(String address) { return (byte) prefs.getInt(HPlusConstants.PREF_HPLUS_LANGUAGE + "_" + address, HPlusConstants.ARG_LANGUAGE_EN); } public static byte getTimeMode(String address) { - return (byte) prefs.getInt(HPlusConstants.PREF_HPLUS_TIMEMODE + "_" + address, 0); + return (byte) prefs.getInt(HPlusConstants.PREF_HPLUS_TIMEMODE + "_" + address, HPlusConstants.ARG_TIMEMODE_24H); } public static byte getUnit(String address) { @@ -212,14 +206,6 @@ public class HPlusCoordinator extends AbstractDeviceCoordinator { return (byte) (prefs.getInt(HPlusConstants.PREF_HPLUS_WRIST + "_" + address, 10) & 0xFF); } - public static boolean getSWAlertTime(String address) { - return prefs.getBoolean(HPlusConstants.PREF_HPLUS_SWALERT + "_" + address, false); - } - - public static int getAlertTime(String address) { - return prefs.getInt(HPlusConstants.PREF_HPLUS_ALERT_TIME + "_" + address, 0); - } - public static int getSITStartTime(String address) { return prefs.getInt(HPlusConstants.PREF_HPLUS_SIT_START_TIME + "_" + address, 0); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/MakibesF68Coordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/MakibesF68Coordinator.java index 1b1abe568..63cd71915 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/MakibesF68Coordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/MakibesF68Coordinator.java @@ -30,4 +30,10 @@ public class MakibesF68Coordinator extends HPlusCoordinator { public DeviceType getDeviceType() { return DeviceType.MAKIBESF68; } + + @Override + public String getManufacturer() { + return "Makibes"; + } + } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java index 4bf02c551..6daec55f3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java @@ -26,6 +26,7 @@ import java.util.GregorianCalendar; import java.util.List; import java.util.UUID; +import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.devices.hplus.HPlusConstants; import nodomain.freeyourgadget.gadgetbridge.devices.hplus.HPlusCoordinator; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; @@ -109,11 +110,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { //Initialize device sendUserInfo(builder); //Sync preferences - setSIT(builder); //Sync SIT Interval - setCurrentDate(builder); // Sync Current Date - setDayOfWeek(builder); - setCurrentTime(builder); // Sync Current Time - setLanguage(builder); + requestDeviceInfo(builder); @@ -141,68 +138,18 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { private HPlusSupport syncPreferences(TransactionBuilder transaction) { if(deviceType == DeviceType.HPLUS) { - byte gender = HPlusCoordinator.getUserGender(getDevice().getAddress()); - byte age = HPlusCoordinator.getUserAge(getDevice().getAddress()); - byte bodyHeight = HPlusCoordinator.getUserHeight(getDevice().getAddress()); - byte bodyWeight = HPlusCoordinator.getUserWeight(getDevice().getAddress()); - int goal = HPlusCoordinator.getGoal(getDevice().getAddress()); - byte displayTime = HPlusCoordinator.getScreenTime(getDevice().getAddress()); - byte country = HPlusCoordinator.getLanguage(getDevice().getAddress()); - byte social = HPlusCoordinator.getSocial(getDevice().getAddress()); // ?? - byte allDayHeart = HPlusCoordinator.getAllDayHR(getDevice().getAddress()); - byte wrist = HPlusCoordinator.getUserWrist(getDevice().getAddress()); - byte alertTimeHour = 0; - byte alertTimeMinute = 0; - - if (HPlusCoordinator.getSWAlertTime(getDevice().getAddress())) { - int t = HPlusCoordinator.getAlertTime(getDevice().getAddress()); - - alertTimeHour = (byte) ((t / 256) & 0xff); - alertTimeMinute = (byte) (t % 256); - } - - byte unit = HPlusCoordinator.getUnit(getDevice().getAddress()); - byte timemode = HPlusCoordinator.getTimeMode((getDevice().getAddress())); - - transaction.write(ctrlCharacteristic, new byte[]{ - HPlusConstants.CMD_SET_PREFS, - gender, - age, - bodyHeight, - bodyWeight, - 0, - 0, - (byte) ((goal / 256) & 0xff), - (byte) (goal % 256), - displayTime, - country, - 0, - social, - allDayHeart, - wrist, - 0, - alertTimeHour, - alertTimeMinute, - unit, - timemode - }); - - }else if(deviceType == DeviceType.MAKIBESF68){ - //Makibes doesn't support setting everything at once. - - setGender(transaction); - setAge(transaction); - setWeight(transaction); - setHeight(transaction); - setGoal(transaction); - setLanguage(transaction); - setScreenTime(transaction); - //setAlarm(transaction, t); - setUnit(transaction); - setTimeMode(transaction); + setSIT(transaction); //Sync SIT Interval } - + setGender(transaction); + setAge(transaction); + setWeight(transaction); + setHeight(transaction); + setGoal(transaction); + setLanguage(transaction); + setScreenTime(transaction); + setUnit(transaction); + setTimeMode(transaction); setAllDayHeart(transaction); return this; @@ -404,12 +351,8 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { private HPlusSupport setAlarm(TransactionBuilder transaction, Calendar t) { transaction.write(ctrlCharacteristic, new byte[]{HPlusConstants.CMD_SET_ALARM, - (byte) (t.get(Calendar.YEAR) / 256), - (byte) (t.get(Calendar.YEAR) % 256), - (byte) (t.get(Calendar.MONTH) + 1), (byte) t.get(Calendar.HOUR_OF_DAY), - (byte) t.get(Calendar.MINUTE), - (byte) t.get(Calendar.SECOND)}); + (byte) t.get(Calendar.MINUTE)}); return this; } @@ -497,8 +440,11 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { setAlarm(builder, t); builder.queue(getQueue()); + GB.toast(getContext(), getContext().getString(R.string.user_feedback_miband_set_alarms_ok), Toast.LENGTH_SHORT, GB.INFO); + return; //Only first alarm } + GB.toast(getContext(), getContext().getString(R.string.user_feedback_all_alarms_disabled), Toast.LENGTH_SHORT, GB.INFO); } From e08a9009787b35ac433602d2cc4b392e19a7caf5 Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Wed, 1 Feb 2017 22:55:40 +0100 Subject: [PATCH 09/53] Refactor the MusicPlaybackReceiver and related files Add actions to the filter (this should help with #536) Add "copy" constructors to MusicSpec and MusicStateSpec, and use those when receiving an updated intent, this way partial updates do not disrupt the local information. Iterate over incoming extra keys, explicitly check the incoming type and use only known type. This could help with #533 Possible problem: this code iterates over every key of the incoming bundle. --- .../externalevents/MusicPlaybackReceiver.java | 39 ++++++++++++------- .../gadgetbridge/model/MusicSpec.java | 13 +++++++ .../gadgetbridge/model/MusicStateSpec.java | 12 ++++++ .../service/DeviceCommunicationService.java | 3 +- 4 files changed, 53 insertions(+), 14 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 a47c8f4d3..9d6ee214a 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; @@ -26,17 +27,32 @@ public class MusicPlaybackReceiver extends BroadcastReceiver { value != null ? value.toString() : "null", value != null ? value.getClass().getName() : "no class")); } */ - MusicSpec musicSpec = new MusicSpec(); - musicSpec.artist = intent.getStringExtra("artist"); - musicSpec.album = intent.getStringExtra("album"); - if (intent.hasExtra("track")) { - musicSpec.track = intent.getStringExtra("track"); - } - else if (intent.hasExtra("title")) { - musicSpec.track = intent.getStringExtra("title"); - } + MusicSpec musicSpec = new MusicSpec(lastMusicSpec); + MusicStateSpec stateSpec = new MusicStateSpec(lastStatecSpec); - musicSpec.duration = intent.getIntExtra("duration", 0) / 1000; + Bundle incomingBundle = intent.getExtras(); + for (String key : incomingBundle.keySet()) { + Object incoming = incomingBundle.get(key); + if (incoming instanceof String && "artist".equals(key)) { + musicSpec.artist = (String) incoming; + } else if (incoming instanceof String && "album".equals(key)) { + musicSpec.album = (String) incoming; + } else if (incoming instanceof String && "track".equals(key)) { + musicSpec.track = (String) incoming; + } else if (incoming instanceof String && "title".equals(key) && musicSpec.track == null) { + musicSpec.track = (String) incoming; + } else if (incoming instanceof Integer && "duration".equals(key)) { + musicSpec.duration = (Integer) incoming / 1000; + } else if (incoming instanceof Long && "duration".equals(key)) { + musicSpec.duration = ((Long) incoming).intValue() / 1000; + } else if (incoming instanceof Integer && "position".equals(key)) { + stateSpec.position = (Integer) incoming / 1000; + } else if (incoming instanceof Long && "position".equals(key)) { + stateSpec.position = ((Long) incoming).intValue() / 1000; + } else if (incoming instanceof Boolean && "playing".equals(key)) { + stateSpec.state = (byte) (((Boolean) incoming) ? MusicStateSpec.STATE_PLAYING : MusicStateSpec.STATE_PAUSED); + } + } if (!lastMusicSpec.equals(musicSpec)) { lastMusicSpec = musicSpec; @@ -47,9 +63,6 @@ public class MusicPlaybackReceiver extends BroadcastReceiver { } if (intent.hasExtra("position") && intent.hasExtra("playing")) { - MusicStateSpec stateSpec = new MusicStateSpec(); - stateSpec.position = intent.getIntExtra("position", 0) / 1000; - stateSpec.state = (byte) (intent.getBooleanExtra("playing", true) ? MusicStateSpec.STATE_PLAYING : MusicStateSpec.STATE_PAUSED); if (!lastStatecSpec.equals(stateSpec)) { LOG.info("Update Music State: state=" + stateSpec.state + ", position= " + stateSpec.position); GBApplication.deviceService().onSetMusicState(stateSpec); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicSpec.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicSpec.java index aa9f67ca9..9866a935d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicSpec.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicSpec.java @@ -17,6 +17,19 @@ public class MusicSpec { public int trackCount; public int trackNr; + public MusicSpec() { + + } + + public MusicSpec(MusicSpec old) { + this.duration = old.duration; + this.trackCount = old.trackCount; + this.trackNr = old.trackNr; + this.track = old.track; + this.album = old.album; + this.artist = old.artist; + } + @Override public boolean equals(Object obj) { if (obj == this) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicStateSpec.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicStateSpec.java index fb15948d7..f9d070eb8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicStateSpec.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicStateSpec.java @@ -15,6 +15,18 @@ public class MusicStateSpec { public byte shuffle; public byte repeat; + public MusicStateSpec() { + + } + + public MusicStateSpec(MusicStateSpec old) { + this.state = old.state; + this.position = old.position; + this.playRate = old.playRate; + this.shuffle = old.shuffle; + this.repeat = old.repeat; + } + @Override public boolean equals(Object obj) { if (obj == this) { 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 1dd3934c3..277e2223a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -599,8 +599,9 @@ public class DeviceCommunicationService extends Service implements SharedPrefere mMusicPlaybackReceiver = new MusicPlaybackReceiver(); IntentFilter filter = new IntentFilter(); filter.addAction("com.android.music.metachanged"); + filter.addAction("com.android.music.playstatechanged"); + filter.addAction("com.android.music.playbackcomplete"); filter.addAction("net.sourceforge.subsonic.androidapp.EVENT_META_CHANGED"); - //filter.addAction("com.android.music.playstatechanged"); registerReceiver(mMusicPlaybackReceiver, filter); } if (mTimeChangeReceiver == null) { From 3fcf4938b97d55a8d283cf83e5b7c15680b4d66f Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Wed, 1 Feb 2017 23:10:23 +0100 Subject: [PATCH 10/53] Changelog for Music receiver refactoring --- CHANGELOG.md | 3 +++ app/src/main/res/xml/changelog_master.xml | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d756f9d8..900f61ad9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ###Changelog +####Version next +* Better integration with android music players + ####Version 0.17.3 * HPlus: Improve display of new messages and phone calls * HPlus: Fix bug related to steps and heart rate diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml index 2d8613556..5187fa13e 100644 --- a/app/src/main/res/xml/changelog_master.xml +++ b/app/src/main/res/xml/changelog_master.xml @@ -1,5 +1,9 @@ + + Better integration with android music players + + HPlus: Improve display of new messages and phone calls HPlus: Fix bug related to steps and heart rate From 006a23dfe8e42427757bc1734dac709a2f18832d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joa=CC=83o=20Paulo=20Barraca?= Date: Fri, 3 Feb 2017 19:30:59 +0000 Subject: [PATCH 11/53] HPlus: Fix time sync and Time format (12/24) --- .../gadgetbridge/devices/hplus/HPlusConstants.java | 4 ++-- .../gadgetbridge/service/devices/hplus/HPlusSupport.java | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusConstants.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusConstants.java index 892b8c722..2fe12b9dc 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusConstants.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusConstants.java @@ -18,8 +18,8 @@ public final class HPlusConstants { public static final byte ARG_LANGUAGE_CN = 1; public static final byte ARG_LANGUAGE_EN = 2; - public static final byte ARG_TIMEMODE_24H = 0; - public static final byte ARG_TIMEMODE_12H = 1; + public static final byte ARG_TIMEMODE_24H = 1; + public static final byte ARG_TIMEMODE_12H = 0; public static final byte ARG_UNIT_METRIC = 0; public static final byte ARG_UNIT_IMPERIAL = 1; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java index 6daec55f3..6ddffffb8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java @@ -141,15 +141,20 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { setSIT(transaction); //Sync SIT Interval } + setCurrentDate(transaction); + setCurrentTime(transaction); + setDayOfWeek(transaction); + setTimeMode(transaction); + setGender(transaction); setAge(transaction); setWeight(transaction); setHeight(transaction); + setGoal(transaction); setLanguage(transaction); setScreenTime(transaction); setUnit(transaction); - setTimeMode(transaction); setAllDayHeart(transaction); return this; From fd61dc602fcda0a2dd712f240ebb3bd639bd46a5 Mon Sep 17 00:00:00 2001 From: ivanovlev Date: Sat, 4 Feb 2017 09:53:07 +0300 Subject: [PATCH 12/53] Transliteration: capitalized just the first letter in the replacement text --- .../freeyourgadget/gadgetbridge/util/LanguageUtils.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/LanguageUtils.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/LanguageUtils.java index a19d79d98..78ae076c3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/LanguageUtils.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/LanguageUtils.java @@ -1,5 +1,7 @@ package nodomain.freeyourgadget.gadgetbridge.util; +import org.apache.commons.lang3.text.WordUtils; + import java.util.HashMap; import java.util.Map; import java.text.Normalizer; @@ -67,7 +69,7 @@ public class LanguageUtils { if (lowerChar != c) { - return replace.toUpperCase(); + return WordUtils.capitalize(replace); } return replace; From b894c018223628fe89cd79f79c0ee93444965b7a Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Sun, 5 Feb 2017 15:13:26 +0100 Subject: [PATCH 13/53] Make the media notification receiver more robust. Sometimes the media notification does not contain the expected components, hence the code covered by the try/catch has been adjusted. This was reported in #533 for VLC. In the future the whole media handling will probably be refactored. --- .../externalevents/NotificationListener.java | 84 +++++++++---------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java index 745b0b8f7..e602dfc00 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java @@ -355,51 +355,51 @@ public class NotificationListener extends NotificationListenerService { MediaController c; try { c = new MediaController(getApplicationContext(), (MediaSession.Token) extras.get(Notification.EXTRA_MEDIA_SESSION)); + + PlaybackState s = c.getPlaybackState(); + stateSpec.position = (int) (s.getPosition() / 1000); + stateSpec.playRate = Math.round(100 * s.getPlaybackSpeed()); + stateSpec.repeat = 1; + stateSpec.shuffle = 1; + switch (s.getState()) { + case PlaybackState.STATE_PLAYING: + stateSpec.state = MusicStateSpec.STATE_PLAYING; + break; + case PlaybackState.STATE_STOPPED: + stateSpec.state = MusicStateSpec.STATE_STOPPED; + break; + case PlaybackState.STATE_PAUSED: + stateSpec.state = MusicStateSpec.STATE_PAUSED; + break; + default: + stateSpec.state = MusicStateSpec.STATE_UNKNOWN; + break; + } + + MediaMetadata d = c.getMetadata(); + if (d == null) + return false; + if (d.containsKey(MediaMetadata.METADATA_KEY_ARTIST)) + musicSpec.artist = d.getString(MediaMetadata.METADATA_KEY_ARTIST); + if (d.containsKey(MediaMetadata.METADATA_KEY_ALBUM)) + musicSpec.album = d.getString(MediaMetadata.METADATA_KEY_ALBUM); + if (d.containsKey(MediaMetadata.METADATA_KEY_TITLE)) + musicSpec.track = d.getString(MediaMetadata.METADATA_KEY_TITLE); + if (d.containsKey(MediaMetadata.METADATA_KEY_DURATION)) + musicSpec.duration = (int) d.getLong(MediaMetadata.METADATA_KEY_DURATION) / 1000; + if (d.containsKey(MediaMetadata.METADATA_KEY_NUM_TRACKS)) + musicSpec.trackCount = (int) d.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS); + if (d.containsKey(MediaMetadata.METADATA_KEY_TRACK_NUMBER)) + musicSpec.trackNr = (int) d.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER); + + // finally, tell the device about it + GBApplication.deviceService().onSetMusicInfo(musicSpec); + GBApplication.deviceService().onSetMusicState(stateSpec); + + return true; } catch (NullPointerException e) { return false; } - - PlaybackState s = c.getPlaybackState(); - stateSpec.position = (int) (s.getPosition() / 1000); - stateSpec.playRate = Math.round(100 * s.getPlaybackSpeed()); - stateSpec.repeat = 1; - stateSpec.shuffle = 1; - switch (s.getState()) { - case PlaybackState.STATE_PLAYING: - stateSpec.state = MusicStateSpec.STATE_PLAYING; - break; - case PlaybackState.STATE_STOPPED: - stateSpec.state = MusicStateSpec.STATE_STOPPED; - break; - case PlaybackState.STATE_PAUSED: - stateSpec.state = MusicStateSpec.STATE_PAUSED; - break; - default: - stateSpec.state = MusicStateSpec.STATE_UNKNOWN; - break; - } - - MediaMetadata d = c.getMetadata(); - if (d == null) - return false; - if (d.containsKey(MediaMetadata.METADATA_KEY_ARTIST)) - musicSpec.artist = d.getString(MediaMetadata.METADATA_KEY_ARTIST); - if (d.containsKey(MediaMetadata.METADATA_KEY_ALBUM)) - musicSpec.album = d.getString(MediaMetadata.METADATA_KEY_ALBUM); - if (d.containsKey(MediaMetadata.METADATA_KEY_TITLE)) - musicSpec.track = d.getString(MediaMetadata.METADATA_KEY_TITLE); - if (d.containsKey(MediaMetadata.METADATA_KEY_DURATION)) - musicSpec.duration = (int)d.getLong(MediaMetadata.METADATA_KEY_DURATION) / 1000; - if (d.containsKey(MediaMetadata.METADATA_KEY_NUM_TRACKS)) - musicSpec.trackCount = (int)d.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS); - if (d.containsKey(MediaMetadata.METADATA_KEY_TRACK_NUMBER)) - musicSpec.trackNr = (int)d.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER); - - // finally, tell the device about it - GBApplication.deviceService().onSetMusicInfo(musicSpec); - GBApplication.deviceService().onSetMusicState(stateSpec); - - return true; } @Override From dccd6c1b0642d602d81aea25e32209cbc05e38f2 Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Sun, 5 Feb 2017 16:37:59 +0100 Subject: [PATCH 14/53] Pebble: implement privacy modes The user can choose whether to completely hide the notification text or push it off-screen. This also effects the incoming call notification. Fixes #370 --- CHANGELOG.md | 1 + .../service/devices/pebble/PebbleSupport.java | 19 +++++++++++++++++++ app/src/main/res/values/arrays.xml | 13 +++++++++++++ app/src/main/res/values/strings.xml | 5 +++++ app/src/main/res/values/values.xml | 4 ++++ app/src/main/res/xml/changelog_master.xml | 1 + app/src/main/res/xml/preferences.xml | 7 +++++++ 7 files changed, 50 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 900f61ad9..66037df9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ####Version next * Better integration with android music players +* Pebble: Implement notification and incoming call privacy modes ####Version 0.17.3 * HPlus: Improve display of new messages and phone calls 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 122f6da59..e4f59e852 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.Iterator; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec; @@ -113,6 +114,16 @@ public class PebbleSupport extends AbstractSerialDeviceSupport { @Override public void onNotification(NotificationSpec notificationSpec) { + String currentPrivacyMode = GBApplication.getPrefs().getString("pebble_pref_privacy_mode", getContext().getString(R.string.p_pebble_privacy_mode_off)); + if (getContext().getString(R.string.p_pebble_privacy_mode_complete).equals(currentPrivacyMode)) { + notificationSpec.body = null; + notificationSpec.sender = null; + notificationSpec.subject = null; + notificationSpec.title = null; + notificationSpec.phoneNumber = null; + } else if (getContext().getString(R.string.p_pebble_privacy_mode_content).equals(currentPrivacyMode)) { + notificationSpec.sender = "\n\n\n\n\n" + notificationSpec.sender; + } if (reconnect()) { super.onNotification(notificationSpec); } @@ -120,6 +131,14 @@ public class PebbleSupport extends AbstractSerialDeviceSupport { @Override public void onSetCallState(CallSpec callSpec) { + String currentPrivacyMode = GBApplication.getPrefs().getString("pebble_pref_privacy_mode", getContext().getString(R.string.p_pebble_privacy_mode_off)); + if (getContext().getString(R.string.p_pebble_privacy_mode_complete).equals(currentPrivacyMode)) { + callSpec.name = null; + callSpec.number = null; + } else if (getContext().getString(R.string.p_pebble_privacy_mode_content).equals(currentPrivacyMode)) { + callSpec.name = null; + } + if (reconnect()) { if ((callSpec.command != CallSpec.CALL_OUTGOING) || GBApplication.getPrefs().getBoolean("pebble_enable_outgoing_call", true)) { super.onSetCallState(callSpec); diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index e2aff8f58..db5a79516 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -113,6 +113,19 @@ 3 1 + + + @string/pref_pebble_privacy_mode_off + @string/pref_pebble_privacy_mode_content + @string/pref_pebble_privacy_mode_complete + + + + @string/p_pebble_privacy_mode_off + @string/p_pebble_privacy_mode_content + @string/p_pebble_privacy_mode_complete + + @string/dateformat_time @string/dateformat_date_time diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 88226d4ce..efc636b99 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -119,6 +119,11 @@ Autoremove dismissed Notifications Notifications are automatically removed from the Pebble when dismissed from the Android device + Privacy mode + Normal notifications and incoming calls display. + Shift the notification text off-screen. Hide the caller\'s name on incoming calls. + Show only the notification icon. Hide the caller\'s name and number on incoming calls. + Location Acquire Location Latitude diff --git a/app/src/main/res/values/values.xml b/app/src/main/res/values/values.xml index df90cb5b7..84c560b36 100644 --- a/app/src/main/res/values/values.xml +++ b/app/src/main/res/values/values.xml @@ -12,4 +12,8 @@ dateformat_time dateformat_datetime + off + content + complete + diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml index 5187fa13e..887dd32e5 100644 --- a/app/src/main/res/xml/changelog_master.xml +++ b/app/src/main/res/xml/changelog_master.xml @@ -2,6 +2,7 @@ Better integration with android music players + Pebble: Implement notification and incoming call privacy modes diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 39c7d9ed9..9f262213b 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -184,6 +184,13 @@ android:key="autoremove_notifications" android:summary="@string/pref_summary_autoremove_notifications" android:title="@string/pref_title_autoremove_notifications" /> + Date: Sun, 5 Feb 2017 17:21:04 +0100 Subject: [PATCH 15/53] Pebble: support weather for Obsidian Ref: #482 --- CHANGELOG.md | 1 + .../pebble/AppMessageHandlerObsidian.java | 160 ++++++++++++++++++ .../devices/pebble/PebbleProtocol.java | 2 + app/src/main/res/xml/changelog_master.xml | 2 +- 4 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerObsidian.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 66037df9a..91237f346 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ####Version next * Better integration with android music players * Pebble: Implement notification and incoming call privacy modes +* Pebble: Support weather for Obisdian watchface ####Version 0.17.3 * HPlus: Improve display of new messages and phone calls diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerObsidian.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerObsidian.java new file mode 100644 index 000000000..0f5f783b0 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerObsidian.java @@ -0,0 +1,160 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble; + +import android.util.Pair; +import android.widget.Toast; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.UUID; + +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; +import nodomain.freeyourgadget.gadgetbridge.model.Weather; +import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; +import nodomain.freeyourgadget.gadgetbridge.util.GB; + +class AppMessageHandlerObsidian extends AppMessageHandler { + + /* + "appKeys": { + "CONFIG_WEATHER_REFRESH": 35, + "CONFIG_WEATHER_UNIT_LOCAL": 31, + "MSG_KEY_WEATHER_TEMP": 100, + + "CONFIG_WEATHER_EXPIRATION": 36, + "MSG_KEY_FETCH_WEATHER": 102, + "MSG_KEY_WEATHER_ICON": 101, + "MSG_KEY_WEATHER_FAILED": 104, + "CONFIG_WEATHER_MODE_LOCAL": 30, + "CONFIG_WEATHER_APIKEY_LOCAL": 33, + "CONFIG_WEATHER_LOCAL": 28, + "CONFIG_COLOR_WEATHER": 29, + "CONFIG_WEATHER_LOCATION_LOCAL": 34, + "CONFIG_WEATHER_SOURCE_LOCAL": 32 + } + */ + + + private static final String ICON_01d = "a"; //night icons are just uppercase + private static final String ICON_02d = "b"; + private static final String ICON_03d = "c"; + private static final String ICON_04d = "d"; + private static final String ICON_09d = "e"; + private static final String ICON_10d = "f"; + private static final String ICON_11d = "g"; + private static final String ICON_13d = "h"; + private static final String ICON_50d = "i"; + + + AppMessageHandlerObsidian(UUID uuid, PebbleProtocol pebbleProtocol) { + super(uuid, pebbleProtocol); + messageKeys = new HashMap<>(); + try { + JSONObject appKeys = getAppKeys(); + Iterator appKeysIterator = appKeys.keys(); + while (appKeysIterator.hasNext()) { + String current = appKeysIterator.next(); + switch (current) { + case "CONFIG_WEATHER_REFRESH": + case "CONFIG_WEATHER_UNIT_LOCAL": + case "MSG_KEY_WEATHER_TEMP": + case "MSG_KEY_WEATHER_ICON": + messageKeys.put(current, appKeys.getInt(current)); + break; + } + } + } catch (JSONException e) { + GB.toast("There was an error accessing the timestyle watchface configuration.", Toast.LENGTH_LONG, GB.ERROR); + } catch (IOException ignore) { + } + } + + private String getIconForConditionCode(int conditionCode, boolean isNight) { + + int generalCondition = conditionCode / 100; + String iconToLoad; + // determine the correct icon + switch (generalCondition) { + case 2: //thunderstorm + iconToLoad = ICON_11d; + break; + case 3: //drizzle + iconToLoad = ICON_09d; + break; + case 5: //rain + if (conditionCode == 500) { + iconToLoad = ICON_09d; + } else if (conditionCode < 505) { + iconToLoad = ICON_10d; + } else if (conditionCode == 511) { + iconToLoad = ICON_10d; + } else { + iconToLoad = ICON_09d; + } + break; + case 6: //snow + if (conditionCode == 600 || conditionCode == 620) { + iconToLoad = ICON_13d; + } else if (conditionCode > 610 && conditionCode < 620) { + iconToLoad = ICON_13d; + } else { + iconToLoad = ICON_13d; + } + break; + case 7: // fog, dust, etc + iconToLoad = ICON_03d; + break; + case 8: // clouds + if (conditionCode == 800) { + iconToLoad = ICON_01d; + } else if (conditionCode < 803) { + iconToLoad = ICON_02d; + } else { + iconToLoad = ICON_04d; + } + break; + default: + iconToLoad = ICON_02d; + break; + } + + return (!isNight) ? iconToLoad : iconToLoad.toUpperCase(); + } + + private byte[] encodeObisdianWeather(WeatherSpec weatherSpec) { + + if (weatherSpec == null) { + return null; + } + + ArrayList> pairs = new ArrayList<>(); + boolean isNight = false; //TODO: use the night icons when night + pairs.add(new Pair<>(messageKeys.get("CONFIG_WEATHER_REFRESH"), (Object) 60)); + pairs.add(new Pair<>(messageKeys.get("CONFIG_WEATHER_UNIT_LOCAL"), (Object) 1)); //celsius + pairs.add(new Pair<>(messageKeys.get("MSG_KEY_WEATHER_ICON"), (Object) getIconForConditionCode(weatherSpec.currentConditionCode, isNight))); //celsius + pairs.add(new Pair<>(messageKeys.get("MSG_KEY_WEATHER_TEMP"), (Object) (weatherSpec.currentTemp - 273))); + + return mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs); + } + + @Override + public GBDeviceEvent[] onAppStart() { + WeatherSpec weatherSpec = Weather.getInstance().getWeatherSpec(); + if (weatherSpec == null) { + return new GBDeviceEvent[]{null}; + } + GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); + sendBytes.encodedBytes = encodeObisdianWeather(weatherSpec); + return new GBDeviceEvent[]{sendBytes}; + } + + @Override + public byte[] encodeUpdateWeather(WeatherSpec weatherSpec) { + return encodeObisdianWeather(weatherSpec); + } +} \ 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 14ae5f9e0..4527299a2 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 @@ -368,6 +368,7 @@ public class PebbleProtocol extends GBDeviceProtocol { private static final UUID UUID_ZALEWSZCZAK_CROWEX = UUID.fromString("a88b3151-2426-43c6-b1d0-9b288b3ec47e"); private static final UUID UUID_ZALEWSZCZAK_FANCY = UUID.fromString("014e17bf-5878-4781-8be1-8ef998cee1ba"); private static final UUID UUID_ZALEWSZCZAK_TALLY = UUID.fromString("abb51965-52e2-440a-b93c-843eeacb697d"); + private static final UUID UUID_OBSIDIAN = UUID.fromString("ef42caba-0c65-4879-ab23-edd2bde68824"); private static final UUID UUID_ZERO = new UUID(0, 0); @@ -390,6 +391,7 @@ public class PebbleProtocol extends GBDeviceProtocol { mAppMessageHandlers.put(UUID_ZALEWSZCZAK_CROWEX, new AppMessageHandlerZalewszczak(UUID_ZALEWSZCZAK_CROWEX, PebbleProtocol.this)); mAppMessageHandlers.put(UUID_ZALEWSZCZAK_FANCY, new AppMessageHandlerZalewszczak(UUID_ZALEWSZCZAK_FANCY, PebbleProtocol.this)); mAppMessageHandlers.put(UUID_ZALEWSZCZAK_TALLY, new AppMessageHandlerZalewszczak(UUID_ZALEWSZCZAK_TALLY, PebbleProtocol.this)); + mAppMessageHandlers.put(UUID_OBSIDIAN, new AppMessageHandlerObsidian(UUID_OBSIDIAN, PebbleProtocol.this)); } private final HashMap mDatalogSessions = new HashMap<>(); diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml index 887dd32e5..abf9e99fc 100644 --- a/app/src/main/res/xml/changelog_master.xml +++ b/app/src/main/res/xml/changelog_master.xml @@ -3,8 +3,8 @@ Better integration with android music players Pebble: Implement notification and incoming call privacy modes + Pebble: Support weather for Obisdian watchface - HPlus: Improve display of new messages and phone calls HPlus: Fix bug related to steps and heart rate From b3cddebdbbe55eeded37ff34072bf820f4e3d07e Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 5 Feb 2017 22:50:42 +0100 Subject: [PATCH 16/53] Pebble: ensure a better error message if someone tries to install a FW 1.x pbw --- .../freeyourgadget/gadgetbridge/devices/pebble/PBWReader.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PBWReader.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PBWReader.java index a045079ed..6fbcd4803 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PBWReader.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PBWReader.java @@ -204,6 +204,9 @@ public class PBWReader { } app = new GBDeviceApp(appUUID, appName, appCreator, appVersion, appType); } + else if (!isFirmware) { + isValid = false; + } } } From 644c06df68950f6f502640a302819bed37ddca9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joa=CC=83o=20Paulo=20Barraca?= Date: Sun, 5 Feb 2017 23:52:36 +0000 Subject: [PATCH 17/53] HPlus: Clear alarms if no alarm is enabled --- .../service/devices/hplus/HPlusSupport.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java index 6ddffffb8..b399b11f7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java @@ -355,9 +355,17 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { private HPlusSupport setAlarm(TransactionBuilder transaction, Calendar t) { + byte hour = HPlusConstants.ARG_ALARM_DISABLE; + byte minute = HPlusConstants.ARG_ALARM_DISABLE; + + if(t != null){ + hour = (byte) t.get(Calendar.HOUR_OF_DAY); + minute = (byte) t.get(Calendar.MINUTE); + } + transaction.write(ctrlCharacteristic, new byte[]{HPlusConstants.CMD_SET_ALARM, - (byte) t.get(Calendar.HOUR_OF_DAY), - (byte) t.get(Calendar.MINUTE)}); + hour, + minute}); return this; } @@ -429,8 +437,8 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { @Override public void onSetAlarms(ArrayList alarms) { - if (alarms.size() == 0) - return; + + TransactionBuilder builder = new TransactionBuilder("alarm"); for (Alarm alarm : alarms) { @@ -441,7 +449,6 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { continue; Calendar t = alarm.getAlarmCal(); - TransactionBuilder builder = new TransactionBuilder("alarm"); setAlarm(builder, t); builder.queue(getQueue()); @@ -449,6 +456,10 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { return; //Only first alarm } + + setAlarm(builder, null); + builder.queue(getQueue()); + GB.toast(getContext(), getContext().getString(R.string.user_feedback_all_alarms_disabled), Toast.LENGTH_SHORT, GB.INFO); } From bf8ae5d5af3a4ddf186c8f3ec85c183274b36f49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joa=CC=83o=20Paulo=20Barraca?= Date: Sun, 5 Feb 2017 23:55:48 +0000 Subject: [PATCH 18/53] HPlus: Add constant ARG_ALARM_DISABLE --- .../gadgetbridge/devices/hplus/HPlusConstants.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusConstants.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusConstants.java index 2fe12b9dc..d158a0af6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusConstants.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusConstants.java @@ -36,6 +36,8 @@ public final class HPlusConstants { public static final byte INCOMING_CALL_STATE_DISABLED_THRESHOLD = 0x7B; public static final byte INCOMING_CALL_STATE_ENABLED = (byte) 0xAA; + public static final byte ARG_ALARM_DISABLE = (byte) -1; + public static final byte[] CMD_SET_PREF_START = new byte[]{0x4f, 0x5a}; public static final byte[] CMD_SET_PREF_START1 = new byte[]{0x4d}; //public static final byte CMD_SET_ALARM = 0x4c; Unknown From a3cc84c01d70d37962514ee4652b372081eee4e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joa=CC=83o=20Paulo=20Barraca?= Date: Mon, 6 Feb 2017 01:33:15 +0000 Subject: [PATCH 19/53] HPlus: add device specific preferences and icon --- .../gadgetbridge/adapter/GBDeviceAdapter.java | 8 +++ .../devices/hplus/HPlusConstants.java | 8 +-- .../devices/hplus/HPlusCoordinator.java | 58 ++++++++++++++---- .../service/devices/hplus/HPlusSupport.java | 13 +--- .../res/drawable-hdpi/ic_device_hplus.png | Bin 0 -> 16273 bytes .../ic_device_hplus_disabled.png | Bin 0 -> 16225 bytes .../res/drawable-mdpi/ic_device_hplus.png | Bin 0 -> 15824 bytes .../ic_device_hplus_disabled.png | Bin 0 -> 16254 bytes .../res/drawable-xhdpi/ic_device_hplus.png | Bin 0 -> 17219 bytes .../ic_device_hplus_disabled.png | Bin 0 -> 17173 bytes .../res/drawable-xxhdpi/ic_device_hplus.png | Bin 0 -> 18437 bytes .../ic_device_hplus_disabled.png | Bin 0 -> 18352 bytes app/src/main/res/values/arrays.xml | 20 ++++++ app/src/main/res/values/strings.xml | 14 +++++ app/src/main/res/values/values.xml | 6 ++ app/src/main/res/xml/preferences.xml | 45 ++++++++++++++ 16 files changed, 146 insertions(+), 26 deletions(-) create mode 100644 app/src/main/res/drawable-hdpi/ic_device_hplus.png create mode 100644 app/src/main/res/drawable-hdpi/ic_device_hplus_disabled.png create mode 100644 app/src/main/res/drawable-mdpi/ic_device_hplus.png create mode 100644 app/src/main/res/drawable-mdpi/ic_device_hplus_disabled.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_device_hplus.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_device_hplus_disabled.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_device_hplus.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_device_hplus_disabled.png diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAdapter.java index 3e3a25a2b..18fabf095 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAdapter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAdapter.java @@ -134,6 +134,14 @@ public class GBDeviceAdapter extends ArrayAdapter { deviceImageView.setImageResource(R.drawable.ic_device_lovetoy_disabled); } break; + case HPLUS: + case MAKIBESF68: + if( device.isConnected()) { + deviceImageView.setImageResource(R.drawable.ic_device_hplus); + } else { + deviceImageView.setImageResource(R.drawable.ic_device_hplus_disabled); + } + break; default: if (device.isConnected()) { deviceImageView.setImageResource(R.drawable.ic_launcher); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusConstants.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusConstants.java index 2fe12b9dc..6d5dd3083 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusConstants.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusConstants.java @@ -14,6 +14,8 @@ public final class HPlusConstants { public static final UUID UUID_CHARACTERISTIC_MEASURE = UUID.fromString("14702853-620a-3973-7c78-9cfff0876abd"); public static final UUID UUID_SERVICE_HP = UUID.fromString("14701820-620a-3973-7c78-9cfff0876abd"); + public static final byte ARG_WRIST_LEFT = 0; //Guess... + public static final byte ARG_WRIST_RIGHT = 1; //Guess... public static final byte ARG_LANGUAGE_CN = 1; public static final byte ARG_LANGUAGE_EN = 2; @@ -104,15 +106,11 @@ public final class HPlusConstants { public static final String PREF_HPLUS_SCREENTIME = "hplus_screentime"; public static final String PREF_HPLUS_ALLDAYHR = "hplus_alldayhr"; - public static final String PREF_HPLUS_HR = "hplus_hr_enable"; public static final String PREF_HPLUS_UNIT = "hplus_unit"; - public static final String PREF_HPLUS_TIMEMODE = "hplus_timemode"; + public static final String PREF_HPLUS_TIMEFORMAT = "hplus_timeformat"; public static final String PREF_HPLUS_WRIST = "hplus_wrist"; - public static final String PREF_HPLUS_SWALERT = "hplus_sw_alert"; - public static final String PREF_HPLUS_ALERT_TIME = "hplus_alert_time"; public static final String PREF_HPLUS_SIT_START_TIME = "hplus_sit_start_time"; public static final String PREF_HPLUS_SIT_END_TIME = "hplus_sit_end_time"; - public static final String PREF_HPLUS_LANGUAGE = "hplus_language"; public static final Map transliterateMap = new HashMap(){ { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusCoordinator.java index 785905f5d..a86561455 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusCoordinator.java @@ -36,6 +36,9 @@ import org.slf4j.LoggerFactory; import java.util.Collection; import java.util.Collections; +import java.util.Locale; + +import static nodomain.freeyourgadget.gadgetbridge.GBApplication.getContext; public class HPlusCoordinator extends AbstractDeviceCoordinator { protected static final Logger LOG = LoggerFactory.getLogger(HPlusCoordinator.class); @@ -144,16 +147,41 @@ public class HPlusCoordinator extends AbstractDeviceCoordinator { } public static byte getLanguage(String address) { - return (byte) prefs.getInt(HPlusConstants.PREF_HPLUS_LANGUAGE + "_" + address, HPlusConstants.ARG_LANGUAGE_EN); + String language = prefs.getString("language", "default"); + Locale locale; + if (language.equals("default")) { + locale = Locale.getDefault(); + } else { + locale = new Locale(language); + } + + if (locale.getLanguage().equals(new Locale("cn").getLanguage())){ + return HPlusConstants.ARG_LANGUAGE_CN; + }else{ + return HPlusConstants.ARG_LANGUAGE_EN; + } } public static byte getTimeMode(String address) { - return (byte) prefs.getInt(HPlusConstants.PREF_HPLUS_TIMEMODE + "_" + address, HPlusConstants.ARG_TIMEMODE_24H); + String tmode = prefs.getString(HPlusConstants.PREF_HPLUS_TIMEFORMAT, getContext().getString(R.string.p_timeformat_24h)); + + if(tmode.equals(getContext().getString(R.string.p_timeformat_24h))) { + return HPlusConstants.ARG_TIMEMODE_24H; + }else{ + return HPlusConstants.ARG_TIMEMODE_12H; + } + } public static byte getUnit(String address) { - return (byte) prefs.getInt(HPlusConstants.PREF_HPLUS_UNIT + "_" + address, 0); + String units = prefs.getString(HPlusConstants.PREF_HPLUS_UNIT, getContext().getString(R.string.p_unit_metric)); + + if(units.equals(getContext().getString(R.string.p_unit_metric))){ + return HPlusConstants.ARG_UNIT_METRIC; + }else{ + return HPlusConstants.ARG_UNIT_IMPERIAL; + } } public static byte getUserWeight(String address) { @@ -190,15 +218,17 @@ public class HPlusCoordinator extends AbstractDeviceCoordinator { } public static byte getScreenTime(String address) { - return (byte) (prefs.getInt(HPlusConstants.PREF_HPLUS_SCREENTIME + "_" + address, 5) & 0xFF); + return (byte) (prefs.getInt(HPlusConstants.PREF_HPLUS_SCREENTIME, 5) & 0xFF); } public static byte getAllDayHR(String address) { - return (byte) (prefs.getInt(HPlusConstants.PREF_HPLUS_ALLDAYHR + "_" + address, HPlusConstants.ARG_HEARTRATE_ALLDAY_ON) & 0xFF); - } + Boolean value = (prefs.getBoolean(HPlusConstants.PREF_HPLUS_ALLDAYHR, true)); - public static byte getHRState(String address) { - return (byte) (prefs.getInt(HPlusConstants.PREF_HPLUS_HR + "_" + address, HPlusConstants.ARG_HEARTRATE_MEASURE_ON) & 0xFF); + if(value){ + return HPlusConstants.ARG_HEARTRATE_ALLDAY_ON; + }else{ + return HPlusConstants.ARG_HEARTRATE_ALLDAY_OFF; + } } public static byte getSocial(String address) { @@ -208,15 +238,21 @@ public class HPlusCoordinator extends AbstractDeviceCoordinator { } public static byte getUserWrist(String address) { - return (byte) (prefs.getInt(HPlusConstants.PREF_HPLUS_WRIST + "_" + address, 10) & 0xFF); + String value = prefs.getString(HPlusConstants.PREF_HPLUS_WRIST, getContext().getString(R.string.left)); + + if(value.equals(getContext().getString(R.string.left))){ + return HPlusConstants.ARG_WRIST_LEFT; + }else{ + return HPlusConstants.ARG_WRIST_RIGHT; + } } public static int getSITStartTime(String address) { - return prefs.getInt(HPlusConstants.PREF_HPLUS_SIT_START_TIME + "_" + address, 0); + return prefs.getInt(HPlusConstants.PREF_HPLUS_SIT_START_TIME, 0); } public static int getSITEndTime(String address) { - return prefs.getInt(HPlusConstants.PREF_HPLUS_SIT_END_TIME + "_" + address, 0); + return prefs.getInt(HPlusConstants.PREF_HPLUS_SIT_END_TIME, 0); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java index 6ddffffb8..255137555 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java @@ -172,6 +172,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { private HPlusSupport setTimeMode(TransactionBuilder transaction) { byte value = HPlusCoordinator.getTimeMode(getDevice().getAddress()); + transaction.write(ctrlCharacteristic, new byte[]{ HPlusConstants.CMD_SET_TIMEMODE, value @@ -333,15 +334,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { private HPlusSupport setAllDayHeart(TransactionBuilder transaction) { - byte value = HPlusCoordinator.getHRState(getDevice().getAddress()); - - transaction.write(ctrlCharacteristic, new byte[]{ - HPlusConstants.CMD_SET_HEARTRATE_STATE, - value - }); - - - value = HPlusCoordinator.getAllDayHR(getDevice().getAddress()); + byte value = HPlusCoordinator.getAllDayHR(getDevice().getAddress()); transaction.write(ctrlCharacteristic, new byte[]{ HPlusConstants.CMD_SET_ALLDAY_HRM, @@ -481,7 +474,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport { @Override public void onEnableRealtimeSteps(boolean enable) { - + onEnableRealtimeHeartRateMeasurement(enable); } @Override diff --git a/app/src/main/res/drawable-hdpi/ic_device_hplus.png b/app/src/main/res/drawable-hdpi/ic_device_hplus.png new file mode 100644 index 0000000000000000000000000000000000000000..7af95bddc8e72e22a0da9fbeb3c6de9d6e8a51a5 GIT binary patch literal 16273 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_device_hplus_disabled.png b/app/src/main/res/drawable-hdpi/ic_device_hplus_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..a4a7d7fdbdbc117c5fd932760aaf80cf66a613d8 GIT binary patch literal 16225 zcmeI3dsGu=7Qjb@8fme(K1!{vAzjXbb(qPEJV;^?uz&_Ipar|NP9_sFl4N3L0)cX@ zBCU@@TernpSF7wYQ+dT3Q--B#Ui5+30Lrk-xk z*?%VIR*;5&CLu_whAu4PiY)W>B;!sd?2L^{4!FHwH-Z>u2fPGXN^w#fRYH4=vhJo2 zWK!C0ls%!g;1+K><)pJJeN;hZZXsD&O6u&g*`{biKo1ZlG_#}%T&~7&C8oqtg;KA= z^(uw5?2w&bz!VA;>_FKH z4@U%05Bq4yNxz>AiY0xtm!lbvl=n;67(Zu}$@oA6ufB7+y#s+fY#%#75epDrOrDHm zBN^Gr0UNL1=L%k$ox~^?<)%Cw3+&`0+IgJ}$FNRjl#m1JQ3HdVSm_cc#}33F@tS?X zJtJNM@L;hBTf5yOTC!Yb8GzWAlo8{yg%w^3vr;VM_mNa)8G!NVNc=e3F__*Vo_Niu zr>6q+C}zASWEL!@P>v1Yton2xMR1I-kYQY=P@U%YCqbH?9;{1gqJ2#3!H?HN^{Yr zl(et3NIqqB83nq~&4B9Q8{b8fl!v8Q%vOPVNR%ZoCFo59#&@@i9(p;U)uC4zJm#55+avLu14;1EXSfD&Wk@gU- zus!@)>>wEKAhkF_I#7+)u0mCEHGyhvHWHjlrN&8(Qj4qc{tzR$85SywW)%sh^O85ytiZGY35FP<+w}MlP5`U?2`%xVyB4k~y@e`ulWv4;uLYXg%m(P*7k_ zgT4WCW7yhYiz7Ji&KLC?Ti)(dS9FybV)n^;7hi!|0#5PnA!GNq{1O0@xlmtl*1IzYLKGH5V^S)PdoL<-u#iV+QqM>7ml^cjYd z6?TUk9E71&aQ_T$-LZjt_hB<~V1oUeKL$_qb9#k*i9sMB!lH;vm=B~CaX~P5f=nRSQK#y^MSM?E(nOQ zDB=?418GHE5D;Ne#3jrJ(u%ksAi|=EOPCL&6>&j8ghdgTFds-O;(~w(iy|&zK9E+# z1pyHjMO?ysAgzcC0wOGmxPNK!imRmoOhlE8>EH2#X>vVLp&n#03En76oxd4?Yb`dB7vE z<=|P@;)N$Q;5k_-nPs&gNM!S@oalceY>-{&XBJr_w%m9CC`F9NxA{`~owNF7rDcWtgNX5FRK ztxegI;_T|W$%%{AEsg`lyXqDt?R=+aG=G zqt~MTDy?~&YwGAcuy)eLAAT@QH*Q)oDNk8IPup4-(qYiv|ntTkuP;&0SQV)3ig zi=L+a=7}$UQHe^bKOVdMlS5;c79=%15}&!pIX(Znf63QdKR7Y|3~BrOkM&gEO6}~O!MMlMGF(etPE=6MIJt>3-1$}F#_s>+Z?=3I_{!CY+I(dm=MMqHfk z{OZKai1X1$pKb+doQH4~73<8O`<5?XWtJR7PM$tJC8DKcYG!?0{he#f_CnYGLsf6i z-zSY+-*|YXS$^pBM9Dkn;$tJ?PipQt-ky2&FXp24=Z>{4TPi@L6Z-z5XR}DJsA^v$Q#(=F5q5s+OsyJ+t-NjMmtl zr+VkC&6~6K;k`Xmk=hkcqGy}_{NAidNKVdf|FI&Am&q6Pbf+*$E!+L?>w3{X~V%c@F!L$+;;=tqPr7=)W7)$VvOeVX8s}g?9AMZ JeRGyp{}+X0Jz@X= literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_device_hplus.png b/app/src/main/res/drawable-mdpi/ic_device_hplus.png new file mode 100644 index 0000000000000000000000000000000000000000..88e4c9c13a22d6819f1ee187c216feb0bec464ce GIT binary patch literal 15824 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_device_hplus.png b/app/src/main/res/drawable-xhdpi/ic_device_hplus.png new file mode 100644 index 0000000000000000000000000000000000000000..e91f060f82b4fda154d645aa2e618956e407b326 GIT binary patch literal 17219 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_device_hplus_disabled.png b/app/src/main/res/drawable-xhdpi/ic_device_hplus_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..2c3f219cd3329d79df3ce3e109311895ef8d1c3c GIT binary patch literal 17173 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_device_hplus.png b/app/src/main/res/drawable-xxhdpi/ic_device_hplus.png new file mode 100644 index 0000000000000000000000000000000000000000..01996225f5c768cc1b56fddff5db8bf5d212d759 GIT binary patch literal 18437 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_device_hplus_disabled.png b/app/src/main/res/drawable-xxhdpi/ic_device_hplus_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..a70528df4d263af0690fed12b8ac4313c9ef2cc3 GIT binary patch literal 18352 zcmeI3c~n!^*1#_)lS2h3EJ6*j7NUmCgoF?VqXG&jAOeb*;U)w!UkhVLX{yyAUb-|Jf6`rb-bhP%%`d!KWEdpOA- zSvMze=I|kQLm&tm?&r%12A^AWFH3Xq{%FR7W8lLo-Zw%CL4NJJmq`q6_$UZswTMH* zRp9}%nS8m_g)5NrV3#CmJeUo1o=NdsejKdA@L-Wx=7D{F;xrZ`7I)dk8Cu2^>ga6&I5vmB^ILBoD0KFB4qrh6z}Veu^s21M96@ z5EC9S2Qy8sfH5=|S3IBSO2^O{E+iVAPNh%9kclK3fk+`xhEsjd0?@+g?b)c_a%+*SxBbrVh1P^lDP2%k_(YAkdc7j zV-v4dNc3A1@CmR4mclZX64;Rjw2P0CtK`ZU`6rg_QGaq_5R+iBC`P61S%1JiEA(>) z+yd|r5P)til@4gBR83C+5W9jh;JV7tmoJv-B7?OF7rNXSpJ_;mzR{&hFv< zCIJCVKbca+mGNOe4jcGz5sL*(m`|j0$wE5bjVy4(Q^^c6o+0E3@HCphjp9b43#fd) z-gSTTk6d%)e6_Cm0M~{-Es*np``$ZYzEffSOie+3$pE6;pp z%hx3)Tc3EafJNvx+PkeD%PuqV$Km{I2n_!Fn16bW#28riiB4niqMz_-d!<~cO4L=D z2qec}>wpHo{SA=|3|x7COB9scg#RoCbgF(9t%m&yN8u7xW>}5c?1Oe+t`Q>xBPd*t$;H|BA2~ zYOsGR>~60gw@#Mss}&QpUC;->@e0}lEO7!P8o9ae%W4MtCBqDfp z+4j{VZ6p4TZC^dow%2r?Osry)yOu)?_p#D_12i1sA>ii@%yy;GDB!R`4kIn*h?8JR zI7bYQPNkj+mD**5)C_1D@kz@*nl4L2xcdAw(Vt+3QSieD{N^I`{OJ1VaO*jG{?3cu zTlzb_B77MaK>$G)jkwVHAhbqY2q5U95f?figw}`)0R&w%;zH+x&>C?efS`*;T+WaiQ};XpOiKK+r`aE_6N!tq~Uj2)by*h0X_|HR3`5K^Kj<(D@*=MqCIW z=%Nu9Iv<4AhzkJ(T{PlC=Y!B1aUp=9i>SDU^!|+*mVy5+CxSmI@4#hsfIm26_`bmb z5R@_rg3?w&(3?*1`51!KLM)$fn&Y~A|Brqn@9GwmGbWoe~3M^>o0CJtvv z%e`E-k1wxR@PBOHbo@v6Fz3-OjvqE^;wZ1Uvrl?mCwP^$jH9mcxgX5V*_^c7c1cts z%f9C5USGLFA@itQ|3~YabQ2iUZaTLPTJvJ`kTtW+1GK^GV)OYIc%)|~vTV&L-{lWV zWToL#FBaYS$zMB?mNjI}S?$<#mtnafNyF@KsvmBHC#`daBf=tanF;oyvw|f{UXZUw zoo&s_@L#Yk^Rou`$0f2mUgQ&Vi__nlHh%d$;o*Ndo z3vLkaqgO?W);S-@xHOeO2omQzIh1KIdqz{7j@%%v`sE47*6d1SrDvzTlxi1E+j+Sz zAt9mT*6rIbwyxhUEPNv>y#2oYcA+TRBl+c*Hy*oOpXIgJ-QAtO<8nj!u3ZkNt72X+ zSg@dDvu8*8!k;Bl>6?u+&W*ScD_^?w-3+JgO^YBqntM>;?PbSLo_y;0_1o)pw{Cfv zV}f$n?Zw5#A7D3>OE81EQeASC$}|jJq^Up zwrfGrYvZQNTld%Dazmz{efsoi^a{~o8;_-bK8en6nlAEg8hj<@z|8jNr#m}FOg+E& z(LW}nzRtmM)~??y8uNv_sh}mRsi3*!;pPdRsT-${d%{Y6|GFs8R-Df_zZS8ktkpDj z-OMlN69uJ+%SKwNlZ)OsZ$-cHc>V{6*2jRkfmlnf{X|Yd2)aELWNT z@`MdCA&`U1Z~qb+K0KG9y-uq+DjJT(`kP&T{^A~O>t6nog=rNpGAkcVJSv^3Vc1Zg zk|C;nntho@)G*#ZFU}|Zb8YCwCD~TOz*|QhJd!u;8b9at>&e^8{eVwO&>*nOZ-P^s z+cc)LBSUPp* z&YjTe(x}~@%b(@gSLS$HUob8t# zv`A|?PVCy6VS~u`+!Yo_ii;C}FuQW7^zlRwh?@&M|-9pr4?_!06a7wrYoe=~n& zywS%b)^%sc{rmSdL)G!|_vA9!sY0u}ckW2ue0b(G^U&!^hcs)$tqcYiK88(zi?=4e zxT2Oo2&cX3pEnE|Zj0%T@kxt6N}gqby1T%$Nn2~ZC4*d6kz?g38(EbttttF^kU-z$ z4EZIrC<&RI$yVEoc56IG`czmtewXg7E!vd4+xD^D7EocJ&7}wXq~jdVgEcI`8Y_dF zjs`dJ9nZH1=e7OoMhbbD^Y-#~^Et;C2FB()X_8a;{D-u$T<1-PgEYyz(;N0>%-1CU zuC4{OJ*nsh2?r;pDURO>2aP;*a;7uIsp8vlz;W)q#uCTX$7IhuH$9w9RGvNhH0ED( zj%AeBUuWged`vX#RyyQ{0`b>2O>GP7CyojEK-2s*WYZ747J}cV^IXwR+6)pOahet%yEQ{r=sn=bfht3dqaNcT^>; zuN&%B=5jOf`Q3o91J#F~*PeKl6I=9Flpof*b*RQOuIP7pb*#GnS?!5mM{RzzccPq; z@|p9(yrWa6;IyR&i+&qfm04e3zj-CQT&leevLmqN?az-Y-XFJqkmH+3QsT4~IPEiM zaMm`uQYv@ao(GXzlD#gWx_+y2!y;4Wjrh#q8MC)mwUw{Dd#NaQ?kg)wEzYN0y#=;uy~V3Ze3O8D?eL7U&+`t%4gw-hIjityg4{<*55bfI-Ljt-xU%auN4(f zo#N0IMy_DtS7&h>BCsU|M~R9WplWx|Zm zCPXEc2Iq0sU*Li7BlQY~9|u=na24b`=EFKTLX7p#EU*8P;`Gl8ygQ*gDr1966TR}S z&1&k8No(fjs}F+jE~~yzbE7zIxqDGvdrb2%KDxZMlz!CdEe8!^=q2X+wqi}`H`b*A3Ub#hHMGs`P`M>y?(P~f7&K*9~VxF o>s>qRm8H0>!TJtkPVJlk<%mlq7ng1%L*U^zJ&^OG&*GK;1Af28t^fc4 literal 0 HcmV?d00001 diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index e2aff8f58..63bbb3100 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -122,4 +122,24 @@ @string/p_dateformat_datetime + + @string/unit_metric + @string/unit_imperial + + + + @string/p_unit_metric + @string/p_unit_imperial + + + + @string/timeformat_24h + @string/timeformat_am_pm + + + + @string/p_timeformat_24h + @string/p_timeformat_am_pm + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 88226d4ce..d72def7f6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -142,6 +142,13 @@ Reconnection Attempts + //HPlus Preferences + Units + Time format + Screen on duration + All day heart rate measurement + HPlus/Makibes Settings + not connected connecting connected @@ -382,4 +389,11 @@ Make sure that this skin is enabled in the Weather Notification app to get weather information on your Pebble.\n\nNo configuration is needed here.\n\nYou can enable the system weather app of your Pebble from the app management.\n\nSupported watchfaces will show the weather automatically. Enable Bluetooth pairing Deactivate this if you have trouble connecting + + Metric + Imperial + + 24H + AM/PM + diff --git a/app/src/main/res/values/values.xml b/app/src/main/res/values/values.xml index df90cb5b7..d8a8eff79 100644 --- a/app/src/main/res/values/values.xml +++ b/app/src/main/res/values/values.xml @@ -12,4 +12,10 @@ dateformat_time dateformat_datetime + metric + imperial + + 24h + am/pm + diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 39c7d9ed9..e9df02ac7 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -388,6 +388,51 @@ android:title="Emulator Port" /> + + + + + + + + + + + + + + + + Date: Tue, 7 Feb 2017 10:15:23 +0100 Subject: [PATCH 20/53] made caller privacy pebble setting generic --- .../gadgetbridge/impl/GBDeviceService.java | 19 ++++- .../service/devices/pebble/PebbleSupport.java | 8 -- app/src/main/res/values/arrays.xml | 12 +++ app/src/main/res/values/strings.xml | 12 ++- app/src/main/res/values/values.xml | 3 + app/src/main/res/xml/preferences.xml | 85 +++++++++++-------- 6 files changed, 89 insertions(+), 50 deletions(-) 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 c8f839267..05bec9de9 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java @@ -11,6 +11,8 @@ import android.support.annotation.Nullable; import java.util.ArrayList; import java.util.UUID; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec; import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; @@ -85,7 +87,7 @@ public class GBDeviceService implements DeviceService { connect(device, false); } - @Override + @Override public void connect(@Nullable GBDevice device, boolean performPair) { Intent intent = createIntent().setAction(ACTION_CONNECT) .putExtra(GBDevice.EXTRA_DEVICE, device) @@ -149,9 +151,22 @@ public class GBDeviceService implements DeviceService { @Override public void onSetCallState(CallSpec callSpec) { + Context context = GBApplication.getContext(); + String currentPrivacyMode = GBApplication.getPrefs().getString("pref_call_privacy_mode", GBApplication.getContext().getString(R.string.p_call_privacy_mode_off)); + if (context.getString(R.string.p_call_privacy_mode_name).equals(currentPrivacyMode)) { + callSpec.name = callSpec.number; + } + else if (context.getString(R.string.p_call_privacy_mode_complete).equals(currentPrivacyMode)) { + callSpec.number = null; + callSpec.name = null; + } + else { + callSpec.name = coalesce(callSpec.name, getContactDisplayNameByNumber(callSpec.number)); + } + Intent intent = createIntent().setAction(ACTION_CALLSTATE) .putExtra(EXTRA_CALL_PHONENUMBER, callSpec.number) - .putExtra(EXTRA_CALL_DISPLAYNAME, coalesce(callSpec.name, getContactDisplayNameByNumber(callSpec.number))) + .putExtra(EXTRA_CALL_DISPLAYNAME, callSpec.name) .putExtra(EXTRA_CALL_COMMAND, callSpec.command); invokeService(intent); } 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 e4f59e852..d4afb684a 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 @@ -131,14 +131,6 @@ public class PebbleSupport extends AbstractSerialDeviceSupport { @Override public void onSetCallState(CallSpec callSpec) { - String currentPrivacyMode = GBApplication.getPrefs().getString("pebble_pref_privacy_mode", getContext().getString(R.string.p_pebble_privacy_mode_off)); - if (getContext().getString(R.string.p_pebble_privacy_mode_complete).equals(currentPrivacyMode)) { - callSpec.name = null; - callSpec.number = null; - } else if (getContext().getString(R.string.p_pebble_privacy_mode_content).equals(currentPrivacyMode)) { - callSpec.name = null; - } - if (reconnect()) { if ((callSpec.command != CallSpec.CALL_OUTGOING) || GBApplication.getPrefs().getBoolean("pebble_enable_outgoing_call", true)) { super.onSetCallState(callSpec); diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index da77e0018..88685f63d 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -155,4 +155,16 @@ @string/p_timeformat_am_pm + + @string/pref_call_privacy_mode_off + @string/pref_call_privacy_mode_name + @string/pref_call_privacy_mode_complete + + + + @string/p_call_privacy_mode_off + @string/p_call_privacy_mode_name + @string/p_call_privacy_mode_complete + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fbfd13a96..d3661cbd0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -88,6 +88,12 @@ when screen is off never + Privacy + Call Privacy Mode + Display name and number + Hide name but display number + Hide name and number + Blacklist Apps Canned Messages @@ -120,9 +126,9 @@ Notifications are automatically removed from the Pebble when dismissed from the Android device Privacy mode - Normal notifications and incoming calls display. - Shift the notification text off-screen. Hide the caller\'s name on incoming calls. - Show only the notification icon. Hide the caller\'s name and number on incoming calls. + Normal notifications + Shift the notification text off-screen + Show only the notification icon Location Acquire Location diff --git a/app/src/main/res/values/values.xml b/app/src/main/res/values/values.xml index ef1cd4a3b..27745d3e0 100644 --- a/app/src/main/res/values/values.xml +++ b/app/src/main/res/values/values.xml @@ -22,4 +22,7 @@ content complete + off + name + complete diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 044d5faa9..d558fa4b4 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -36,6 +36,44 @@ android:summaryOff="@string/pref_summary_minimize_priority_off" android:summaryOn="@string/pref_summary_minimize_priority_on" android:title="@string/pref_title_minimize_priority" /> + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + From 4f0674d038ac95aab2935b9b95022e8470c4dd36 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Tue, 7 Feb 2017 23:49:10 +0100 Subject: [PATCH 21/53] Support for alarm clock notifications for Mi1 + Mi2 #538 No support for Pebble and HPlus for now. Atm relies on the CM deskclock alarm, which nicely broadcasts events about the current alarm. See https://github.com/CyanogenMod/android_packages_apps_DeskClock.git --- .../devices/miband/MiBandConst.java | 1 + .../miband/MiBandPreferencesActivity.java | 2 + .../externalevents/AlarmClockReceiver.java | 67 +++++++++++++++++++ .../gadgetbridge/model/NotificationType.java | 4 +- .../service/DeviceCommunicationService.java | 15 ++++- .../service/devices/miband/MiBandSupport.java | 25 ++++++- .../devices/miband2/MiBand2Support.java | 38 +++++++---- .../actions/StopNotificationAction.java | 28 ++++++++ app/src/main/res/values/strings.xml | 1 + app/src/main/res/xml/miband_preferences.xml | 30 +++++++++ 10 files changed, 194 insertions(+), 17 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmClockReceiver.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/actions/StopNotificationAction.java 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 98877a833..b8e6f456d 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 @@ -23,6 +23,7 @@ public final class MiBandConst { public static final String ORIGIN_INCOMING_CALL = "incoming_call"; + public static final String ORIGIN_ALARM_CLOCK = "alarm_clock"; public static final String MI_GENERAL_NAME_PREFIX = "MI"; public static final String MI_BAND2_NAME = "MI Band 2"; public static final String MI_1 = "1"; 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 caeb4e2a6..129f4afe4 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 @@ -17,6 +17,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; import nodomain.freeyourgadget.gadgetbridge.util.GB; +import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.ORIGIN_ALARM_CLOCK; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.ORIGIN_INCOMING_CALL; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_ACTIVATE_DISPLAY_ON_LIFT; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_DATEFORMAT; @@ -146,6 +147,7 @@ public class MiBandPreferencesActivity extends AbstractSettingsActivity { prefKeys.add(PREF_MIBAND_FITNESS_GOAL); prefKeys.add(PREF_MIBAND_RESERVE_ALARM_FOR_CALENDAR); prefKeys.add(PREF_MIBAND_DEVICE_TIME_OFFSET_HOURS); + prefKeys.add(getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_ALARM_CLOCK)); prefKeys.add(getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_INCOMING_CALL)); for (NotificationType type : NotificationType.values()) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmClockReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmClockReceiver.java new file mode 100644 index 000000000..6753c5edc --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmClockReceiver.java @@ -0,0 +1,67 @@ +package nodomain.freeyourgadget.gadgetbridge.externalevents; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; + +public class AlarmClockReceiver extends BroadcastReceiver { + /** + * AlarmActivity and AlarmService (when unbound) listen for this broadcast intent + * so that other applications can snooze the alarm (after ALARM_ALERT_ACTION and before + * ALARM_DONE_ACTION). + */ + public static final String ALARM_SNOOZE_ACTION = "com.android.deskclock.ALARM_SNOOZE"; + + /** + * AlarmActivity and AlarmService listen for this broadcast intent so that other + * applications can dismiss the alarm (after ALARM_ALERT_ACTION and before ALARM_DONE_ACTION). + */ + public static final String ALARM_DISMISS_ACTION = "com.android.deskclock.ALARM_DISMISS"; + + /** A public action sent by AlarmService when the alarm has started. */ + public static final String ALARM_ALERT_ACTION = "com.android.deskclock.ALARM_ALERT"; + + /** A public action sent by AlarmService when the alarm has stopped for any reason. */ + public static final String ALARM_DONE_ACTION = "com.android.deskclock.ALARM_DONE"; + private int lastId; + + + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (ALARM_ALERT_ACTION.equals(action)) { + sendAlarm(true); + } else if (ALARM_DONE_ACTION.equals(action)) { + sendAlarm(false); + } + } + + + + private synchronized void sendAlarm(boolean on) { + dismissLastAlarm(); + if (on) { + lastId = generateId(); + NotificationSpec spec = new NotificationSpec(); + spec.type = NotificationType.GENERIC_ALARM_CLOCK; + // can we get the alarm title somehow? + GBApplication.deviceService().onNotification(spec); + } + } + + private void dismissLastAlarm() { + if (lastId != 0) { + GBApplication.deviceService().onDeleteNotification(lastId); + lastId = 0; + } + } + + private int generateId() { + // lacks negative values, but should be sufficient + return (int) (Math.random() * Integer.MAX_VALUE); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationType.java index daae8f4ce..2f0128259 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationType.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationType.java @@ -17,7 +17,8 @@ public enum NotificationType { SIGNAL(PebbleIconID.NOTIFICATION_HIPCHAT, PebbleColor.BlueMoon), TWITTER(PebbleIconID.NOTIFICATION_TWITTER, PebbleColor.BlueMoon), TELEGRAM(PebbleIconID.NOTIFICATION_TELEGRAM, PebbleColor.PictonBlue), - WHATSAPP(PebbleIconID.NOTIFICATION_WHATSAPP, PebbleColor.MayGreen); + WHATSAPP(PebbleIconID.NOTIFICATION_WHATSAPP, PebbleColor.MayGreen), + GENERIC_ALARM_CLOCK(PebbleIconID.ALARM_CLOCK, PebbleColor.Red); public int icon; public byte color; @@ -41,6 +42,7 @@ public enum NotificationType { case GENERIC_EMAIL: case GENERIC_NAVIGATION: case GENERIC_SMS: + case GENERIC_ALARM_CLOCK: return getFixedValue(); case FACEBOOK: case TWITTER: 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 277e2223a..019e245ff 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -27,6 +27,7 @@ import nodomain.freeyourgadget.gadgetbridge.activities.OnboardingActivity; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; +import nodomain.freeyourgadget.gadgetbridge.externalevents.AlarmClockReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.AlarmReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.BluetoothConnectReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.K9Receiver; @@ -152,8 +153,9 @@ public class DeviceCommunicationService extends Service implements SharedPrefere private MusicPlaybackReceiver mMusicPlaybackReceiver = null; private TimeChangeReceiver mTimeChangeReceiver = null; private BluetoothConnectReceiver mBlueToothConnectReceiver = null; - private AlarmReceiver mAlarmReceiver = null; + private AlarmClockReceiver mAlarmClockReceiver = null; + private AlarmReceiver mAlarmReceiver = null; private Random mRandom = new Random(); /** @@ -619,6 +621,13 @@ public class DeviceCommunicationService extends Service implements SharedPrefere mAlarmReceiver = new AlarmReceiver(); registerReceiver(mAlarmReceiver, new IntentFilter("DAILY_ALARM")); } + if (mAlarmClockReceiver == null) { + mAlarmClockReceiver = new AlarmClockReceiver(); + IntentFilter filter = new IntentFilter(); + filter.addAction(AlarmClockReceiver.ALARM_ALERT_ACTION); + filter.addAction(AlarmClockReceiver.ALARM_DONE_ACTION); + registerReceiver(mAlarmClockReceiver, filter); + } } else { if (mPhoneCallReceiver != null) { unregisterReceiver(mPhoneCallReceiver); @@ -652,6 +661,10 @@ public class DeviceCommunicationService extends Service implements SharedPrefere unregisterReceiver(mAlarmReceiver); mAlarmReceiver = null; } + if (mAlarmClockReceiver != null) { + unregisterReceiver(mAlarmClockReceiver); + mAlarmClockReceiver = null; + } } } 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 be1e32fb2..e5ef862a8 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 @@ -50,6 +50,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.DeviceService; import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport; import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction; @@ -102,6 +103,8 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { private final GBDeviceEventVersionInfo versionCmd = new GBDeviceEventVersionInfo(); private final GBDeviceEventBatteryInfo batteryCmd = new GBDeviceEventBatteryInfo(); private RealtimeSamplesSupport realtimeSamplesSupport; + private boolean alarmClockRining; + private boolean alarmClockRinging; public MiBandSupport() { super(LOG); @@ -541,13 +544,29 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { @Override public void onNotification(NotificationSpec notificationSpec) { + if (notificationSpec.type == NotificationType.GENERIC_ALARM_CLOCK) { + onAlarmClock(notificationSpec); + return; + } + String origin = notificationSpec.type.getGenericType(); performPreferredNotification(origin + " received", origin, null); } + private void onAlarmClock(NotificationSpec notificationSpec) { + alarmClockRining = true; + AbortTransactionAction abortAction = new AbortTransactionAction() { + @Override + protected boolean shouldAbort() { + return !isAlarmClockRinging(); + } + }; + performPreferredNotification("alarm clock ringing", MiBandConst.ORIGIN_ALARM_CLOCK, abortAction); + } + @Override public void onDeleteNotification(int id) { - + alarmClockRining = false; // we should have the notificationtype at least to check } @Override @@ -616,6 +635,10 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { public void onSetCannedMessages(CannedMessagesSpec cannedMessagesSpec) { } + private boolean isAlarmClockRinging() { + // don't synchronize, this is not really important + return alarmClockRinging; + } private boolean isTelephoneRinging() { // don't synchronize, this is not really important return telephoneRinging; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/MiBand2Support.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/MiBand2Support.java index d068c2c55..09f7e6a47 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/MiBand2Support.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/MiBand2Support.java @@ -73,6 +73,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.CheckAuthenti import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.DeviceInfo; import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.NotificationStrategy; import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.RealtimeSamplesSupport; +import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.actions.StopNotificationAction; import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.operations.FetchActivityOperation; import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.operations.InitOperation; import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.operations.UpdateFirmwareOperation; @@ -123,6 +124,7 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport { private final GBDeviceEventVersionInfo versionCmd = new GBDeviceEventVersionInfo(); private final GBDeviceEventBatteryInfo batteryCmd = new GBDeviceEventBatteryInfo(); private RealtimeSamplesSupport realtimeSamplesSupport; + private boolean alarmClockRinging; public MiBand2Support() { super(LOG); @@ -586,6 +588,10 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport { @Override public void onNotification(NotificationSpec notificationSpec) { + if (notificationSpec.type == NotificationType.GENERIC_ALARM_CLOCK) { + onAlarmClock(notificationSpec); + return; + } int alertLevel = MiBand2Service.ALERT_LEVEL_MESSAGE; if (notificationSpec.type == NotificationType.UNKNOWN) { alertLevel = MiBand2Service.ALERT_LEVEL_VIBRATE_ONLY; @@ -594,9 +600,20 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport { performPreferredNotification(origin + " received", origin, alertLevel, null); } + private void onAlarmClock(NotificationSpec notificationSpec) { + alarmClockRinging = true; + AbortTransactionAction abortAction = new StopNotificationAction(getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_ALERT_LEVEL)) { + @Override + protected boolean shouldAbort() { + return !isAlarmClockRinging(); + } + }; + performPreferredNotification("alarm clock ringing", MiBandConst.ORIGIN_ALARM_CLOCK, MiBand2Service.ALERT_LEVEL_VIBRATE_ONLY, abortAction); + } + @Override public void onDeleteNotification(int id) { - + alarmClockRinging = false; // we should have the notificationtype at least to check } @Override @@ -616,23 +633,11 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport { public void onSetCallState(CallSpec callSpec) { if (callSpec.command == CallSpec.CALL_INCOMING) { telephoneRinging = true; - AbortTransactionAction abortAction = new AbortTransactionAction() { + AbortTransactionAction abortAction = new StopNotificationAction(getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_ALERT_LEVEL)) { @Override protected boolean shouldAbort() { return !isTelephoneRinging(); } - - @Override - public boolean run(BluetoothGatt gatt) { - if (!super.run(gatt)) { - // send a signal to stop the vibration - BluetoothGattCharacteristic characteristic = MiBand2Support.this.getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_ALERT_LEVEL); - characteristic.setValue(new byte[] {MiBand2Service.ALERT_LEVEL_NONE}); - gatt.writeCharacteristic(characteristic); - return false; - } - return true; - } }; performPreferredNotification("incoming call", MiBandConst.ORIGIN_INCOMING_CALL, MiBand2Service.ALERT_LEVEL_PHONE_CALL, abortAction); } else if ((callSpec.command == CallSpec.CALL_START) || (callSpec.command == CallSpec.CALL_END)) { @@ -644,6 +649,11 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport { public void onSetCannedMessages(CannedMessagesSpec cannedMessagesSpec) { } + private boolean isAlarmClockRinging() { + // don't synchronize, this is not really important + return alarmClockRinging; + } + private boolean isTelephoneRinging() { // don't synchronize, this is not really important return telephoneRinging; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/actions/StopNotificationAction.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/actions/StopNotificationAction.java new file mode 100644 index 000000000..1de8ad6cc --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/actions/StopNotificationAction.java @@ -0,0 +1,28 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.actions; + +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCharacteristic; + +import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBand2Service; +import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.AbortTransactionAction; + +public abstract class StopNotificationAction extends AbortTransactionAction { + + private final BluetoothGattCharacteristic alertLevelCharacteristic; + + public StopNotificationAction(BluetoothGattCharacteristic alertLevelCharacteristic) { + this.alertLevelCharacteristic = alertLevelCharacteristic; + } + + @Override + public boolean run(BluetoothGatt gatt) { + if (!super.run(gatt)) { + // send a signal to stop the vibration + alertLevelCharacteristic.setValue(new byte[]{MiBand2Service.ALERT_LEVEL_NONE}); + gatt.writeCharacteristic(alertLevelCharacteristic); + return false; + } + return true; + } +}; + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d3661cbd0..86095992e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -406,5 +406,6 @@ 24H AM/PM + Alarm Clock diff --git a/app/src/main/res/xml/miband_preferences.xml b/app/src/main/res/xml/miband_preferences.xml index ed215a5a2..65bb17597 100644 --- a/app/src/main/res/xml/miband_preferences.xml +++ b/app/src/main/res/xml/miband_preferences.xml @@ -210,6 +210,36 @@ android:title="@string/vibration_try"/> + + + + + + + + + + + Date: Thu, 9 Feb 2017 15:07:00 +0100 Subject: [PATCH 22/53] Pebble: fix alarm notifications only working one id -1 means undefined, everything else is liked to a real android notification --- .../gadgetbridge/externalevents/AlarmClockReceiver.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmClockReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmClockReceiver.java index 6753c5edc..b01707c99 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmClockReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmClockReceiver.java @@ -48,6 +48,7 @@ public class AlarmClockReceiver extends BroadcastReceiver { lastId = generateId(); NotificationSpec spec = new NotificationSpec(); spec.type = NotificationType.GENERIC_ALARM_CLOCK; + spec.id = -1; // can we get the alarm title somehow? GBApplication.deviceService().onNotification(spec); } From 5bb1995eb9c176edf19fe289dba67d08da86bb95 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 9 Feb 2017 17:10:39 +0100 Subject: [PATCH 23/53] Pebble: fix privacy mode title being "null" in some cases --- .../service/devices/pebble/PebbleSupport.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) 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 d4afb684a..6140b24c1 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 @@ -122,7 +122,13 @@ public class PebbleSupport extends AbstractSerialDeviceSupport { notificationSpec.title = null; notificationSpec.phoneNumber = null; } else if (getContext().getString(R.string.p_pebble_privacy_mode_content).equals(currentPrivacyMode)) { - notificationSpec.sender = "\n\n\n\n\n" + notificationSpec.sender; + if (notificationSpec.sender != null) {if (notificationSpec.sender != null) { + notificationSpec.sender = "\n\n\n\n\n" + notificationSpec.sender; + } else if (notificationSpec.title != null) { + notificationSpec.title = "\n\n\n\n\n" + notificationSpec.title; + } else if (notificationSpec.subject != null) { + notificationSpec.subject = "\n\n\n\n\n" + notificationSpec.subject; + } } if (reconnect()) { super.onNotification(notificationSpec); From 2b7162055dfd00e482117ecbfc27028e0a300be3 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 9 Feb 2017 17:18:33 +0100 Subject: [PATCH 24/53] bump version, add changelog --- CHANGELOG.md | 9 +++++++-- app/build.gradle | 4 ++-- app/src/main/res/xml/changelog_master.xml | 9 +++++++-- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 91237f346..8a3ce44cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,14 @@ ###Changelog -####Version next +####Version 0.17.4 (next) * Better integration with android music players -* Pebble: Implement notification and incoming call privacy modes +* Privacy options for calls (hide caller name/number) +* Pebble: Implement notification privacy modes * Pebble: Support weather for Obisdian watchface +* HPlus: Support alarms +* HPlus: Fix time and date sync and time format (12/24) +* HPlus: Add device specific preferences and icon +* HPlus: Support for Makibes F68 ####Version 0.17.3 * HPlus: Improve display of new messages and phone calls diff --git a/app/build.gradle b/app/build.gradle index a86bb12b8..985f5ef35 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -26,8 +26,8 @@ android { targetSdkVersion 23 // note: always bump BOTH versionCode and versionName! - versionName "0.17.3" - versionCode 84 + versionName "0.17.4" + versionCode 85 } buildTypes { release { diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml index abf9e99fc..b4d46f05c 100644 --- a/app/src/main/res/xml/changelog_master.xml +++ b/app/src/main/res/xml/changelog_master.xml @@ -1,9 +1,14 @@ - + Better integration with android music players - Pebble: Implement notification and incoming call privacy modes + Privacy options for calls (hide caller name/number) + Pebble: Implement notification privacy modes Pebble: Support weather for Obisdian watchface + HPlus: Support alarms + HPlus: Fix time and date sync and time format (12/24) + HPlus: Add device specific preferences and icon + HPlus: Support for Makibes F68 HPlus: Improve display of new messages and phone calls From 083b8db1ecdf087b7a05e409e1b965037544dcb5 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 9 Feb 2017 17:20:29 +0100 Subject: [PATCH 25/53] update Japanese and Spanish from Transifex (THANKS!) --- app/src/main/res/values-es/strings.xml | 3 +++ app/src/main/res/values-ja/strings.xml | 23 ++++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index a6de97f27..850612101 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -96,6 +96,7 @@ Enviar las horas de salida y puesta de Sol basándose en la localización a la línea cronológica del Pebble Eliminar automáticamente las notificaciones rechazadas Las notificaciones se borran automáticamente de Pebble cuando son rechazadas en Android + Modo privado Localización Buscar localización Latitud @@ -338,4 +339,6 @@ Por favor, ten en cuenta que puedes importar datos desde Mi Band, Pebble Health Emparejando con Pebble En su dispositivo Android va a aparecer un mensaje para emparejarse. Si no apareciera, mira en el cajón de notificaciones y acepta la propuesta de emparejamiento. Después acepta también en tu Pebble. Asegúrate de que este tema esté activado en la aplicación de notificación del tiempo para obtener la información en tu Pebble.\n\nNo se requiere configuración.\n\nPuedes activar la aplicación del tiempo del sistema desde la configuración de la app.\n\nLas watchfaces soportadas mostrarán la información del tiempo automáticamente. + Activar el emparejamiento Bluetooth + Desactiva esto si tienes problemas de conexión diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 6071e09ee..a49252046 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -70,10 +70,15 @@ サイレント サイレントモードに基づいて、送信される不要な通知を停止します。 音訳 - デバイスでお使いの言語のフォントがサポートされていない場合に、使用してください (現在はキリル文字のみ) + デバイスでお使いの言語のフォントがサポートされていない場合に、これを有効にしてください (現在はキリル文字のみ) いつも スクリーンがオフのとき なし + プライバシー + 通話プライバシーモード + 名前と番号を表示 + 名前は非表示、番号は表示 + 名前と番号を非表示 アップのブラックリスト 定型のメッセージ 返信 @@ -96,6 +101,10 @@ 場所に基づいて、Pebble のタイムラインに日の出・日の入りの時間を送ります 消去した通知を自動削除 通知は、Androidデバイスから削除されたときに、Pebbleから自動的に削除されます + プライバシーモード + 通常の通知 + 通知テキストを画面外にシフト + 通知アイコンのみを表示 場所 場所の取得 緯度 @@ -115,6 +124,11 @@ ウォッチアプリのログ記録を有効にする Gadgetbridgeがウォッチアプリからログを記録するようにする (再接続が必要です) 再接続の試行 + 単位 + 時刻形式 + 画面オンの期間 + 一日中心拍数測定 + HPlus/Makibes 設定 非接続 接続中 接続 @@ -338,4 +352,11 @@ Mi Band、Pebble Health、Morpheuz からデータをインポートすること Pebbleペアリング お使いのAndroidデバイスでペアリングのダイアログがポップアップすると思います。 起こらない場合は、通知ドロワーを調べて、ペアリング要求を受け入れます。 その後、Pebbleでペアリング要求を受け入れます 天気予報アプリでこのスキンが有効になっていることを確認してください。\n\nここで必要な設定はありません。\n\nアプリ管理からPebbleのシステム天気アプリを有効にすることができます。\n\nサポートされているウォッチフェイスが自動的に天気を表示します。 + Bluetoothペアリングを有効にする + 接続に問題がある場合は、この機能を無効にしてください + メートル + ヤード・ポンド + 24時間 + AM/PM + アラームクロック From c0076b20d3f369376dca364b1499edbc0380a0e6 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 9 Feb 2017 17:23:41 +0100 Subject: [PATCH 26/53] fix copy and pasta error --- .../gadgetbridge/service/devices/pebble/PebbleSupport.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 6140b24c1..426b65121 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 @@ -122,7 +122,7 @@ public class PebbleSupport extends AbstractSerialDeviceSupport { notificationSpec.title = null; notificationSpec.phoneNumber = null; } else if (getContext().getString(R.string.p_pebble_privacy_mode_content).equals(currentPrivacyMode)) { - if (notificationSpec.sender != null) {if (notificationSpec.sender != null) { + if (notificationSpec.sender != null) { notificationSpec.sender = "\n\n\n\n\n" + notificationSpec.sender; } else if (notificationSpec.title != null) { notificationSpec.title = "\n\n\n\n\n" + notificationSpec.title; From f35e3e460d44c4cb8dd44969a79ddd9eccfba316 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 9 Feb 2017 17:35:46 +0100 Subject: [PATCH 27/53] remove K9 receiver as is works better with generic notifications --- app/src/main/AndroidManifest.xml | 1 - .../activities/ControlCenter.java | 2 - .../externalevents/K9Receiver.java | 87 ------------------- .../externalevents/NotificationListener.java | 6 -- .../service/DeviceCommunicationService.java | 13 --- .../devices/pebble/PebbleProtocol.java | 2 +- app/src/main/res/values/strings.xml | 1 - app/src/main/res/xml/preferences.xml | 8 -- 8 files changed, 1 insertion(+), 119 deletions(-) delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/K9Receiver.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ceb2ac0bc..bdbc78781 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -15,7 +15,6 @@ - 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 35f0009e7..1a2755836 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenter.java @@ -425,8 +425,6 @@ public class ControlCenter extends GBActivity { wantedPermissions.add(Manifest.permission.READ_EXTERNAL_STORAGE); if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_DENIED) wantedPermissions.add(Manifest.permission.READ_CALENDAR); - if (ContextCompat.checkSelfPermission(this, "com.fsck.k9.permission.READ_MESSAGES") == PackageManager.PERMISSION_DENIED) - wantedPermissions.add("com.fsck.k9.permission.READ_MESSAGES"); if (!wantedPermissions.isEmpty()) ActivityCompat.requestPermissions(this, wantedPermissions.toArray(new String[wantedPermissions.size()]), 0); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/K9Receiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/K9Receiver.java deleted file mode 100644 index c9431b43b..000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/K9Receiver.java +++ /dev/null @@ -1,87 +0,0 @@ -package nodomain.freeyourgadget.gadgetbridge.externalevents; - -import android.app.NotificationManager; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; -import android.os.PowerManager; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import nodomain.freeyourgadget.gadgetbridge.GBApplication; -import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; -import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; -import nodomain.freeyourgadget.gadgetbridge.util.Prefs; - -public class K9Receiver extends BroadcastReceiver { - - private static final Logger LOG = LoggerFactory.getLogger(K9Receiver.class); - private final Uri k9Uri = Uri.parse("content://com.fsck.k9.messageprovider/inbox_messages"); - - @Override - public void onReceive(Context context, Intent intent) { - - Prefs prefs = GBApplication.getPrefs(); - if ("never".equals(prefs.getString("notification_mode_k9mail", "when_screen_off"))) { - return; - } - if ("when_screen_off".equals(prefs.getString("notification_mode_k9mail", "when_screen_off"))) { - PowerManager powermanager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - if (powermanager.isScreenOn()) { - return; - } - } - switch (GBApplication.getGrantedInterruptionFilter()) { - case NotificationManager.INTERRUPTION_FILTER_ALL: - break; - case NotificationManager.INTERRUPTION_FILTER_ALARMS: - case NotificationManager.INTERRUPTION_FILTER_NONE: - case NotificationManager.INTERRUPTION_FILTER_PRIORITY: - return; - } - - String uriWanted = intent.getData().toString(); - - String[] messagesProjection = { - "senderAddress", - "subject", - "preview", - "uri" - }; - - NotificationSpec notificationSpec = new NotificationSpec(); - notificationSpec.id = -1; - notificationSpec.type = NotificationType.GENERIC_EMAIL; - - /* - * there seems to be no way to specify the uri in the where clause. - * If we do so, we just get the newest message, not the one requested. - * So, we will just search our message and match the uri manually. - * It should be the first one returned by the query in most cases, - */ - - try (Cursor c = context.getContentResolver().query(k9Uri, messagesProjection, null, null, null)) { - if (c != null) { - while (c.moveToNext()) { - String uri = c.getString(c.getColumnIndex("uri")); - if (uri.equals(uriWanted)) { - notificationSpec.sender = c.getString(c.getColumnIndex("senderAddress")); - notificationSpec.subject = c.getString(c.getColumnIndex("subject")); - notificationSpec.body = c.getString(c.getColumnIndex("preview")); - break; - } - } - } - } catch (Exception e) { - e.printStackTrace(); - notificationSpec.sender = "Gadgetbridge"; - notificationSpec.subject = "Permission Error?"; - notificationSpec.body = "Please reinstall Gadgetbridge to enable K-9 Mail notifications"; - } - - GBApplication.deviceService().onNotification(notificationSpec); - } -} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java index e602dfc00..fc6ecfc64 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java @@ -214,12 +214,6 @@ public class NotificationListener extends NotificationListenerService { return; } - if (source.equals("com.fsck.k9")) { - if (!"never".equals(prefs.getString("notification_mode_k9mail", "when_screen_off"))) { - return; - } - } - if (source.equals("com.moez.QKSMS") || source.equals("com.android.mms") || source.equals("com.sonyericsson.conversations") || 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 019e245ff..5e5315c72 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -30,7 +30,6 @@ import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; import nodomain.freeyourgadget.gadgetbridge.externalevents.AlarmClockReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.AlarmReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.BluetoothConnectReceiver; -import nodomain.freeyourgadget.gadgetbridge.externalevents.K9Receiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.MusicPlaybackReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.PebbleReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.PhoneCallReceiver; @@ -148,7 +147,6 @@ public class DeviceCommunicationService extends Service implements SharedPrefere private PhoneCallReceiver mPhoneCallReceiver = null; private SMSReceiver mSMSReceiver = null; - private K9Receiver mK9Receiver = null; private PebbleReceiver mPebbleReceiver = null; private MusicPlaybackReceiver mMusicPlaybackReceiver = null; private TimeChangeReceiver mTimeChangeReceiver = null; @@ -586,13 +584,6 @@ public class DeviceCommunicationService extends Service implements SharedPrefere mSMSReceiver = new SMSReceiver(); registerReceiver(mSMSReceiver, new IntentFilter("android.provider.Telephony.SMS_RECEIVED")); } - if (mK9Receiver == null) { - mK9Receiver = new K9Receiver(); - IntentFilter filter = new IntentFilter(); - filter.addDataScheme("email"); - filter.addAction("com.fsck.k9.intent.action.EMAIL_RECEIVED"); - registerReceiver(mK9Receiver, filter); - } if (mPebbleReceiver == null) { mPebbleReceiver = new PebbleReceiver(); registerReceiver(mPebbleReceiver, new IntentFilter("com.getpebble.action.SEND_NOTIFICATION")); @@ -637,10 +628,6 @@ public class DeviceCommunicationService extends Service implements SharedPrefere unregisterReceiver(mSMSReceiver); mSMSReceiver = null; } - if (mK9Receiver != null) { - unregisterReceiver(mK9Receiver); - mK9Receiver = null; - } if (mPebbleReceiver != null) { unregisterReceiver(mPebbleReceiver); mPebbleReceiver = null; 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 4527299a2..772167a23 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 @@ -457,7 +457,7 @@ public class PebbleProtocol extends GBDeviceProtocol { String title; String subtitle = null; - // for SMS and EMAIL that came in though SMS or K9 receiver + // for SMS that came in though the SMS receiver if (notificationSpec.sender != null) { title = notificationSpec.sender; subtitle = notificationSpec.subject; diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 86095992e..77484bacb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -74,7 +74,6 @@ Repetitions Phone Calls SMS - K9-Mail Pebble Messages Support for applications which send Notifications to the Pebble via PebbleKit. Generic notification support diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index d558fa4b4..b44383c6b 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -104,14 +104,6 @@ android:title="@string/pref_title_notifications_sms" android:summary="%s" /> - - Date: Fri, 10 Feb 2017 00:32:03 +0100 Subject: [PATCH 28/53] Implement hashCode() when you implement equals()! --- .../gadgetbridge/model/MusicStateSpec.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicStateSpec.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicStateSpec.java index f9d070eb8..c960b149d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicStateSpec.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicStateSpec.java @@ -43,4 +43,15 @@ public class MusicStateSpec { this.shuffle == stateSpec.shuffle && this.repeat == stateSpec.repeat; } + + @Override + public int hashCode() { + int result = (int) state; +// ignore the position -- it is taken into account in equals() +// result = 31 * result + position; + result = 31 * result + playRate; + result = 31 * result + (int) shuffle; + result = 31 * result + (int) repeat; + return result; + } } From 0042ffc5140a4b46bcf95792f803c6b590920a89 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Fri, 10 Feb 2017 22:52:55 +0100 Subject: [PATCH 29/53] Set the notification ID on alarm start --- .../gadgetbridge/externalevents/AlarmClockReceiver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmClockReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmClockReceiver.java index b01707c99..96a07295e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmClockReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmClockReceiver.java @@ -48,7 +48,7 @@ public class AlarmClockReceiver extends BroadcastReceiver { lastId = generateId(); NotificationSpec spec = new NotificationSpec(); spec.type = NotificationType.GENERIC_ALARM_CLOCK; - spec.id = -1; + spec.id = lastId; // can we get the alarm title somehow? GBApplication.deviceService().onNotification(spec); } From ee28ccd4fe37bc8190a0f0ac978999a60cbe022e Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Fri, 10 Feb 2017 23:06:34 +0100 Subject: [PATCH 30/53] Pebble: add a dev option to always and immediately ACK PebbleKit messages to the watch Might help #509 --- .../devices/pebble/PebbleIoThread.java | 1 + .../devices/pebble/PebbleKitSupport.java | 10 ++++++---- .../devices/pebble/PebbleProtocol.java | 19 +++++++++++++------ app/src/main/res/values/strings.xml | 2 ++ app/src/main/res/xml/preferences.xml | 5 +++++ 5 files changed, 27 insertions(+), 10 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 f4e6e31e9..35c1c2564 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 @@ -85,6 +85,7 @@ class PebbleIoThread extends GBDeviceIoThread { mBtAdapter = btAdapter; mPebbleSupport = pebbleSupport; mEnablePebblekit = prefs.getBoolean("pebble_enable_pebblekit", false); + mPebbleProtocol.setAlwaysACKPebbleKit(prefs.getBoolean("pebble_always_ack_pebblekit", false)); } private int readWithException(InputStream inputStream, byte[] buffer, int byteOffset, int byteCount) throws IOException { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleKitSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleKitSupport.java index 6d05dc8c2..2277d1ca2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleKitSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleKitSupport.java @@ -64,10 +64,12 @@ class PebbleKitSupport { break; case PEBBLEKIT_ACTION_APP_ACK: transaction_id = intent.getIntExtra("transaction_id", -1); - if (transaction_id >= 0 && transaction_id <= 255) { - mPebbleIoThread.write(mPebbleProtocol.encodeApplicationMessageAck(null, (byte) transaction_id)); - } else { - LOG.warn("illegal transaction id " + transaction_id); + if (!mPebbleProtocol.mAlwaysACKPebbleKit) { + if (transaction_id >= 0 && transaction_id <= 255) { + mPebbleIoThread.write(mPebbleProtocol.encodeApplicationMessageAck(null, (byte) transaction_id)); + } else { + LOG.warn("illegal transaction id " + transaction_id); + } } break; 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 772167a23..6d1e93c19 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 @@ -253,6 +253,7 @@ public class PebbleProtocol extends GBDeviceProtocol { private static final Random mRandom = new Random(); int mFwMajor = 3; + boolean mAlwaysACKPebbleKit = false; private boolean mForceProtocol = false; private GBDeviceEventScreenshot mDevEventScreenshot = null; private int mScreenshotRemaining = -1; @@ -1833,16 +1834,17 @@ public class PebbleProtocol extends GBDeviceProtocol { jsonArray.put(jsonObject); } - // this is a hack we send an ack to the Pebble immediately because we cannot map the transaction_id from the intent back to a uuid yet - /* - GBDeviceEventSendBytes sendBytesAck = new GBDeviceEventSendBytes(); - sendBytesAck.encodedBytes = encodeApplicationMessageAck(uuid, last_id); - */ + GBDeviceEventSendBytes sendBytesAck = null; + if (mAlwaysACKPebbleKit) { + // this is a hack we send an ack to the Pebble immediately because somebody said it helps some PebbleKit apps :P + sendBytesAck = new GBDeviceEventSendBytes(); + sendBytesAck.encodedBytes = encodeApplicationMessageAck(uuid, last_id); + } GBDeviceEventAppMessage appMessage = new GBDeviceEventAppMessage(); appMessage.appUUID = uuid; appMessage.id = last_id & 0xff; appMessage.message = jsonArray.toString(); - return new GBDeviceEvent[]{appMessage}; + return new GBDeviceEvent[]{appMessage, sendBytesAck}; } byte[] encodeApplicationMessagePush(short endpoint, UUID uuid, ArrayList> pairs) { @@ -2584,6 +2586,11 @@ public class PebbleProtocol extends GBDeviceProtocol { mForceProtocol = force; } + void setAlwaysACKPebbleKit(boolean alwaysACKPebbleKit) { + LOG.info("setting always ACK Pebbleit to " + alwaysACKPebbleKit); + mAlwaysACKPebbleKit = alwaysACKPebbleKit; + } + private String getFixedString(ByteBuffer buf, int length) { byte[] tmp = new byte[length]; buf.get(tmp, 0, length); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 77484bacb..3bed06a37 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -149,6 +149,8 @@ If your Pebble 2/Pebble LE does not work as expected, try this setting to limit the MTU (valid range 20–512) Enable Watch App Logging Will cause logs from watch apps to be logged by Gadgetbridge (requires reconnect) + Prematurely ACK PebbleKit + Will cause messages that are sent to external 3rd party apps to be acknowledged always and immediately Reconnection Attempts diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index b44383c6b..d324fa3a1 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -386,6 +386,11 @@ android:key="pebble_enable_applogs" android:summary="@string/pref_summary_pebble_enable_applogs" android:title="@string/pref_title_pebble_enable_applogs" /> + Date: Fri, 10 Feb 2017 23:11:21 +0100 Subject: [PATCH 31/53] Pebble: make sure to not display "open on phone" and "dismiss" when the source of a notification was our AlarmClockReceiver --- .../gadgetbridge/externalevents/AlarmClockReceiver.java | 1 + .../gadgetbridge/service/devices/pebble/PebbleProtocol.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmClockReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmClockReceiver.java index 96a07295e..aa102be83 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmClockReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AlarmClockReceiver.java @@ -49,6 +49,7 @@ public class AlarmClockReceiver extends BroadcastReceiver { NotificationSpec spec = new NotificationSpec(); spec.type = NotificationType.GENERIC_ALARM_CLOCK; spec.id = lastId; + spec.sourceName = "ALARMCLOCKRECEIVER"; // can we get the alarm title somehow? GBApplication.deviceService().onNotification(spec); } 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 6d1e93c19..acc58cf0f 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 @@ -574,7 +574,7 @@ public class PebbleProtocol extends GBDeviceProtocol { byte dismiss_action_id; - if (hasHandle) { + if (hasHandle && !"ALARMCLOCKRECEIVER".equals(sourceName)) { actions_count = 3; dismiss_string = "Dismiss"; dismiss_action_id = 0x02; From 5dfd40062fab68b7a390e9f8970e73bf139f97cb Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Fri, 10 Feb 2017 23:16:22 +0100 Subject: [PATCH 32/53] fix previous commit --- .../gadgetbridge/service/devices/pebble/PebbleProtocol.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 acc58cf0f..f3ae7825f 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 @@ -654,7 +654,7 @@ public class PebbleProtocol extends GBDeviceProtocol { buf.put(dismiss_string.getBytes()); // open and mute actions - if (hasHandle) { + if (hasHandle && !"ALARMCLOCKRECEIVER".equals(sourceName)) { buf.put((byte) 0x01); buf.put((byte) 0x02); // generic buf.put((byte) 0x01); // number attributes @@ -892,7 +892,7 @@ public class PebbleProtocol extends GBDeviceProtocol { } byte dismiss_action_id; - if (hasHandle) { + if (hasHandle && !"ALARMCLOCKRECEIVER".equals(sourceName)) { actions_count = 3; dismiss_string = "Dismiss"; dismiss_action_id = 0x02; @@ -979,7 +979,7 @@ public class PebbleProtocol extends GBDeviceProtocol { buf.put(dismiss_string.getBytes()); // open and mute actions - if (hasHandle) { + if (hasHandle && !"ALARMCLOCKRECEIVER".equals(sourceName)) { buf.put((byte) 0x01); buf.put((byte) 0x02); // generic action buf.put((byte) 0x01); // number attributes From fea31924ba0148e72fcccf698fd29ed5e1d49e4a Mon Sep 17 00:00:00 2001 From: Avamander Date: Sat, 11 Feb 2017 10:49:01 +0200 Subject: [PATCH 33/53] Music data handling improvements (#550) * Fixed extracting the track length. * Added current track and total track count. * Few small changes to make sure everything gets updated properly. * Remove unnecessary includes. --- .../externalevents/MusicPlaybackReceiver.java | 28 +++++++++++-------- .../service/DeviceCommunicationService.java | 16 ++++++++--- 2 files changed, 29 insertions(+), 15 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 9d6ee214a..6a84e42c2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/MusicPlaybackReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/MusicPlaybackReceiver.java @@ -15,7 +15,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; public class MusicPlaybackReceiver extends BroadcastReceiver { private static final Logger LOG = LoggerFactory.getLogger(MusicPlaybackReceiver.class); private static MusicSpec lastMusicSpec = new MusicSpec(); - private static MusicStateSpec lastStatecSpec = new MusicStateSpec(); + private static MusicStateSpec lastStateSpec = new MusicStateSpec(); @Override public void onReceive(Context context, Intent intent) { @@ -28,7 +28,7 @@ public class MusicPlaybackReceiver extends BroadcastReceiver { } */ MusicSpec musicSpec = new MusicSpec(lastMusicSpec); - MusicStateSpec stateSpec = new MusicStateSpec(lastStatecSpec); + MusicStateSpec stateSpec = new MusicStateSpec(lastStateSpec); Bundle incomingBundle = intent.getExtras(); for (String key : incomingBundle.keySet()) { @@ -51,6 +51,14 @@ public class MusicPlaybackReceiver extends BroadcastReceiver { stateSpec.position = ((Long) incoming).intValue() / 1000; } else if (incoming instanceof Boolean && "playing".equals(key)) { stateSpec.state = (byte) (((Boolean) incoming) ? MusicStateSpec.STATE_PLAYING : MusicStateSpec.STATE_PAUSED); + } else if (incoming instanceof String && "duration".equals(key)) { + musicSpec.duration = Integer.valueOf((String) incoming) / 1000; + } else if (incoming instanceof String && "trackno".equals(key)) { + musicSpec.trackNr = Integer.valueOf((String) incoming); + } else if (incoming instanceof String && "totaltrack".equals(key)) { + musicSpec.trackCount = Integer.valueOf((String) incoming); + } else if (incoming instanceof Integer && "pos".equals(key)) { + stateSpec.position = (Integer) incoming; } } @@ -59,17 +67,15 @@ public class MusicPlaybackReceiver extends BroadcastReceiver { LOG.info("Update Music Info: " + musicSpec.artist + " / " + musicSpec.album + " / " + musicSpec.track); GBApplication.deviceService().onSetMusicInfo(musicSpec); } else { - LOG.info("got metadata changed intent, but nothing changed, ignoring."); + LOG.info("Got metadata changed intent, but nothing changed, ignoring."); } - if (intent.hasExtra("position") && intent.hasExtra("playing")) { - if (!lastStatecSpec.equals(stateSpec)) { - LOG.info("Update Music State: state=" + stateSpec.state + ", position= " + stateSpec.position); - GBApplication.deviceService().onSetMusicState(stateSpec); - } else { - LOG.info("got state changed intent, but not enough has changed, ignoring."); - } - lastStatecSpec = stateSpec; + if (!lastStateSpec.equals(stateSpec)) { + lastStateSpec = stateSpec; + LOG.info("Update Music State: state=" + stateSpec.state + ", position= " + stateSpec.position); + GBApplication.deviceService().onSetMusicState(stateSpec); + } else { + LOG.info("Got state changed intent, but not enough has changed, ignoring."); } } } 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 5e5315c72..04206e8d1 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -156,6 +156,15 @@ public class DeviceCommunicationService extends Service implements SharedPrefere private AlarmReceiver mAlarmReceiver = null; private Random mRandom = new Random(); + private final String[] mMusicActions = { + "com.android.music.metachanged", + "com.android.music.playstatechanged", + "com.android.music.queuechanged", + "com.android.music.playbackcomplete", + "net.sourceforge.subsonic.androidapp.EVENT_META_CHANGED", + "com.maxmpz.audioplayer.TPOS_SYNC", + "com.maxmpz.audioplayer.STATUS_CHANGED",}; + /** * For testing! * @@ -591,10 +600,9 @@ public class DeviceCommunicationService extends Service implements SharedPrefere if (mMusicPlaybackReceiver == null) { mMusicPlaybackReceiver = new MusicPlaybackReceiver(); IntentFilter filter = new IntentFilter(); - filter.addAction("com.android.music.metachanged"); - filter.addAction("com.android.music.playstatechanged"); - filter.addAction("com.android.music.playbackcomplete"); - filter.addAction("net.sourceforge.subsonic.androidapp.EVENT_META_CHANGED"); + for (String action : mMusicActions){ + filter.addAction(action); + } registerReceiver(mMusicPlaybackReceiver, filter); } if (mTimeChangeReceiver == null) { From 3936a7d8a0f6b6cf9ef96ac8ffddaccaebac513a Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 11 Feb 2017 22:34:04 +0100 Subject: [PATCH 34/53] update all languages from transifex (THANKS) French changes merged by a PR are overwritten though this. We didn't have a solution from that - so I will just rely on transifex - sorry. --- app/src/main/res/values-de/strings.xml | 1 - app/src/main/res/values-es/strings.xml | 19 ++++- app/src/main/res/values-fr/strings.xml | 103 ++++++++++++++++--------- app/src/main/res/values-hu/strings.xml | 1 - app/src/main/res/values-it/strings.xml | 2 - app/src/main/res/values-ja/strings.xml | 3 +- app/src/main/res/values-ko/strings.xml | 1 - app/src/main/res/values-pl/strings.xml | 1 - app/src/main/res/values-ru/strings.xml | 1 - app/src/main/res/values-uk/strings.xml | 1 - 10 files changed, 88 insertions(+), 45 deletions(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 846d85b28..3a714eff7 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -56,7 +56,6 @@ Wiederholungen Anrufe SMS - K9-Mail Pebble Nachrichten Unterstützung für Anwendungen die Benachrichtigungen an die Pebble via PebbleKit senden. Andere Benachrichtigungen diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 850612101..8ee6275dd 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -62,7 +62,6 @@ Repeticiones Llamadas telefónicas SMS - K9-Mail Mensajes de Pebble Soporte para aplicaciones que envían notificaciones a Pebble a través de PebbleKit. Soporte para notificaciones genéricas @@ -74,6 +73,11 @@ siempre cuando la pantalla está apagada nunca + Privacidad + Modo de privacidad de llamada + Mostrar nombre y número + Ocultar nombre pero mostrar número + Ocultar nombre y número Excluir aplicaciones Mensajes predeterminados Respuestas @@ -97,6 +101,9 @@ Eliminar automáticamente las notificaciones rechazadas Las notificaciones se borran automáticamente de Pebble cuando son rechazadas en Android Modo privado + Notificación normal + Desplaza la notificación fuera de la pantalla + Muestra solo el icono de notificación Localización Buscar localización Latitud @@ -116,6 +123,11 @@ Activar crear registros de la App del Reloj Producirá registros de las apps del reloj que Gadgetbridge guardará (necesita reconexión) Intentos de reconexión + Unidades + Formato de hora + Tiempo de pantalla encendida + Medición del ritmo cardíaco todo el día + Ajustes de HPlus/Makibes no conectado conectando conectado @@ -341,4 +353,9 @@ Por favor, ten en cuenta que puedes importar datos desde Mi Band, Pebble Health Asegúrate de que este tema esté activado en la aplicación de notificación del tiempo para obtener la información en tu Pebble.\n\nNo se requiere configuración.\n\nPuedes activar la aplicación del tiempo del sistema desde la configuración de la app.\n\nLas watchfaces soportadas mostrarán la información del tiempo automáticamente. Activar el emparejamiento Bluetooth Desactiva esto si tienes problemas de conexión + Métrica + Imperial + 24H + AM/PM + Despertador diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 46d61389c..411ee1609 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -27,6 +27,9 @@ Désactiver Activer la mesure du rythme cardiaque Désactiver la mesure du rythme cardiaque + Activer l\'application météo du système + Désactiver l\'application météo du système + Installer l\'application de notification de la météo Configurer Haut de page @@ -37,7 +40,7 @@ Vous êtes sur le point d\'installer les micrologiciels %1$s et %2$s à la place de ceux qui sont actuellement sur votre Mi Band. Ce micrologiciel a été testé et est connu pour être compatible avec Gadgetbridge. Ce micrologiciel n\'a pas été testé et peut ne pas être compatible avec Gadgetbridge.\n\nIl n\'est pas conseillé de le flasher sur votre Mi Band. - Si vous désirez continuer et que tout fonctionne correctement par la suite, SVP informez-en les développeurs de Gadgetbridge pour demander l\'ajout de ce micrologiciel à leur liste: %s + Si vous désirez continuer et que tout fonctionne correctement par la suite, veuillez en informer les développeurs de Gadgetbridge pour demander l\'ajout de ce micrologiciel à leur liste: %s Paramètres Paramètres généraux @@ -52,20 +55,29 @@ Clair Sombre Langue + Masquer la notification de Gadgetbridge + L\'icône de la barre d\'état et la notification de l\'écran de verrouillage sont affichées + L\'icône de la barre d\'état et la notification de l\'écran de verrouillage sont masquées Notifications Répétitions Appels téléphoniques Textos - K9-Mail Messages Pebble Support des applications qui envoient des notification à Pebble par PebbleKit. Support des notifications génériques ... y compris quand l\'écran est allumé Ne Pas Déranger Arrêter l’envoi des notifications non-désirées en mode Ne Pas Déranger. + Transcription + À utiliser si l\'appareil ne supporte pas la police de caractères (pour l\'instant seulement le Cyrillique) toujours quand l\'écran est éteint jamais + Confidentialité + Mode de confidentialité d\'appel + Afficher le nom et le numéro + Masquer le nom mais afficher le numéro + Masquer le nom et le numéro Applications bloquées Modèles de messages Réponses @@ -80,10 +92,18 @@ Synchroniser Pebble Health Synchroniser Misfit Synchroniser Morpheuz + Support des appels sortants + Désactiver ceci empêchera la Pebble 2/LE de vibrer lors des appels sortants Permettre l\'accès aux applications tierces Android Activer le support expérimental pour les applications Android utilisant PebbleKit Lever et coucher de soleil Envoyer les heures de lever et coucher du soleil dans l’historique Pebble en fonction de l\'emplacement + Effacer automatiquement les notifications rejetées + Les notifications sont automatiquement effacées de la Pebble lorsqu\'elles sont rejetées sur l\'appareil Android + Mode privé + Notifications normales + Déplace les notifications hors de l\'écran + Ne montre que l\'icône de notification Emplacement Obtenir l\'emplacement Latitude @@ -97,12 +117,17 @@ Activer les fonctionnalités non-testées Activer les fonctionnalités non-testées. ACTIVEZ UNIQUEMENT SI VOUS SAVEZ CE QUE VOUS FAITES! Toujours préférer le BLE - Utiliser le support expérimental du LE pour toutes les Pebble au lieu du Bluetooth classique ; cela requiert l’appairage d\'une \"Pebble LE\" après qu’une non-LE ai déjà été connectée + Utiliser le support expérimental du LE pour toutes les Pebble au lieu du Bluetooth classique ; cela requiert l’appairage d\'une \"Pebble LE\" après qu’une non-LE ait déjà été connectée Limite du GATT MTU de Pebble 2/LE Si votre Pebble 2/LE ne fonctionne pas correctement, essayez d\'activer cette option pour limiter le MTU (plage valide 20-512) Activer les logs des Watch App Ceci permettra à Gadgetbridge de conserver les logs des Watch App (requiert une reconnexion) Tentatives de reconnexion + Unités + Format de l\'heure + Durée d\'écran allumé + Mesure de la fréquence cardiaque toute la journée + Paramètres HPlus/Makibes non connecté connexion en cours connecté @@ -118,13 +143,13 @@ Cliquez sur l\'appareil pour ouvrir le gestionnaire d\'application Cliquez sur l\'appareil pour ouvrir le gestionnaire d’activité Cliquez sur connecter pour envoyer une vibration - Tapotter sur le périphérique pour le connecter. + Tapottez sur le périphérique pour le connecter. Connexion impossible. L’adresse Bluetooth est-elle valide? Gadgetbridge est en fonctionnement Installation du fichier %1$d/%2$d échec de l\'installation ! Installation réalisée avec succès - VOUS TENTEZ D\'INSTALLER UN MICROLOGICIEL, PROCÉDEZ À VOS PROPRES RISQUES.\n\n\nCe micrologiciel est pour la version de matériel: %s + VOUS TENTEZ D\'INSTALLER UN MICROLOGICIEL, PROCÉDEZ À VOS RISQUES ET PÉRILS.\n\n\nCe micrologiciel est pour la version de matériel: %s Vous êtes sur le point d\'installer l\'application suivante:\n\n\n%1$s Version %2$s par %3$s\n N.D. Initialisé @@ -236,13 +261,13 @@ Ne pas confirmer le transfert de données d\'activités Les données d\'activités ne seront pas effacées du bracelet si elles ne sont pas confirmées. Utile si GB est utilisé avec d\'autres applications. Les données d\'activités seront conservées sur le Mi Band après la synchronisation. Utile si GB est utilisé avec d\'autres applications. - Utilisez le mode low-latency pour les mises à jour FW - Cela peu aider sur les appareils où les mises à jour du firmware échouent + Utilisez le mode basse latence pour les mises à jour du micrologiciel + Cela peut aider sur les appareils où les mises à jour du micrologiciel échouent Historique de pas Pas/minute actuel Nombre total de pas Historique de pas/minute - Démarrer votre activité + Démarrez votre activité Activité Sommeil léger Sommeil profond @@ -253,15 +278,15 @@ Micrologiciel non compatible Ce micrologiciel n\'est pas compatible avec l\'appareil Alarmes à réserver pour événements futurs - Utiliser le capteur cardiaque pour améliorer la précision du sommeil - La compensation de temps en heure (pour détecter le sommeil de travailleurs en rotation, par exemple) + Utiliser le capteur cardiaque pour améliorer la détection du sommeil + La compensation de temps en heure (pour travailleurs en rotation, par exemple) Mi2 : Format de la date Heure Allumer l\'écran lors d\'un mouvement Sur le point de transférer des données depuis %1$s en attente de reconnexion - A propos de vous + À propos de vous Année de naissance Genre Taille en cm @@ -276,50 +301,50 @@ Micrologiciel: %1$s Erreur à la création de votre fichier log : %1$s HR: - Le firmware se met à jour + Le micrologiciel se met à jour Échec lors de l\'écriture du micrologiciel Rythme cardiaque Rythme cardiaque Importer la base de donnée - Importer des données d\'activité ancienne + Importer des données d\'activité anciennes Depuis Gadgetbridge 0.12.0, nous utilisons un nouveau format de base de données. -Vous êtes en mesure d\'importer des données d\'activité ancienne et l\'associer à l\'appareil que vous vous connectez à (%1$s).\n +Vous êtes en mesure d\'importer des données d\'activité anciennes et de les associer à l\'appareil auquel vous vous connectez (%1$s).\n \n -Si vous ne voulez pas importer les anciennes données maintenant, vous pouvez toujours le faire plus tard en appuyant sur le bouton FUSIONNER LES ANCIENNES DONNÉES D’ACTIVITÉ » dans le Gestionnaire de base de données\n +Si vous ne voulez pas importer les anciennes données maintenant, vous pouvez toujours le faire plus tard en appuyant sur le bouton \"FUSIONNER LES ANCIENNES DONNÉES D’ACTIVITÉ\" dans le gestionnaire de base de données\n \n Notez que vous pouvez importer des données de Mi Band, Pebble Health et Morpheuz mais PAS de Pebble Misfit. - Stockez les enregistrement brut dans la base de données - Si coché, les données sont stockées \"tel quel\" et seront disponible pour interprétation ultérieurement (lorsque-nous serons en mesure de mieux les comprendre). -NOTE : la base de données sera bien évidement plus grande ! + Stockez les enregistrements brut dans la base de données + Si coché, les données sont stockées \"telles quelles\" et seront disponibles pour une interprétation ultérieure. +NOTE: la base de données sera bien évidement plus grande ! Gestion de base de données Gestion de base de données - Les opérations sur la base de donnée ont utilisé le chemin suivant sur votre appareil.\n Ce chemin n\'est pas accessible par d\'autres applications Android ou par votre ordinateur./nBase de donnée à attendu (Vous pouvez mettre aussi la base de donnée que vous souhaitez importer ici) : - Les données d\'activité enregistrées avec les versions antérieures à la 0.12 de Gadgetbridge doivent être convertis en un nouveau format.\n + Les opérations sur la base de donnée ont utilisé le chemin suivant sur votre appareil.\n Ce chemin n\'est pas accessible par d\'autres applications Android ou par votre ordinateur./nVous trouverez votre base de données (ou celle que vous souhaitez importer) ici: + Les données d\'activité enregistrées avec les versions antérieures à la 0.12 de Gadgetbridge doivent être converties en un nouveau format.\n Vous pouvez le faire en utilisant le bouton ci-dessous. Soyez conscient que vous devez être connecté à l\'appareil que vous souhaitez associer avec les anciennes données d\'activité !\n Si vous avez déjà importé vos données et êtes satisfait du résultat, vous pouvez supprimer l\'ancienne base de données. - Import / Suppression des anciennes Base de Données. + Import / Suppression des anciennes bases de données. Impossible d\'accéder au fichier d\'export. Merci de contacter les développeurs. Exporter vers : %1$s Erreur d\'exportation BD: %1$s Importer des données ? - Voulez vous vraiment effacer la base de donnée actuel ? Toutes vos données (si vous en avez) seront perdu. - Importation réussit. + Voulez-vous vraiment effacer la base de données actuelle ? Toutes vos données (si vous en avez) seront perdues. + Importation réussie. Erreur lors de l\'importation BD: %1$s - Aucune ancienne base de donnée trouvé, rien à importer. - Pas d\'appareil connecté à associer avec l\'ancienne base de donnée. - Fusion des données d\'activités + Aucune ancienne base de données trouvée, rien à importer. + Pas d\'appareil connecté à associer avec l\'ancienne base de données. + Fusion des données d\'activité Merci d\'attendre pendant la fusion de vos données. - Échec de l\'import des anciennes données d\'activité dans la nouvelle base de donnée. - Association des ancienne donnée avec le nouvel appareil. - Détruire les ancienne données ? - Voulez vous vraiment détruire entièrement la base de donnée ? Toutes vos données d\'activités et vos informations issus de vos appareils seront perdu. + Échec de l\'import des anciennes données d\'activité dans la nouvelle base de données. + Association des anciennes données avec le nouvel appareil. + Détruire les anciennes données ? + Voulez-vous vraiment détruire entièrement la base de données ? Toutes vos données d\'activité et vos informations issues de vos appareils seront perdues. Les données ont été effacées. - Échec de la destruction de la base de donnée. - Voulez vous détruire les anciennes activités de la base ? - Voulez vous vraiment détruire entièrement la base de donnée ? Toutes vos données non importé seront perdu. - Les anciennes données d\'activité ont été effacées correctement. - Échec de la destruction de l\'ancienne base de donnée. + Échec de la destruction de la base de données. + Voulez-vous détruire les anciennes activités de la base de données ? + Voulez-vous vraiment détruire entièrement la base de données ? Toutes vos données non importées seront perdues. + Les anciennes données d\'activité ont été correctement effacées. + Échec de la destruction de l\'ancienne base de données. Écraser Annuler Supprimer @@ -328,4 +353,12 @@ Si vous avez déjà importé vos données et êtes satisfait du résultat, vous Appairage avec une Pebble Une fenêtre d’appairage va s’afficher sur votre téléphone. Si cela ne se produit pas, regardez dans vos notifications et acceptez la demande d’appairage. Acceptez ensuite la demande d’appairage sur votre Pebble. + Assurez vous que ce thème soit activé dans l\'application de notification de la météo pour recevoir les informations sur votre Pebble.\n\nAucune configuration n\'est requise.\n\nVous pouvez activer l\'application météo système de votre Pebble depuis la configuration de l\'application.\n\nLes watchfaces supportées afficheront la météo automatiquement. + Activer l\'appairage Bluetooth + Désactivez ceci si vous avez des problèmes de connexion + Mesure + Impériale + 24H + AM/PM + Réveil diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 6c9eec168..7a3e39eae 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -56,7 +56,6 @@ Ismétlések Telefonhívások SMS - K9-Mail Pebble üzenetek Támogatás az alkalmazásoknak, amik értesítéseket küldenek a Pebble-nek a PebbleKit-en keresztül. Általános értesítési támogatás diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 80fe82417..17d93a81e 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -54,14 +54,12 @@ Chiaro Scuro Lingua - Nascondi la notifica di gadgetbridge L\'icona nella barra di stato e la notifica nella schermata di blocco vengono mostrate L\'icona nella barra di stato e la notifica nella schermata di blocco non vengono mostrate Notifiche Ripetizioni Chiamate telefoniche SMS - K9-Mail Messaggi Pebble Supporto per applicazioni che inviano le notifiche a Pebble usando PebbleKit. Notifiche generiche diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index a49252046..2572526ae 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -62,7 +62,6 @@ 繰り返し 電話通知 SMS - K9メール Pebbleメッセージ PebbleKit経由でPebbleに通知を送信するアプリケーションをサポートします。 一般ステータス通知対応 @@ -123,6 +122,8 @@ Pebble 2/Pebble LE が期待どおりに機能しない場合は、この設定を試して MTU を制限してください (有効範囲 20-512) ウォッチアプリのログ記録を有効にする Gadgetbridgeがウォッチアプリからログを記録するようにする (再接続が必要です) + 早期 ACK PebbleKit + 外部のサードパーティアプリケーションに送信されたメッセージは、常に即座に承認されます 再接続の試行 単位 時刻形式 diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 2f42f669e..5873f5b27 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -44,7 +44,6 @@ 반복 전화 SMS - K-9 메일 Pebble 메세지 일반적인 알림 지원 … 화면이 켜져있을 때도 diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 2a4484ce2..5364165ae 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -55,7 +55,6 @@ Powtórzenia Połączenia SMS - K9-Mail Wiadomości Pebble Obsługa ogólnych powiadomień ... także gdy ekran jest włączony diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 2ed467a6b..fe2315c57 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -46,7 +46,6 @@ Повторы Вызовы СМС-сообщения - K9-Mail Сообщения Pebble Поддержка обычных уведомлений … даже когда экран включён diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 1d966d845..57f1da2e4 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -44,7 +44,6 @@ Повтори Виклики SMS—повідомлення - K9-Mail Повідомлення Pebble Підтримка звичайних сповіщень … навіть коли екран увімкнено From c851f73265894af2c506fe9bf27f475f175abbd7 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 11 Feb 2017 22:42:39 +0100 Subject: [PATCH 35/53] update CHANGELOG --- CHANGELOG.md | 5 ++++- app/src/main/res/xml/changelog_master.xml | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a3ce44cd..25eb027e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,13 @@ ###Changelog -####Version 0.17.4 (next) +####Version 0.17.4 * Better integration with android music players * Privacy options for calls (hide caller name/number) +* Send a notification to the connected if the Android Alarm Clock rings (com.android.deskclock) +* Fixes for cyrillic transliteration * Pebble: Implement notification privacy modes * Pebble: Support weather for Obisdian watchface +* Pebble: add a dev option to always and immediately ACK PebbleKit messages to the watch * HPlus: Support alarms * HPlus: Fix time and date sync and time format (12/24) * HPlus: Add device specific preferences and icon diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml index b4d46f05c..7ab0440cd 100644 --- a/app/src/main/res/xml/changelog_master.xml +++ b/app/src/main/res/xml/changelog_master.xml @@ -3,8 +3,11 @@ Better integration with android music players Privacy options for calls (hide caller name/number) + Send a notification to the connected if the Android Alarm Clock rings (com.android.deskclock) + Fixes for cyrillic transliteration Pebble: Implement notification privacy modes Pebble: Support weather for Obisdian watchface + Pebble: add a dev option to always and immediately ACK PebbleKit messages to the watch HPlus: Support alarms HPlus: Fix time and date sync and time format (12/24) HPlus: Add device specific preferences and icon From b31dd9b2fa3758baf89d3a00df20866ff9521c15 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 11 Feb 2017 22:52:33 +0100 Subject: [PATCH 36/53] translate some strings to German --- app/src/main/res/values-de/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 3a714eff7..060540384 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -62,9 +62,15 @@ … auch wenn der Bildschirm an ist Bitte nicht stören Stoppe unerwünschte Nachrichten, wenn im \"Nicht Stören\"-Modus + Transliteration immer wenn der Bildschirm aus ist niemals + Privatsphäre + Privatsphäre-Modus für Anrufe + Zeige Name und Telefonnumer + Verstecke den Namen aber zeige die Telefonnummer an + Verstecke Name und Telefonnummer Sperre für Apps Vorgefertigte Nachrichten Antworten @@ -83,6 +89,10 @@ 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 + Privatsphäre-Modus + Normale Benachrichtigungen + Verschiebe den Benachrichttigungstext außerhalb des Bildschirms + Zeige nur das Benachrichtigungs-Symbol Standort Standort Bestimmen Breitengrad @@ -102,6 +112,8 @@ Watch App Logging einschalten Schreibt logs von Watch Apps in Gadgetbridge logs (Pebble muss nach Ändern der Option erneut verbunden werden) Neuverbindungsversuche + Einheiten + Zeitformat nicht verbunden verbinde verbunden @@ -308,4 +320,5 @@ Wenn Du schon deine Daten importiert hast und mit dem Ergebnis zufrieden bist, k Vibration + Wecker From 1d1edd41d755cda7039e3dbc89ef68df8bd7e0b9 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 12 Feb 2017 23:12:42 +0100 Subject: [PATCH 37/53] Pebble 2/LE: remove a sleep which might be no longer necessary Will speedup data transfer --- .../service/devices/pebble/ble/PebbleGATTServer.java | 5 ----- .../service/devices/pebble/ble/PebbleLESupport.java | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/ble/PebbleGATTServer.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/ble/PebbleGATTServer.java index fd8637bb4..fba114624 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/ble/PebbleGATTServer.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/ble/PebbleGATTServer.java @@ -65,11 +65,6 @@ class PebbleGATTServer extends BluetoothGattServerCallback { writeCharacteristics.setValue(new byte[]{(byte) (((serial << 3) | 1) & 0xff)}); mBluetoothGattServer.notifyCharacteristicChanged(mBtDevice, writeCharacteristics, false); - - try { - Thread.sleep(100); // FIXME: bad bad, I mean BAAAD - } catch (InterruptedException ignore) { - } } public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/ble/PebbleLESupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/ble/PebbleLESupport.java index e13552d92..07ed20a56 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/ble/PebbleLESupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/ble/PebbleLESupport.java @@ -24,7 +24,7 @@ public class PebbleLESupport { private int mMTU = 20; private int mMTULimit = Integer.MAX_VALUE; boolean mIsConnected = false; - public CountDownLatch mPPAck; + CountDownLatch mPPAck; public PebbleLESupport(Context context, final BluetoothDevice btDevice, PipedInputStream pipedInputStream, PipedOutputStream pipedOutputStream) throws IOException { mBtDevice = btDevice; From a26563d6c7bc94cf91fb439ba99f57ad5e4d78a7 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Mon, 13 Feb 2017 22:27:37 +0100 Subject: [PATCH 38/53] Pebble: also acknowledge PebbleKit intents with transaction_id -1 I don't understand why this should be necessary but for some 3rd party apps it helps (#509) --- .../service/devices/pebble/PebbleKitSupport.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleKitSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleKitSupport.java index 2277d1ca2..441170047 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleKitSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleKitSupport.java @@ -55,9 +55,9 @@ class PebbleKitSupport { try { JSONArray jsonArray = new JSONArray(jsonString); mPebbleIoThread.write(mPebbleProtocol.encodeApplicationMessageFromJSON(uuid, jsonArray)); - if (transaction_id >= 0 && transaction_id <= 255) { - sendAppMessageAck(transaction_id); - } + // if (transaction_id >= 0 && transaction_id <= 255) { + sendAppMessageAck(transaction_id); + // } } catch (JSONException e) { e.printStackTrace(); } From 23f2dd35d44cda43439ea5e50b11f9c243100ca9 Mon Sep 17 00:00:00 2001 From: Avamander Date: Fri, 17 Feb 2017 10:01:37 +0200 Subject: [PATCH 39/53] Extract music shuffle and repeat states and set the song progress to auto-update. (#554) --- .../externalevents/MusicPlaybackReceiver.java | 13 +++++++++++++ .../gadgetbridge/model/MusicStateSpec.java | 8 ++++---- .../service/DeviceCommunicationService.java | 3 ++- 3 files changed, 19 insertions(+), 5 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 6a84e42c2..5afa67911 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/MusicPlaybackReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/MusicPlaybackReceiver.java @@ -51,6 +51,7 @@ public class MusicPlaybackReceiver extends BroadcastReceiver { stateSpec.position = ((Long) incoming).intValue() / 1000; } else if (incoming instanceof Boolean && "playing".equals(key)) { stateSpec.state = (byte) (((Boolean) incoming) ? MusicStateSpec.STATE_PLAYING : MusicStateSpec.STATE_PAUSED); + stateSpec.playRate = (byte) (((Boolean) incoming) ? 100 : 0); } else if (incoming instanceof String && "duration".equals(key)) { musicSpec.duration = Integer.valueOf((String) incoming) / 1000; } else if (incoming instanceof String && "trackno".equals(key)) { @@ -59,6 +60,18 @@ public class MusicPlaybackReceiver extends BroadcastReceiver { musicSpec.trackCount = Integer.valueOf((String) incoming); } else if (incoming instanceof Integer && "pos".equals(key)) { stateSpec.position = (Integer) incoming; + } else if (incoming instanceof Integer && "repeat".equals(key)) { + if ((Integer) incoming > 0) { + stateSpec.repeat = 1; + } else { + stateSpec.repeat = 0; + } + } else if (incoming instanceof Integer && "shuffle".equals(key)) { + if ((Integer) incoming > 0) { + stateSpec.shuffle = 1; + } else { + stateSpec.shuffle = 0; + } } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicStateSpec.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicStateSpec.java index c960b149d..eac51d930 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicStateSpec.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicStateSpec.java @@ -10,8 +10,8 @@ public class MusicStateSpec { public static final int STATE_UNKNOWN = 3; public byte state; - public int position; - public int playRate; + public int position; // Position of the current media in seconds + public int playRate; // Speed of playback, usually 0 or 100 (full speed) public byte shuffle; public byte repeat; @@ -47,8 +47,8 @@ public class MusicStateSpec { @Override public int hashCode() { int result = (int) state; -// ignore the position -- it is taken into account in equals() -// result = 31 * result + position; +//ignore the position -- it is taken into account in equals() +//result = 31 * result + position; result = 31 * result + playRate; result = 31 * result + (int) shuffle; result = 31 * result + (int) repeat; 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 04206e8d1..d88594e9c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -163,7 +163,8 @@ public class DeviceCommunicationService extends Service implements SharedPrefere "com.android.music.playbackcomplete", "net.sourceforge.subsonic.androidapp.EVENT_META_CHANGED", "com.maxmpz.audioplayer.TPOS_SYNC", - "com.maxmpz.audioplayer.STATUS_CHANGED",}; + "com.maxmpz.audioplayer.STATUS_CHANGED", + "com.maxmpz.audioplayer.PLAYING_MODE_CHANGED"}; /** * For testing! From e5d09b9fa2d358a66a897e84cbb3621934436c3b Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Fri, 17 Feb 2017 23:11:44 +0100 Subject: [PATCH 40/53] Automatically start the service on boot (can be turned off) Fixes #9 --- app/src/main/AndroidManifest.xml | 9 +++++++++ .../externalevents/AutoStartReceiver.java | 20 +++++++++++++++++++ .../gadgetbridge/util/GBPrefs.java | 6 ++++++ app/src/main/res/values/strings.xml | 1 + app/src/main/res/xml/preferences.xml | 4 ++++ 5 files changed, 40 insertions(+) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AutoStartReceiver.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bdbc78781..b4132de8f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -17,6 +17,7 @@ + + + + + + + + diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AutoStartReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AutoStartReceiver.java new file mode 100644 index 000000000..c6c194d07 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AutoStartReceiver.java @@ -0,0 +1,20 @@ +package nodomain.freeyourgadget.gadgetbridge.externalevents; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +import nodomain.freeyourgadget.gadgetbridge.GBApplication; + +public class AutoStartReceiver extends BroadcastReceiver { + private static final String TAG = AutoStartReceiver.class.getName(); + + @Override + public void onReceive(Context context, Intent intent) { + if (GBApplication.getGBPrefs().getAutoStart()) { + Log.i(TAG, "Boot completed, starting Gadgetbridge"); + GBApplication.deviceService().start(); + } + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GBPrefs.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GBPrefs.java index 024fb4426..4fc42f0f8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GBPrefs.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GBPrefs.java @@ -6,6 +6,8 @@ import java.util.Date; public class GBPrefs { public static final String AUTO_RECONNECT = "general_autocreconnect"; + private static final String AUTO_START = "general_autostartonboot"; + private static final boolean AUTO_START_DEFAULT = true; public static boolean AUTO_RECONNECT_DEFAULT = true; public static final String USER_NAME = "mi_user_alias"; @@ -22,6 +24,10 @@ public class GBPrefs { return mPrefs.getBoolean(AUTO_RECONNECT, AUTO_RECONNECT_DEFAULT); } + public boolean getAutoStart() { + return mPrefs.getBoolean(AUTO_START, AUTO_START_DEFAULT); + } + public String getUserName() { return mPrefs.getString(USER_NAME, USER_NAME_DEFAULT); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3bed06a37..a36191753 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -52,6 +52,7 @@ General Settings Connect to device when Bluetooth turned on + Start automatically Reconnect automatically Preferred Audioplayer Default diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index d324fa3a1..df84c17c5 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -3,6 +3,10 @@ + Date: Sun, 19 Feb 2017 22:59:37 +0100 Subject: [PATCH 41/53] Pebble: First shot at implementing dataloggin for PebbleKit apps Closes #497 Could help #316 --- .../pebble/GBDeviceEventDataLogging.java | 16 ++++++ .../devices/pebble/DatalogSession.java | 42 ++++++++++++++++ .../devices/pebble/PebbleIoThread.java | 9 ++++ .../devices/pebble/PebbleKitSupport.java | 50 +++++++++++++++++++ .../devices/pebble/PebbleProtocol.java | 40 +++++++++++---- 5 files changed, 148 insertions(+), 9 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/pebble/GBDeviceEventDataLogging.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/pebble/GBDeviceEventDataLogging.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/pebble/GBDeviceEventDataLogging.java new file mode 100644 index 000000000..971d99cc1 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/pebble/GBDeviceEventDataLogging.java @@ -0,0 +1,16 @@ +package nodomain.freeyourgadget.gadgetbridge.deviceevents.pebble; + +import java.util.UUID; + +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; + +public class GBDeviceEventDataLogging extends GBDeviceEvent { + public static final int COMMAND_RECEIVE_DATA = 1; + public static final int COMMAND_FINISH_SESSION = 2; + + public int command; + public UUID appUUID; + public long tag; + public byte pebbleDataType; + public Object data; +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSession.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSession.java index 2b07d944a..fc7291436 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSession.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSession.java @@ -1,9 +1,17 @@ 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.deviceevents.GBDeviceEvent; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.pebble.GBDeviceEventDataLogging; + class DatalogSession { + private static final Logger LOG = LoggerFactory.getLogger(DatalogSession.class); + final byte id; final int tag; final UUID uuid; @@ -26,4 +34,38 @@ class DatalogSession { String getTaginfo() { return taginfo; } + + GBDeviceEvent[] handleMessageForPebbleKit(ByteBuffer buf, int length) { + if (0 != (length % itemSize)) { + LOG.warn("invalid length"); + return null; + } + int packetCount = length / itemSize; + GBDeviceEvent[] gbDeviceEvents = new GBDeviceEvent[packetCount + 1]; // pad for ack + for (int i = 0; i < packetCount; i++) { + GBDeviceEventDataLogging dataLogging = new GBDeviceEventDataLogging(); + switch (itemType) { + case PebbleProtocol.TYPE_BYTEARRAY: + byte[] itemData = new byte[itemSize]; + buf.get(itemData); + dataLogging.data = itemData; + break; + + case PebbleProtocol.TYPE_UINT: + dataLogging.data = buf.getInt() & 0xffffffffL; + break; + + case PebbleProtocol.TYPE_INT: + dataLogging.data = buf.getInt(); + break; + } + + dataLogging.command = GBDeviceEventDataLogging.COMMAND_RECEIVE_DATA; + dataLogging.appUUID = uuid; + dataLogging.tag = tag; + dataLogging.pebbleDataType = itemType; + gbDeviceEvents[i] = dataLogging; + } + return gbDeviceEvents; + } } \ No newline at end of file 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 35c1c2564..4ec9cacb2 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 @@ -33,6 +33,7 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppManagement; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppMessage; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.pebble.GBDeviceEventDataLogging; import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PBWReader; import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleInstallable; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; @@ -86,6 +87,7 @@ class PebbleIoThread extends GBDeviceIoThread { mPebbleSupport = pebbleSupport; mEnablePebblekit = prefs.getBoolean("pebble_enable_pebblekit", false); mPebbleProtocol.setAlwaysACKPebbleKit(prefs.getBoolean("pebble_always_ack_pebblekit", false)); + mPebbleProtocol.setEnablePebbleKit(mEnablePebblekit); } private int readWithException(InputStream inputStream, byte[] buffer, int byteOffset, int byteCount) throws IOException { @@ -493,6 +495,13 @@ class PebbleIoThread extends GBDeviceIoThread { mPebbleKitSupport.sendAppMessageIntent((GBDeviceEventAppMessage) deviceEvent); } } + } else if (deviceEvent instanceof GBDeviceEventDataLogging) { + if (mEnablePebblekit) { + LOG.info("Got Datalogging event"); + if (mPebbleKitSupport != null) { + mPebbleKitSupport.sendDataLoggingIntent((GBDeviceEventDataLogging) deviceEvent); + } + } } return false; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleKitSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleKitSupport.java index 441170047..9f285de88 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleKitSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleKitSupport.java @@ -4,6 +4,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.util.Base64; import org.json.JSONArray; import org.json.JSONException; @@ -13,6 +14,7 @@ import org.slf4j.LoggerFactory; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppMessage; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.pebble.GBDeviceEventDataLogging; class PebbleKitSupport { //private static final String PEBBLEKIT_ACTION_PEBBLE_CONNECTED = "com.getpebble.action.PEBBLE_CONNECTED"; @@ -26,12 +28,20 @@ class PebbleKitSupport { private static final String PEBBLEKIT_ACTION_APP_START = "com.getpebble.action.app.START"; private static final String PEBBLEKIT_ACTION_APP_STOP = "com.getpebble.action.app.STOP"; + private static final String PEBBLEKIT_ACTION_DL_RECEIVE_DATA_NEW = "com.getpebble.action.dl.RECEIVE_DATA_NEW"; + private static final String PEBBLEKIT_ACTION_DL_RECEIVE_DATA = "com.getpebble.action.dl.RECEIVE_DATA"; + private static final String PEBBLEKIT_ACTION_DL_ACK_DATA = "com.getpebble.action.dl.ACK_DATA"; + private static final String PEBBLEKIT_ACTION_DL_REQUEST_DATA = "com.getpebble.action.dl.REQUEST_DATA"; + private static final String PEBBLEKIT_ACTION_DL_FINISH_SESSION = "com.getpebble.action.dl.FINISH_SESSION_NEW"; + private static final Logger LOG = LoggerFactory.getLogger(PebbleKitSupport.class); private final PebbleProtocol mPebbleProtocol; private final Context mContext; private final PebbleIoThread mPebbleIoThread; + private int dataLogTransactionId = 1; + private final BroadcastReceiver mPebbleKitReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -72,6 +82,9 @@ class PebbleKitSupport { } } break; + case PEBBLEKIT_ACTION_DL_ACK_DATA: + LOG.info("GOT DL DATA ACK"); + break; } } @@ -88,6 +101,7 @@ class PebbleKitSupport { intentFilter.addAction(PEBBLEKIT_ACTION_APP_SEND); intentFilter.addAction(PEBBLEKIT_ACTION_APP_START); intentFilter.addAction(PEBBLEKIT_ACTION_APP_STOP); + intentFilter.addAction(PEBBLEKIT_ACTION_DL_ACK_DATA); mContext.registerReceiver(mPebbleKitReceiver, intentFilter); } @@ -116,4 +130,40 @@ class PebbleKitSupport { } } + void sendDataLoggingIntent(GBDeviceEventDataLogging dataLogging) { + Intent intent = new Intent(); + intent.putExtra("data_log_timestamp", System.currentTimeMillis() / 1000); // is this data really not present in data from watch?! + intent.putExtra("uuid", dataLogging.appUUID); + intent.putExtra("data_log_uuid", dataLogging.appUUID); // Is that really the same? + intent.putExtra("data_log_tag", dataLogging.tag); + + switch (dataLogging.command) { + case GBDeviceEventDataLogging.COMMAND_RECEIVE_DATA: + intent.setAction(PEBBLEKIT_ACTION_DL_RECEIVE_DATA_NEW); + intent.putExtra("pbl_data_id", dataLogTransactionId++); + intent.putExtra("pbl_data_type", dataLogging.pebbleDataType); + switch (dataLogging.pebbleDataType) { + case PebbleProtocol.TYPE_BYTEARRAY: + intent.putExtra("pbl_data_object", Base64.encodeToString((byte[]) dataLogging.data, Base64.NO_WRAP)); + break; + case PebbleProtocol.TYPE_UINT: + intent.putExtra("pbl_data_object", (Long) dataLogging.data); + break; + case PebbleProtocol.TYPE_INT: + intent.putExtra("pbl_data_object", (Integer) dataLogging.data); + break; + } + LOG.info("broadcasting datalogging to uuid " + dataLogging.appUUID + " tag: " + dataLogging.tag + "transaction id: " + dataLogTransactionId + " type: " + dataLogging.pebbleDataType); + break; + case GBDeviceEventDataLogging.COMMAND_FINISH_SESSION: + intent.setAction(PEBBLEKIT_ACTION_DL_FINISH_SESSION); + LOG.info("broadcasting datalogging finish session to uuid " + dataLogging.appUUID + " tag: " + dataLogging.tag); + + break; + default: + LOG.warn("invalid datalog command"); + return; + } + mContext.sendBroadcast(intent); + } } 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 f3ae7825f..ce2529755 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 @@ -28,6 +28,7 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventNotificati import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventScreenshot; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.pebble.GBDeviceEventDataLogging; import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleIconID; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp; @@ -224,10 +225,10 @@ public class PebbleProtocol extends GBDeviceProtocol { private static final byte PHONEVERSION_REMOTE_OS_LINUX = 4; private static final byte PHONEVERSION_REMOTE_OS_WINDOWS = 5; - private static final byte TYPE_BYTEARRAY = 0; + static final byte TYPE_BYTEARRAY = 0; private static final byte TYPE_CSTRING = 1; - private static final byte TYPE_UINT = 2; - private static final byte TYPE_INT = 3; + static final byte TYPE_UINT = 2; + static final byte TYPE_INT = 3; private final short LENGTH_PREFIX = 4; @@ -253,6 +254,7 @@ public class PebbleProtocol extends GBDeviceProtocol { private static final Random mRandom = new Random(); int mFwMajor = 3; + boolean mEnablePebbleKit = false; boolean mAlwaysACKPebbleKit = false; private boolean mForceProtocol = false; private GBDeviceEventScreenshot mDevEventScreenshot = null; @@ -2212,10 +2214,11 @@ public class PebbleProtocol extends GBDeviceProtocol { return null; } - private GBDeviceEventSendBytes decodeDatalog(ByteBuffer buf, short length) { + private GBDeviceEvent[] decodeDatalog(ByteBuffer buf, short length) { boolean ack = true; byte command = buf.get(); byte id = buf.get(); + GBDeviceEvent[] devEvts = new GBDeviceEvent[1]; switch (command) { case DATALOG_TIMEOUT: LOG.info("DATALOG TIMEOUT. id=" + (id & 0xff) + " - ignoring"); @@ -2228,7 +2231,11 @@ public class PebbleProtocol extends GBDeviceProtocol { LOG.info("DATALOG SENDDATA. id=" + (id & 0xff) + ", items_left=" + items_left + ", total length=" + (length - 10)); if (datalogSession != null) { LOG.info("DATALOG UUID=" + datalogSession.uuid + ", tag=" + datalogSession.tag + datalogSession.getTaginfo() + ", itemSize=" + datalogSession.itemSize + ", itemType=" + datalogSession.itemType); - ack = datalogSession.handleMessage(buf, length - 10); + if (!datalogSession.uuid.equals(UUID_ZERO) && datalogSession.getClass().equals(DatalogSession.class) && mEnablePebbleKit) { + devEvts = datalogSession.handleMessageForPebbleKit(buf, length - 10); + } else { + ack = datalogSession.handleMessage(buf, length - 10); + } } break; case DATALOG_OPENSESSION: @@ -2255,7 +2262,15 @@ public class PebbleProtocol extends GBDeviceProtocol { break; case DATALOG_CLOSE: LOG.info("DATALOG_CLOSE. id=" + (id & 0xff)); - if (mDatalogSessions.containsKey(id)) { + datalogSession = mDatalogSessions.get(id); + if (datalogSession != null) { + if (!datalogSession.uuid.equals(UUID_ZERO) && datalogSession.getClass().equals(DatalogSession.class) && mEnablePebbleKit) { + GBDeviceEventDataLogging dataLogging = new GBDeviceEventDataLogging(); + dataLogging.command = GBDeviceEventDataLogging.COMMAND_FINISH_SESSION; + dataLogging.appUUID = datalogSession.uuid; + dataLogging.tag = datalogSession.tag; + devEvts = new GBDeviceEvent[]{dataLogging, null}; + } mDatalogSessions.remove(id); } break; @@ -2271,7 +2286,9 @@ public class PebbleProtocol extends GBDeviceProtocol { LOG.info("sending NACK (0x86)"); sendBytes.encodedBytes = encodeDatalog(id, DATALOG_NACK); } - return sendBytes; + // append ack/nack + devEvts[devEvts.length - 1] = sendBytes; + return devEvts; } private GBDeviceEvent decodeAppReorder(ByteBuffer buf) { @@ -2539,7 +2556,7 @@ public class PebbleProtocol extends GBDeviceProtocol { } break; case ENDPOINT_DATALOG: - devEvts = new GBDeviceEvent[]{decodeDatalog(buf, length)}; + devEvts = decodeDatalog(buf, length); break; case ENDPOINT_SCREENSHOT: devEvts = new GBDeviceEvent[]{decodeScreenshot(buf, length)}; @@ -2587,10 +2604,15 @@ public class PebbleProtocol extends GBDeviceProtocol { } void setAlwaysACKPebbleKit(boolean alwaysACKPebbleKit) { - LOG.info("setting always ACK Pebbleit to " + alwaysACKPebbleKit); + LOG.info("setting always ACK PebbleKit to " + alwaysACKPebbleKit); mAlwaysACKPebbleKit = alwaysACKPebbleKit; } + void setEnablePebbleKit(boolean enablePebbleKit) { + LOG.info("setting enable PebbleKit support to " + enablePebbleKit); + mEnablePebbleKit = enablePebbleKit; + } + private String getFixedString(ByteBuffer buf, int length) { byte[] tmp = new byte[length]; buf.get(tmp, 0, length); From ad9cfae6f972c2b61af9af337966f5896ab69f91 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Mon, 20 Feb 2017 08:47:42 +0100 Subject: [PATCH 42/53] Pebble: Pass datalog creation timestamp to PebbleKit, properly announce PebbleKit datalogging support --- .../contentprovider/PebbleContentProvider.java | 6 +++--- .../deviceevents/pebble/GBDeviceEventDataLogging.java | 1 + .../service/devices/pebble/DatalogSession.java | 5 ++++- .../service/devices/pebble/DatalogSessionHealthHR.java | 4 ++-- .../pebble/DatalogSessionHealthOverlayData.java | 4 ++-- .../devices/pebble/DatalogSessionHealthSleep.java | 4 ++-- .../devices/pebble/DatalogSessionHealthSteps.java | 4 ++-- .../devices/pebble/DatalogSessionPebbleHealth.java | 4 ++-- .../service/devices/pebble/PebbleKitSupport.java | 2 +- .../service/devices/pebble/PebbleProtocol.java | 10 +++++----- 10 files changed, 24 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/contentprovider/PebbleContentProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/contentprovider/PebbleContentProvider.java index e16c1bdc6..384e28744 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/contentprovider/PebbleContentProvider.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/contentprovider/PebbleContentProvider.java @@ -58,17 +58,17 @@ public class PebbleContentProvider extends ContentProvider { if (uri.equals(CONTENT_URI)) { MatrixCursor mc = new MatrixCursor(columnNames); int connected = 0; - int appMessage = 0; + int pebbleKit = 0; Prefs prefs = GBApplication.getPrefs(); if (prefs.getBoolean("pebble_enable_pebblekit", false)) { - appMessage = 1; + pebbleKit = 1; } String fwString = "unknown"; if (mGBDevice != null && mGBDevice.getType() == DeviceType.PEBBLE && mGBDevice.isInitialized()) { connected = 1; fwString = mGBDevice.getFirmwareVersion(); } - mc.addRow(new Object[]{connected, appMessage, 0, 3, 8, 2, fwString}); + mc.addRow(new Object[]{connected, pebbleKit, pebbleKit, 3, 8, 2, fwString}); return mc; } else { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/pebble/GBDeviceEventDataLogging.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/pebble/GBDeviceEventDataLogging.java index 971d99cc1..83c88af00 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/pebble/GBDeviceEventDataLogging.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/pebble/GBDeviceEventDataLogging.java @@ -10,6 +10,7 @@ public class GBDeviceEventDataLogging extends GBDeviceEvent { public int command; public UUID appUUID; + public long timestamp; public long tag; public byte pebbleDataType; public Object data; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSession.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSession.java index fc7291436..08409e758 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSession.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSession.java @@ -17,12 +17,14 @@ class DatalogSession { final UUID uuid; final byte itemType; final short itemSize; + final int timestamp; String taginfo = "(unknown)"; - DatalogSession(byte id, UUID uuid, int tag, byte itemType, short itemSize) { + DatalogSession(byte id, UUID uuid, int timestamp, int tag, byte itemType, short itemSize) { this.id = id; this.tag = tag; this.uuid = uuid; + this.timestamp = timestamp; this.itemType = itemType; this.itemSize = itemSize; } @@ -62,6 +64,7 @@ class DatalogSession { dataLogging.command = GBDeviceEventDataLogging.COMMAND_RECEIVE_DATA; dataLogging.appUUID = uuid; + dataLogging.timestamp = timestamp & 0xffffffffL; dataLogging.tag = tag; dataLogging.pebbleDataType = itemType; gbDeviceEvents[i] = dataLogging; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthHR.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthHR.java index 2f70e1f4c..61400aa49 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthHR.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthHR.java @@ -13,8 +13,8 @@ class DatalogSessionHealthHR extends DatalogSessionPebbleHealth { private static final Logger LOG = LoggerFactory.getLogger(DatalogSessionHealthHR.class); - DatalogSessionHealthHR(byte id, UUID uuid, int tag, byte item_type, short item_size, GBDevice device) { - super(id, uuid, tag, item_type, item_size, device); + DatalogSessionHealthHR(byte id, UUID uuid, int timestamp, int tag, byte item_type, short item_size, GBDevice device) { + super(id, uuid, timestamp, tag, item_type, item_size, device); taginfo = "(Health - HR " + tag + " )"; } 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 e41d8f325..463c57493 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 @@ -22,8 +22,8 @@ class DatalogSessionHealthOverlayData extends DatalogSessionPebbleHealth { private static final Logger LOG = LoggerFactory.getLogger(DatalogSessionHealthOverlayData.class); - public DatalogSessionHealthOverlayData(byte id, UUID uuid, int tag, byte item_type, short item_size, GBDevice device) { - super(id, uuid, tag, item_type, item_size, device); + DatalogSessionHealthOverlayData(byte id, UUID uuid, int timestamp, int tag, byte item_type, short item_size, GBDevice device) { + super(id, uuid, timestamp, tag, item_type, item_size, device); taginfo = "(Health - overlay data " + tag + " )"; } 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 d6534ef71..1cb770822 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 @@ -22,8 +22,8 @@ class DatalogSessionHealthSleep extends DatalogSessionPebbleHealth { private static final Logger LOG = LoggerFactory.getLogger(DatalogSessionHealthSleep.class); - public DatalogSessionHealthSleep(byte id, UUID uuid, int tag, byte item_type, short item_size, GBDevice device) { - super(id, uuid, tag, item_type, item_size, device); + DatalogSessionHealthSleep(byte id, UUID uuid, int timestamp, int tag, byte item_type, short item_size, GBDevice device) { + super(id, uuid, timestamp, tag, item_type, item_size, device); taginfo = "(Health - sleep " + tag + " )"; } 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 1f69dcd1c..725c89241 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 @@ -20,8 +20,8 @@ class DatalogSessionHealthSteps extends DatalogSessionPebbleHealth { private static final Logger LOG = LoggerFactory.getLogger(DatalogSessionHealthSteps.class); - public DatalogSessionHealthSteps(byte id, UUID uuid, int tag, byte item_type, short item_size, GBDevice device) { - super(id, uuid, tag, item_type, item_size, device); + DatalogSessionHealthSteps(byte id, UUID uuid, int timestamp, int tag, byte item_type, short item_size, GBDevice device) { + super(id, uuid, timestamp, tag, item_type, item_size, device); taginfo = "(Health - steps)"; } 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 index 2aae2cb92..e54780aa8 100644 --- 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 @@ -10,8 +10,8 @@ abstract class DatalogSessionPebbleHealth extends DatalogSession { private final GBDevice mDevice; - DatalogSessionPebbleHealth(byte id, UUID uuid, int tag, byte itemType, short itemSize, GBDevice device) { - super(id, uuid, tag, itemType, itemSize); + DatalogSessionPebbleHealth(byte id, UUID uuid, int timestamp, int tag, byte itemType, short itemSize, GBDevice device) { + super(id, uuid, timestamp, tag, itemType, itemSize); mDevice = device; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleKitSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleKitSupport.java index 9f285de88..ed28ff011 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleKitSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleKitSupport.java @@ -132,7 +132,7 @@ class PebbleKitSupport { void sendDataLoggingIntent(GBDeviceEventDataLogging dataLogging) { Intent intent = new Intent(); - intent.putExtra("data_log_timestamp", System.currentTimeMillis() / 1000); // is this data really not present in data from watch?! + intent.putExtra("data_log_timestamp", dataLogging.timestamp); intent.putExtra("uuid", dataLogging.appUUID); intent.putExtra("data_log_uuid", dataLogging.appUUID); // Is that really the same? intent.putExtra("data_log_tag", dataLogging.tag); 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 ce2529755..dc0284403 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 @@ -2248,15 +2248,15 @@ public class PebbleProtocol extends GBDeviceProtocol { LOG.info("DATALOG OPENSESSION. id=" + (id & 0xff) + ", App UUID=" + uuid.toString() + ", log_tag=" + log_tag + ", item_type=" + item_type + ", itemSize=" + item_size); 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, getDevice())); + mDatalogSessions.put(id, new DatalogSessionHealthSteps(id, uuid, timestamp, log_tag, item_type, item_size, getDevice())); } else if (uuid.equals(UUID_ZERO) && log_tag == 83) { - mDatalogSessions.put(id, new DatalogSessionHealthSleep(id, uuid, log_tag, item_type, item_size, getDevice())); + mDatalogSessions.put(id, new DatalogSessionHealthSleep(id, uuid, timestamp, log_tag, item_type, item_size, getDevice())); } else if (uuid.equals(UUID_ZERO) && log_tag == 84) { - mDatalogSessions.put(id, new DatalogSessionHealthOverlayData(id, uuid, log_tag, item_type, item_size, getDevice())); + mDatalogSessions.put(id, new DatalogSessionHealthOverlayData(id, uuid, timestamp, log_tag, item_type, item_size, getDevice())); } else if (uuid.equals(UUID_ZERO) && log_tag == 85) { - mDatalogSessions.put(id, new DatalogSessionHealthHR(id, uuid, log_tag, item_type, item_size, getDevice())); + mDatalogSessions.put(id, new DatalogSessionHealthHR(id, uuid, timestamp, log_tag, item_type, item_size, getDevice())); } else { - mDatalogSessions.put(id, new DatalogSession(id, uuid, log_tag, item_type, item_size)); + mDatalogSessions.put(id, new DatalogSession(id, uuid, timestamp, log_tag, item_type, item_size)); } } break; From 2dbda6138bf130438aea9577c838edf0188c2fa7 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Mon, 20 Feb 2017 22:09:00 +0100 Subject: [PATCH 43/53] Pebble: some cleanups and simplifications for datalogging via PebbleKit --- .../pebble/GBDeviceEventDataLogging.java | 2 +- .../devices/pebble/DatalogSession.java | 34 +++++++++++-------- .../devices/pebble/PebbleKitSupport.java | 31 +++++++++-------- .../devices/pebble/PebbleProtocol.java | 12 ++++--- 4 files changed, 43 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/pebble/GBDeviceEventDataLogging.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/pebble/GBDeviceEventDataLogging.java index 83c88af00..1dd4f5431 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/pebble/GBDeviceEventDataLogging.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/pebble/GBDeviceEventDataLogging.java @@ -13,5 +13,5 @@ public class GBDeviceEventDataLogging extends GBDeviceEvent { public long timestamp; public long tag; public byte pebbleDataType; - public Object data; + public Object[] data; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSession.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSession.java index 08409e758..ed03b054a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSession.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSession.java @@ -6,7 +6,6 @@ import org.slf4j.LoggerFactory; import java.nio.ByteBuffer; import java.util.UUID; -import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.pebble.GBDeviceEventDataLogging; class DatalogSession { @@ -37,38 +36,43 @@ class DatalogSession { return taginfo; } - GBDeviceEvent[] handleMessageForPebbleKit(ByteBuffer buf, int length) { + GBDeviceEventDataLogging handleMessageForPebbleKit(ByteBuffer buf, int length) { if (0 != (length % itemSize)) { LOG.warn("invalid length"); return null; } int packetCount = length / itemSize; - GBDeviceEvent[] gbDeviceEvents = new GBDeviceEvent[packetCount + 1]; // pad for ack + + if (packetCount <= 0) { + LOG.warn("invalid number of datalog elements"); + return null; + } + + GBDeviceEventDataLogging dataLogging = new GBDeviceEventDataLogging(); + dataLogging.command = GBDeviceEventDataLogging.COMMAND_RECEIVE_DATA; + dataLogging.appUUID = uuid; + dataLogging.timestamp = timestamp & 0xffffffffL; + dataLogging.tag = tag; + dataLogging.pebbleDataType = itemType; + dataLogging.data = new Object[packetCount]; + for (int i = 0; i < packetCount; i++) { - GBDeviceEventDataLogging dataLogging = new GBDeviceEventDataLogging(); switch (itemType) { case PebbleProtocol.TYPE_BYTEARRAY: byte[] itemData = new byte[itemSize]; buf.get(itemData); - dataLogging.data = itemData; + dataLogging.data[i] = itemData; break; case PebbleProtocol.TYPE_UINT: - dataLogging.data = buf.getInt() & 0xffffffffL; + dataLogging.data[i] = buf.getInt() & 0xffffffffL; break; case PebbleProtocol.TYPE_INT: - dataLogging.data = buf.getInt(); + dataLogging.data[i] = buf.getInt(); break; } - - dataLogging.command = GBDeviceEventDataLogging.COMMAND_RECEIVE_DATA; - dataLogging.appUUID = uuid; - dataLogging.timestamp = timestamp & 0xffffffffL; - dataLogging.tag = tag; - dataLogging.pebbleDataType = itemType; - gbDeviceEvents[i] = dataLogging; } - return gbDeviceEvents; + return dataLogging; } } \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleKitSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleKitSupport.java index ed28ff011..fbccba860 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleKitSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleKitSupport.java @@ -140,30 +140,31 @@ class PebbleKitSupport { switch (dataLogging.command) { case GBDeviceEventDataLogging.COMMAND_RECEIVE_DATA: intent.setAction(PEBBLEKIT_ACTION_DL_RECEIVE_DATA_NEW); - intent.putExtra("pbl_data_id", dataLogTransactionId++); intent.putExtra("pbl_data_type", dataLogging.pebbleDataType); - switch (dataLogging.pebbleDataType) { - case PebbleProtocol.TYPE_BYTEARRAY: - intent.putExtra("pbl_data_object", Base64.encodeToString((byte[]) dataLogging.data, Base64.NO_WRAP)); - break; - case PebbleProtocol.TYPE_UINT: - intent.putExtra("pbl_data_object", (Long) dataLogging.data); - break; - case PebbleProtocol.TYPE_INT: - intent.putExtra("pbl_data_object", (Integer) dataLogging.data); - break; + for (Object dataObject : dataLogging.data) { + intent.putExtra("pbl_data_id", dataLogTransactionId++); + switch (dataLogging.pebbleDataType) { + case PebbleProtocol.TYPE_BYTEARRAY: + intent.putExtra("pbl_data_object", Base64.encodeToString((byte[]) dataObject, Base64.NO_WRAP)); + break; + case PebbleProtocol.TYPE_UINT: + intent.putExtra("pbl_data_object", (Long) dataObject); + break; + case PebbleProtocol.TYPE_INT: + intent.putExtra("pbl_data_object", (Integer) dataObject); + break; + } + LOG.info("broadcasting datalogging to uuid " + dataLogging.appUUID + " tag: " + dataLogging.tag + "transaction id: " + dataLogTransactionId + " type: " + dataLogging.pebbleDataType); + mContext.sendBroadcast(intent); } - LOG.info("broadcasting datalogging to uuid " + dataLogging.appUUID + " tag: " + dataLogging.tag + "transaction id: " + dataLogTransactionId + " type: " + dataLogging.pebbleDataType); break; case GBDeviceEventDataLogging.COMMAND_FINISH_SESSION: intent.setAction(PEBBLEKIT_ACTION_DL_FINISH_SESSION); LOG.info("broadcasting datalogging finish session to uuid " + dataLogging.appUUID + " tag: " + dataLogging.tag); - + mContext.sendBroadcast(intent); break; default: LOG.warn("invalid datalog command"); - return; } - mContext.sendBroadcast(intent); } } 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 dc0284403..8e6ed14da 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 @@ -2218,7 +2218,7 @@ public class PebbleProtocol extends GBDeviceProtocol { boolean ack = true; byte command = buf.get(); byte id = buf.get(); - GBDeviceEvent[] devEvts = new GBDeviceEvent[1]; + GBDeviceEventDataLogging devEvtDataLogging = null; switch (command) { case DATALOG_TIMEOUT: LOG.info("DATALOG TIMEOUT. id=" + (id & 0xff) + " - ignoring"); @@ -2232,7 +2232,10 @@ public class PebbleProtocol extends GBDeviceProtocol { if (datalogSession != null) { LOG.info("DATALOG UUID=" + datalogSession.uuid + ", tag=" + datalogSession.tag + datalogSession.getTaginfo() + ", itemSize=" + datalogSession.itemSize + ", itemType=" + datalogSession.itemType); if (!datalogSession.uuid.equals(UUID_ZERO) && datalogSession.getClass().equals(DatalogSession.class) && mEnablePebbleKit) { - devEvts = datalogSession.handleMessageForPebbleKit(buf, length - 10); + devEvtDataLogging = datalogSession.handleMessageForPebbleKit(buf, length - 10); + if (devEvtDataLogging == null) { + ack = false; + } } else { ack = datalogSession.handleMessage(buf, length - 10); } @@ -2269,7 +2272,7 @@ public class PebbleProtocol extends GBDeviceProtocol { dataLogging.command = GBDeviceEventDataLogging.COMMAND_FINISH_SESSION; dataLogging.appUUID = datalogSession.uuid; dataLogging.tag = datalogSession.tag; - devEvts = new GBDeviceEvent[]{dataLogging, null}; + devEvtDataLogging = dataLogging; } mDatalogSessions.remove(id); } @@ -2287,8 +2290,7 @@ public class PebbleProtocol extends GBDeviceProtocol { sendBytes.encodedBytes = encodeDatalog(id, DATALOG_NACK); } // append ack/nack - devEvts[devEvts.length - 1] = sendBytes; - return devEvts; + return new GBDeviceEvent[]{devEvtDataLogging, sendBytes}; } private GBDeviceEvent decodeAppReorder(ByteBuffer buf) { From c23e496db6d16424279fc3c39cd1e3268143711a Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Mon, 20 Feb 2017 22:19:16 +0100 Subject: [PATCH 44/53] bump version, update changelog --- 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 25eb027e8..4aa956f79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ ###Changelog +####Version 0.17.5 +* Automatically start the service on boot (can be turned off) +* Pebble: PebbleKit compatibility improvements (Datalogging) +* Pebble: Display music shuffle and repeat states for some players +* Pebble 2/LE: Speed up data transfer + ####Version 0.17.4 * Better integration with android music players * Privacy options for calls (hide caller name/number) diff --git a/app/build.gradle b/app/build.gradle index 985f5ef35..efd0ed855 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -26,8 +26,8 @@ android { targetSdkVersion 23 // note: always bump BOTH versionCode and versionName! - versionName "0.17.4" - versionCode 85 + versionName "0.17.5" + versionCode 86 } buildTypes { release { diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml index 7ab0440cd..469c9e74f 100644 --- a/app/src/main/res/xml/changelog_master.xml +++ b/app/src/main/res/xml/changelog_master.xml @@ -1,5 +1,11 @@ + + Automatically start the service on boot (can be turned off) + Pebble: PebbleKit compatibility improvements (Datalogging) + Pebble: Display music shuffle and repeat states for some players + Pebble 2/LE: Speed up data transfer + Better integration with android music players Privacy options for calls (hide caller name/number) From 24794c46b1960cf3b929bcfcd579fbe9541aba20 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Mon, 20 Feb 2017 22:20:22 +0100 Subject: [PATCH 45/53] update translations from transifex (THANKS) --- app/src/main/res/values-es/strings.xml | 3 +++ app/src/main/res/values-fr/strings.xml | 3 +++ app/src/main/res/values-ja/strings.xml | 1 + 3 files changed, 7 insertions(+) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 8ee6275dd..aa21fdae5 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -45,6 +45,7 @@ Ajustes Ajustes generales Conectarse al dispositivo cuando el Bluetooth esté activado + Iniciar automáticamente Reconectar automáticamente Reproductor de audio favorito Predeterminado @@ -122,6 +123,8 @@ Si tu Pebble 2/Pebble LE no funciona correctamente, prueba esta opción para limitar el MTU (rango válido 20–512) Activar crear registros de la App del Reloj Producirá registros de las apps del reloj que Gadgetbridge guardará (necesita reconexión) + ACK antes de tiempo de PebbleKit + Permitirá a los mensajes enviados a apps de terceros ser reconocidos siempre e inmediatamente Intentos de reconexión Unidades Formato de hora diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 411ee1609..2ab027771 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -45,6 +45,7 @@ Paramètres Paramètres généraux Connecter votre appareil quand le Bluetooth est mis en marche + Démarrer automatiquement Reconnexion automatique Lecteur audio préféré Par défaut @@ -122,6 +123,8 @@ Si votre Pebble 2/LE ne fonctionne pas correctement, essayez d\'activer cette option pour limiter le MTU (plage valide 20-512) Activer les logs des Watch App Ceci permettra à Gadgetbridge de conserver les logs des Watch App (requiert une reconnexion) + ACK à l\'avance du PebbleKit + Ceci permettra aux messages envoyés à des apps tierces d\'être toujours reconnus immédiatement Tentatives de reconnexion Unités Format de l\'heure diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 2572526ae..967a79651 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -45,6 +45,7 @@ 設定 一般設定 Bluetoothがオンになったときにデバイスに接続 + 自動的に開始 自動的に再接続 お好みのオーディオプレイヤー デフォルト From db58b32b6f00a1aac233e1f57f6334a520faa59d Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Mon, 20 Feb 2017 22:23:44 +0100 Subject: [PATCH 46/53] Update two german strings --- app/src/main/res/values-de/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 060540384..e458991e4 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -42,6 +42,7 @@ Einstellungen Allgemeine Einstellungen Verbinde, wenn Bluetooth eingeschaltet wird + Automatisch starten Verbindungen automatisch wiederherstellen Bevorzugter Audioplayer Standard @@ -85,6 +86,7 @@ Pebble Health synchronisieren Misfit synchronisieren Morpheuz synchronisieren + Unterstützung für ausgehende Anrufe Erlaube Zugriff von anderen Android Apps Experimentelle Unterstützung für Android Apps, die PebbleKit benutzen Sonnenauf- und -untergang From e9cb5fd3740ede7b535544bd81e89c736afee1e7 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Tue, 21 Feb 2017 16:20:42 +0100 Subject: [PATCH 47/53] WIP sleep in a week chart Displays minutes which is confusing Only displays deeps sleep (no idea why) Is green (which is also confusing) --- .../charts/AbstractWeekChartFragment.java | 263 ++++++++++++++++++ .../activities/charts/ActivityAnalysis.java | 6 +- .../activities/charts/ChartsActivity.java | 16 +- .../charts/WeekSleepChartFragment.java | 34 +++ .../charts/WeekStepsChartFragment.java | 259 +---------------- app/src/main/res/values/strings.xml | 2 +- 6 files changed, 322 insertions(+), 258 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractWeekChartFragment.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekSleepChartFragment.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractWeekChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractWeekChartFragment.java new file mode 100644 index 000000000..478437bd5 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractWeekChartFragment.java @@ -0,0 +1,263 @@ +package nodomain.freeyourgadget.gadgetbridge.activities.charts; + +import android.graphics.Color; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.github.mikephil.charting.charts.BarChart; +import com.github.mikephil.charting.charts.Chart; +import com.github.mikephil.charting.charts.PieChart; +import com.github.mikephil.charting.components.LimitLine; +import com.github.mikephil.charting.components.XAxis; +import com.github.mikephil.charting.components.YAxis; +import com.github.mikephil.charting.data.BarData; +import com.github.mikephil.charting.data.BarDataSet; +import com.github.mikephil.charting.data.BarEntry; +import com.github.mikephil.charting.data.PieData; +import com.github.mikephil.charting.data.PieDataSet; +import com.github.mikephil.charting.data.PieEntry; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; +import java.util.Locale; + +import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; + + +public abstract class AbstractWeekChartFragment extends AbstractChartFragment { + protected static final Logger LOG = LoggerFactory.getLogger(AbstractWeekChartFragment.class); + + private Locale mLocale; + private int mTargetValue = 0; + + private PieChart mTodayPieChart; + private BarChart mWeekChart; + + @Override + protected ChartsData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device) { + Calendar day = Calendar.getInstance(); + day.setTime(chartsHost.getEndDate()); + //NB: we could have omitted the day, but this way we can move things to the past easily + DayData dayData = refreshDayPie(db, day, device); + DefaultChartsData weekBeforeData = refreshWeekBeforeData(db, mWeekChart, day, device); + + return new MyChartsData(dayData, weekBeforeData); + } + + @Override + protected void updateChartsnUIThread(ChartsData chartsData) { + MyChartsData mcd = (MyChartsData) chartsData; + +// setupLegend(mWeekChart); + mTodayPieChart.setCenterText(NumberFormat.getNumberInstance(mLocale).format(mcd.getDayData().totalValue)); + mTodayPieChart.setData(mcd.getDayData().data); + + mWeekChart.setData(null); // workaround for https://github.com/PhilJay/MPAndroidChart/issues/2317 + mWeekChart.setData(mcd.getWeekBeforeData().getData()); + mWeekChart.getLegend().setEnabled(false); + mWeekChart.getXAxis().setValueFormatter(mcd.getWeekBeforeData().getXValueFormatter()); + } + + @Override + protected void renderCharts() { + mWeekChart.invalidate(); + mTodayPieChart.invalidate(); + } + + private DefaultChartsData refreshWeekBeforeData(DBHandler db, BarChart barChart, Calendar day, GBDevice device) { + + ActivityAnalysis analysis = new ActivityAnalysis(); + + day = (Calendar) day.clone(); // do not modify the caller's argument + day.add(Calendar.DATE, -7); + List entries = new ArrayList<>(); + ArrayList labels = new ArrayList(); + + for (int counter = 0; counter < 7; counter++) { + entries.add(new BarEntry(counter, getTotalForSamples(getSamplesOfDay(db, day, device)))); + labels.add(day.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT, mLocale)); + day.add(Calendar.DATE, 1); + } + + BarDataSet set = new BarDataSet(entries, ""); + set.setColor(akActivity.color); + + BarData barData = new BarData(set); + barData.setValueTextColor(Color.GRAY); //prevent tearing other graph elements with the black text. Another approach would be to hide the values cmpletely with data.setDrawValues(false); + + LimitLine target = new LimitLine(mTargetValue); + barChart.getAxisLeft().removeAllLimitLines(); + barChart.getAxisLeft().addLimitLine(target); + + return new DefaultChartsData(barData, new PreformattedXIndexLabelFormatter(labels)); + } + + + private DayData refreshDayPie(DBHandler db, Calendar day, GBDevice device) { + + int totalValue = getTotalForSamples(getSamplesOfDay(db, day, device)); + + PieData data = new PieData(); + List entries = new ArrayList<>(); + List colors = new ArrayList<>(); + + entries.add(new PieEntry(totalValue, "")); //we don't want labels on the pie chart + colors.add(akActivity.color); + + if (totalValue < mTargetValue) { + entries.add(new PieEntry((mTargetValue - totalValue))); //we don't want labels on the pie chart + colors.add(Color.GRAY); + } + + PieDataSet set = new PieDataSet(entries, ""); + set.setColors(colors); + data.setDataSet(set); + //this hides the values (numeric) added to the set. These would be shown aside the strings set with addXValue above + data.setDrawValues(false); + + return new DayData(data, totalValue); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + mLocale = getResources().getConfiguration().locale; + + View rootView = inflater.inflate(R.layout.fragment_weeksteps_chart, container, false); + + int goal = getGoal(); + if (goal >= 0) { + mTargetValue = goal; + } + + mTodayPieChart = (PieChart) rootView.findViewById(R.id.todaystepschart); + mWeekChart = (BarChart) rootView.findViewById(R.id.weekstepschart); + + setupWeekChart(); + setupTodayPieChart(); + + // refresh immediately instead of use refreshIfVisible(), for perceived performance + refresh(); + + return rootView; + } + + private void setupTodayPieChart() { + mTodayPieChart.setBackgroundColor(BACKGROUND_COLOR); + mTodayPieChart.getDescription().setTextColor(DESCRIPTION_COLOR); + mTodayPieChart.getDescription().setText(getContext().getString(R.string.weeksteps_today_steps_description, String.valueOf(mTargetValue))); +// mTodayPieChart.setNoDataTextDescription(""); + mTodayPieChart.setNoDataText(""); + mTodayPieChart.getLegend().setEnabled(false); +// setupLegend(mTodayPieChart); + } + + private void setupWeekChart() { + mWeekChart.setBackgroundColor(BACKGROUND_COLOR); + mWeekChart.getDescription().setTextColor(DESCRIPTION_COLOR); + mWeekChart.getDescription().setText(""); + mWeekChart.setFitBars(true); + + configureBarLineChartDefaults(mWeekChart); + + XAxis x = mWeekChart.getXAxis(); + x.setDrawLabels(true); + x.setDrawGridLines(false); + x.setEnabled(true); + x.setTextColor(CHART_TEXT_COLOR); + x.setDrawLimitLinesBehindData(true); + x.setPosition(XAxis.XAxisPosition.BOTTOM); + + YAxis y = mWeekChart.getAxisLeft(); + y.setDrawGridLines(false); + y.setDrawTopYLabelEntry(false); + y.setTextColor(CHART_TEXT_COLOR); + y.setDrawZeroLine(true); + y.setSpaceBottom(0); + y.setAxisMinimum(0); + + y.setEnabled(true); + + YAxis yAxisRight = mWeekChart.getAxisRight(); + yAxisRight.setDrawGridLines(false); + yAxisRight.setEnabled(false); + yAxisRight.setDrawLabels(false); + yAxisRight.setDrawTopYLabelEntry(false); + yAxisRight.setTextColor(CHART_TEXT_COLOR); + } + + @Override + protected void setupLegend(Chart chart) { +// List legendColors = new ArrayList<>(1); +// List legendLabels = new ArrayList<>(1); +// legendColors.add(akActivity.color); +// legendLabels.add(getContext().getString(R.string.chart_steps)); +// chart.getLegend().setCustom(legendColors, legendLabels); +// chart.getLegend().setTextColor(LEGEND_TEXT_COLOR); + } + + private List getSamplesOfDay(DBHandler db, Calendar day, GBDevice device) { + int startTs; + int endTs; + + day = (Calendar) day.clone(); // do not modify the caller's argument + day.set(Calendar.HOUR_OF_DAY, 0); + day.set(Calendar.MINUTE, 0); + day.set(Calendar.SECOND, 0); + startTs = (int) (day.getTimeInMillis() / 1000); + + day.set(Calendar.HOUR_OF_DAY, 23); + day.set(Calendar.MINUTE, 59); + day.set(Calendar.SECOND, 59); + endTs = (int) (day.getTimeInMillis() / 1000); + + return getSamples(db, device, startTs, endTs); + } + + @Override + protected List getSamples(DBHandler db, GBDevice device, int tsFrom, int tsTo) { + return super.getAllSamples(db, device, tsFrom, tsTo); + } + + private static class DayData { + private final PieData data; + private final int totalValue; + + DayData(PieData data, int totalValue) { + this.data = data; + this.totalValue = totalValue; + } + } + + private static class MyChartsData extends ChartsData { + private final DefaultChartsData weekBeforeData; + private final DayData dayData; + + MyChartsData(DayData dayData, DefaultChartsData weekBeforeData) { + this.dayData = dayData; + this.weekBeforeData = weekBeforeData; + } + + DayData getDayData() { + return dayData; + } + + DefaultChartsData getWeekBeforeData() { + return weekBeforeData; + } + } + + abstract int getGoal(); + + abstract int getTotalForSamples(List activitySamples); +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityAnalysis.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityAnalysis.java index 8d0719f23..1d3d3669e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityAnalysis.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityAnalysis.java @@ -7,8 +7,8 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivityAmounts; import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; -public class ActivityAnalysis { - public ActivityAmounts calculateActivityAmounts(List samples) { +class ActivityAnalysis { + ActivityAmounts calculateActivityAmounts(List samples) { ActivityAmount deepSleep = new ActivityAmount(ActivityKind.TYPE_DEEP_SLEEP); ActivityAmount lightSleep = new ActivityAmount(ActivityKind.TYPE_LIGHT_SLEEP); ActivityAmount notWorn = new ActivityAmount(ActivityKind.TYPE_NOT_WORN); @@ -64,7 +64,7 @@ public class ActivityAnalysis { return result; } - public int calculateTotalSteps(List samples) { + int calculateTotalSteps(List samples) { int totalSteps = 0; for (ActivitySample sample : samples) { int steps = sample.getSteps(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsActivity.java index 292202cca..2b897d516 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsActivity.java @@ -56,7 +56,7 @@ public class ChartsActivity extends AbstractGBFragmentActivity implements Charts private final String mDuration; private TextView durationLabel; - public ShowDurationDialog(String duration, Context context) { + ShowDurationDialog(String duration, Context context) { super(context); mDuration = duration; } @@ -298,7 +298,7 @@ public class ChartsActivity extends AbstractGBFragmentActivity implements Charts */ public class SectionsPagerAdapter extends AbstractFragmentPagerAdapter { - public SectionsPagerAdapter(FragmentManager fm) { + SectionsPagerAdapter(FragmentManager fm) { super(fm); } @@ -311,8 +311,10 @@ public class ChartsActivity extends AbstractGBFragmentActivity implements Charts case 1: return new SleepChartFragment(); case 2: - return new WeekStepsChartFragment(); + return new WeekSleepChartFragment(); case 3: + return new WeekStepsChartFragment(); + case 4: return new LiveActivityFragment(); } @@ -321,8 +323,8 @@ public class ChartsActivity extends AbstractGBFragmentActivity implements Charts @Override public int getCount() { - // Show 3 total pages. - return 4; + // Show 5 total pages. + return 5; } @Override @@ -333,8 +335,10 @@ public class ChartsActivity extends AbstractGBFragmentActivity implements Charts case 1: return getString(R.string.sleepchart_your_sleep); case 2: - return getString(R.string.weekstepschart_steps_a_week); + return getString(R.string.weeksleepchart_sleep_a_week); case 3: + return getString(R.string.weekstepschart_steps_a_week); + case 4: return getString(R.string.liveactivity_live_activity); } return super.getPageTitle(position); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekSleepChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekSleepChartFragment.java new file mode 100644 index 000000000..4582d2b0f --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekSleepChartFragment.java @@ -0,0 +1,34 @@ +package nodomain.freeyourgadget.gadgetbridge.activities.charts; + +import java.util.List; + +import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.model.ActivityAmount; +import nodomain.freeyourgadget.gadgetbridge.model.ActivityAmounts; +import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind; +import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; + +public class WeekSleepChartFragment extends AbstractWeekChartFragment { + @Override + public String getTitle() { + return getString(R.string.weeksleepchart_sleep_a_week); + } + + @Override + int getGoal() { + return 8 * 60; // FIXME + } + + @Override + int getTotalForSamples(List activitySamples) { + ActivityAnalysis analysis = new ActivityAnalysis(); + ActivityAmounts amounts = analysis.calculateActivityAmounts(activitySamples); + long totalSeconds = 0; + for (ActivityAmount amount : amounts.getAmounts()) { + if ((amount.getActivityKind() & ActivityKind.TYPE_SLEEP) != 0) { + totalSeconds += amount.getTotalSeconds(); + } + } + return (int) (totalSeconds / 60); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java index 3d08ed5e6..d4dd6ce8d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java @@ -1,267 +1,30 @@ package nodomain.freeyourgadget.gadgetbridge.activities.charts; -import android.graphics.Color; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import com.github.mikephil.charting.charts.BarChart; -import com.github.mikephil.charting.charts.Chart; -import com.github.mikephil.charting.charts.PieChart; -import com.github.mikephil.charting.components.LimitLine; -import com.github.mikephil.charting.components.XAxis; -import com.github.mikephil.charting.components.YAxis; -import com.github.mikephil.charting.data.BarData; -import com.github.mikephil.charting.data.BarDataSet; -import com.github.mikephil.charting.data.BarEntry; -import com.github.mikephil.charting.data.PieData; -import com.github.mikephil.charting.data.PieDataSet; -import com.github.mikephil.charting.data.PieEntry; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.text.NumberFormat; -import java.util.ArrayList; -import java.util.Calendar; import java.util.List; -import java.util.Locale; import nodomain.freeyourgadget.gadgetbridge.R; -import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandCoordinator; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; - -public class WeekStepsChartFragment extends AbstractChartFragment { - protected static final Logger LOG = LoggerFactory.getLogger(WeekStepsChartFragment.class); - - private Locale mLocale; - private int mTargetSteps = 10000; - - private PieChart mTodayStepsChart; - private BarChart mWeekStepsChart; - - @Override - protected ChartsData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device) { - Calendar day = Calendar.getInstance(); - day.setTime(chartsHost.getEndDate()); - //NB: we could have omitted the day, but this way we can move things to the past easily - DaySteps daySteps = refreshDaySteps(db, day, device); - DefaultChartsData weekBeforeStepsData = refreshWeekBeforeSteps(db, mWeekStepsChart, day, device); - - return new MyChartsData(daySteps, weekBeforeStepsData); - } - - @Override - protected void updateChartsnUIThread(ChartsData chartsData) { - MyChartsData mcd = (MyChartsData) chartsData; - -// setupLegend(mWeekStepsChart); - mTodayStepsChart.setCenterText(NumberFormat.getNumberInstance(mLocale).format(mcd.getDaySteps().totalSteps)); - mTodayStepsChart.setData(mcd.getDaySteps().data); - - mWeekStepsChart.setData(null); // workaround for https://github.com/PhilJay/MPAndroidChart/issues/2317 - mWeekStepsChart.setData(mcd.getWeekBeforeStepsData().getData()); - mWeekStepsChart.getLegend().setEnabled(false); - mWeekStepsChart.getXAxis().setValueFormatter(mcd.getWeekBeforeStepsData().getXValueFormatter()); - } - - @Override - protected void renderCharts() { - mWeekStepsChart.invalidate(); - mTodayStepsChart.invalidate(); - } - - private DefaultChartsData refreshWeekBeforeSteps(DBHandler db, BarChart barChart, Calendar day, GBDevice device) { - - ActivityAnalysis analysis = new ActivityAnalysis(); - - day = (Calendar) day.clone(); // do not modify the caller's argument - day.add(Calendar.DATE, -7); - List entries = new ArrayList<>(); - ArrayList labels = new ArrayList(); - - for (int counter = 0; counter < 7; counter++) { - entries.add(new BarEntry(counter, analysis.calculateTotalSteps(getSamplesOfDay(db, day, device)))); - labels.add(day.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT, mLocale)); - day.add(Calendar.DATE, 1); - } - - BarDataSet set = new BarDataSet(entries, ""); - set.setColor(akActivity.color); - - BarData barData = new BarData(set); - barData.setValueTextColor(Color.GRAY); //prevent tearing other graph elements with the black text. Another approach would be to hide the values cmpletely with data.setDrawValues(false); - - LimitLine target = new LimitLine(mTargetSteps); - barChart.getAxisLeft().removeAllLimitLines(); - barChart.getAxisLeft().addLimitLine(target); - - return new DefaultChartsData(barData, new PreformattedXIndexLabelFormatter(labels)); - } - - - private DaySteps refreshDaySteps(DBHandler db, Calendar day, GBDevice device) { - ActivityAnalysis analysis = new ActivityAnalysis(); - - int totalSteps = analysis.calculateTotalSteps(getSamplesOfDay(db, day, device)); - - PieData data = new PieData(); - List entries = new ArrayList<>(); - List colors = new ArrayList<>(); - - entries.add(new PieEntry(totalSteps, "")); //we don't want labels on the pie chart - colors.add(akActivity.color); - - if (totalSteps < mTargetSteps) { - entries.add(new PieEntry((mTargetSteps - totalSteps))); //we don't want labels on the pie chart - colors.add(Color.GRAY); - } - - PieDataSet set = new PieDataSet(entries, ""); - set.setColors(colors); - data.setDataSet(set); - //this hides the values (numeric) added to the set. These would be shown aside the strings set with addXValue above - data.setDrawValues(false); - - return new DaySteps(data, totalSteps); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - mLocale = getResources().getConfiguration().locale; - - View rootView = inflater.inflate(R.layout.fragment_weeksteps_chart, container, false); - - GBDevice device = getChartsHost().getDevice(); - if (device != null) { - // TODO: eek, this is device specific! - mTargetSteps = MiBandCoordinator.getFitnessGoal(device.getAddress()); - } - - mTodayStepsChart = (PieChart) rootView.findViewById(R.id.todaystepschart); - mWeekStepsChart = (BarChart) rootView.findViewById(R.id.weekstepschart); - - setupWeekStepsChart(); - setupTodayStepsChart(); - - // refresh immediately instead of use refreshIfVisible(), for perceived performance - refresh(); - - return rootView; - } - +public class WeekStepsChartFragment extends AbstractWeekChartFragment { @Override public String getTitle() { return getString(R.string.weekstepschart_steps_a_week); } - private void setupTodayStepsChart() { - mTodayStepsChart.setBackgroundColor(BACKGROUND_COLOR); - mTodayStepsChart.getDescription().setTextColor(DESCRIPTION_COLOR); - mTodayStepsChart.getDescription().setText(getContext().getString(R.string.weeksteps_today_steps_description, String.valueOf(mTargetSteps))); -// mTodayStepsChart.setNoDataTextDescription(""); - mTodayStepsChart.setNoDataText(""); - mTodayStepsChart.getLegend().setEnabled(false); -// setupLegend(mTodayStepsChart); - } - - private void setupWeekStepsChart() { - mWeekStepsChart.setBackgroundColor(BACKGROUND_COLOR); - mWeekStepsChart.getDescription().setTextColor(DESCRIPTION_COLOR); - mWeekStepsChart.getDescription().setText(""); - mWeekStepsChart.setFitBars(true); - - configureBarLineChartDefaults(mWeekStepsChart); - - XAxis x = mWeekStepsChart.getXAxis(); - x.setDrawLabels(true); - x.setDrawGridLines(false); - x.setEnabled(true); - x.setTextColor(CHART_TEXT_COLOR); - x.setDrawLimitLinesBehindData(true); - x.setPosition(XAxis.XAxisPosition.BOTTOM); - - YAxis y = mWeekStepsChart.getAxisLeft(); - y.setDrawGridLines(false); - y.setDrawTopYLabelEntry(false); - y.setTextColor(CHART_TEXT_COLOR); - y.setDrawZeroLine(true); - y.setSpaceBottom(0); - y.setAxisMinimum(0); - - y.setEnabled(true); - - YAxis yAxisRight = mWeekStepsChart.getAxisRight(); - yAxisRight.setDrawGridLines(false); - yAxisRight.setEnabled(false); - yAxisRight.setDrawLabels(false); - yAxisRight.setDrawTopYLabelEntry(false); - yAxisRight.setTextColor(CHART_TEXT_COLOR); + @Override + int getGoal() { + GBDevice device = getChartsHost().getDevice(); + if (device != null) { + return MiBandCoordinator.getFitnessGoal(device.getAddress()); + } + return -1; } @Override - protected void setupLegend(Chart chart) { -// List legendColors = new ArrayList<>(1); -// List legendLabels = new ArrayList<>(1); -// legendColors.add(akActivity.color); -// legendLabels.add(getContext().getString(R.string.chart_steps)); -// chart.getLegend().setCustom(legendColors, legendLabels); -// chart.getLegend().setTextColor(LEGEND_TEXT_COLOR); - } - - private List getSamplesOfDay(DBHandler db, Calendar day, GBDevice device) { - int startTs; - int endTs; - - day = (Calendar) day.clone(); // do not modify the caller's argument - day.set(Calendar.HOUR_OF_DAY, 0); - day.set(Calendar.MINUTE, 0); - day.set(Calendar.SECOND, 0); - startTs = (int) (day.getTimeInMillis() / 1000); - - day.set(Calendar.HOUR_OF_DAY, 23); - day.set(Calendar.MINUTE, 59); - day.set(Calendar.SECOND, 59); - endTs = (int) (day.getTimeInMillis() / 1000); - - return getSamples(db, device, startTs, endTs); - } - - @Override - protected List getSamples(DBHandler db, GBDevice device, int tsFrom, int tsTo) { - return super.getAllSamples(db, device, tsFrom, tsTo); - } - - private static class DaySteps { - private final PieData data; - private final int totalSteps; - - public DaySteps(PieData data, int totalSteps) { - this.data = data; - this.totalSteps = totalSteps; - } - } - - private static class MyChartsData extends ChartsData { - private final DefaultChartsData weekBeforeStepsData; - private final DaySteps daySteps; - - public MyChartsData(DaySteps daySteps, DefaultChartsData weekBeforeStepsData) { - this.daySteps = daySteps; - this.weekBeforeStepsData = weekBeforeStepsData; - } - - public DaySteps getDaySteps() { - return daySteps; - } - - public DefaultChartsData getWeekBeforeStepsData() { - return weekBeforeStepsData; - } + int getTotalForSamples(List activitySamples) { + ActivityAnalysis analysis = new ActivityAnalysis(); + return analysis.calculateTotalSteps(activitySamples); } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a36191753..efc254dbf 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -277,6 +277,7 @@ Last charge: %s \n Number of charges: %s Your Sleep + Sleep a week Steps a week Your Activity and Sleep Updating Firmware… @@ -409,5 +410,4 @@ 24H AM/PM Alarm Clock - From 337bfa19384486843347f59d2010339e363deb1b Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Tue, 21 Feb 2017 21:41:21 +0100 Subject: [PATCH 48/53] Handle button presses and log them See #556 --- .../devices/miband/MiBand2Service.java | 2 +- .../devices/miband2/MiBand2Support.java | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBand2Service.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBand2Service.java index 0b8f5623f..fb3e9a107 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBand2Service.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBand2Service.java @@ -31,7 +31,7 @@ public class MiBand2Service { public static final UUID UUID_UNKNOWN_CHARACTERISTIC8 = UUID.fromString("00000008-0000-3512-2118-0009af100700"); // service uuid fee1 public static final UUID UUID_CHARACTERISTIC_AUTH = UUID.fromString("00000009-0000-3512-2118-0009af100700"); - public static final UUID UUID_UNKNOWN_CHARACTERISTIC10 = UUID.fromString("00000010-0000-3512-2118-0009af100700"); + public static final UUID UUID_CHARACTERISTIC_10_BUTTON = UUID.fromString("00000010-0000-3512-2118-0009af100700"); public static final int ALERT_LEVEL_NONE = 0; public static final int ALERT_LEVEL_MESSAGE = 1; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/MiBand2Support.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/MiBand2Support.java index 09f7e6a47..6d9a83fcf 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/MiBand2Support.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/MiBand2Support.java @@ -273,6 +273,7 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport { // .notify(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_SENSOR_DATA), enable); builder.notify(getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_3_CONFIGURATION), enable); builder.notify(getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_6_BATTERY_INFO), enable); + builder.notify(getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_10_BUTTON), enable); BluetoothGattCharacteristic heartrateCharacteristic = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_MEASUREMENT); if (heartrateCharacteristic != null) { builder.notify(heartrateCharacteristic, enable); @@ -858,6 +859,9 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport { LOG.info("AUTHENTICATION?? " + characteristicUUID); logMessageContent(characteristic.getValue()); return true; + } else if (MiBand2Service.UUID_CHARACTERISTIC_10_BUTTON.equals(characteristicUUID)) { + handleButtonPressed(characteristic.getValue()); + return true; } else { LOG.info("Unhandled characteristic changed: " + characteristicUUID); logMessageContent(characteristic.getValue()); @@ -865,6 +869,11 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport { return false; } + private void handleButtonPressed(byte[] value) { + LOG.info("Button pressed: " + value); + logMessageContent(value); + } + private void handleUnknownCharacteristic(byte[] value) { } @@ -887,6 +896,9 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport { } else if (MiBandService.UUID_CHARACTERISTIC_DATE_TIME.equals(characteristicUUID)) { logDate(characteristic.getValue(), status); return true; + } else if (MiBand2Service.UUID_CHARACTERISTIC_10_BUTTON.equals(characteristicUUID)) { + handleButtonPressed(characteristic.getValue()); + return true; } else { LOG.info("Unhandled characteristic read: " + characteristicUUID); logMessageContent(characteristic.getValue()); @@ -1260,6 +1272,13 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport { @Override public void onTestNewFunction() { + try { + performInitialized("read characteristic 10") + .read(getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_10_BUTTON)) + .queue(getQueue()); + } catch (IOException e) { + e.printStackTrace(); + } } @Override From 6834f36ec7103f75db7f4fa93c9be019359b93ff Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Tue, 21 Feb 2017 22:52:06 +0100 Subject: [PATCH 49/53] Updated contributors list --- CONTRIBUTORS.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index ca95966ba..62fedfc58 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -25,8 +25,9 @@ * Andreas Shimokawa * Carsten Pfeiffer * Daniele Gobbetti -* Julien Pivotto * João Paulo Barraca +* ivanovlev +* Julien Pivotto * Steffen Liebergeld * Lem Dulfo * Sergey Trofimov @@ -35,9 +36,11 @@ * 0nse <0nse@users.noreply.github.com> * Gergely Peidl * Christian Fischer -* Normano64 * 6arms1leg +* Normano64 +* Avamander * Ⲇⲁⲛⲓ Φi +* Yar * xzovy * xphnx * Tarik Sekmen @@ -51,6 +54,7 @@ * Kevin Richter * Kasha * Ivan +* Hasan Ammar * Gilles MOREL * Gilles Émilien MOREL * Chris Perelstein From 437ec6c9b7938513f9fe4b5bb52f9ca586de8c40 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 23 Feb 2017 08:49:55 +0100 Subject: [PATCH 50/53] Minor improvements to the WIP week sleep chart --- .../charts/AbstractWeekChartFragment.java | 12 +++++++++-- .../charts/WeekSleepChartFragment.java | 21 +++++++++++++++++++ .../charts/WeekStepsChartFragment.java | 12 +++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractWeekChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractWeekChartFragment.java index 478437bd5..4dec8275e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractWeekChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractWeekChartFragment.java @@ -18,6 +18,7 @@ import com.github.mikephil.charting.data.BarEntry; import com.github.mikephil.charting.data.PieData; import com.github.mikephil.charting.data.PieDataSet; import com.github.mikephil.charting.data.PieEntry; +import com.github.mikephil.charting.formatter.IValueFormatter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -90,7 +91,8 @@ public abstract class AbstractWeekChartFragment extends AbstractChartFragment { } BarDataSet set = new BarDataSet(entries, ""); - set.setColor(akActivity.color); + set.setColor(getMainColor()); + set.setValueFormatter(getFormatter()); BarData barData = new BarData(set); barData.setValueTextColor(Color.GRAY); //prevent tearing other graph elements with the black text. Another approach would be to hide the values cmpletely with data.setDrawValues(false); @@ -112,7 +114,7 @@ public abstract class AbstractWeekChartFragment extends AbstractChartFragment { List colors = new ArrayList<>(); entries.add(new PieEntry(totalValue, "")); //we don't want labels on the pie chart - colors.add(akActivity.color); + colors.add(getMainColor()); if (totalValue < mTargetValue) { entries.add(new PieEntry((mTargetValue - totalValue))); //we don't want labels on the pie chart @@ -120,6 +122,7 @@ public abstract class AbstractWeekChartFragment extends AbstractChartFragment { } PieDataSet set = new PieDataSet(entries, ""); + set.setValueFormatter(getFormatter()); set.setColors(colors); data.setDataSet(set); //this hides the values (numeric) added to the set. These would be shown aside the strings set with addXValue above @@ -260,4 +263,9 @@ public abstract class AbstractWeekChartFragment extends AbstractChartFragment { abstract int getGoal(); abstract int getTotalForSamples(List activitySamples); + + abstract IValueFormatter getFormatter(); + + abstract Integer getMainColor(); } + diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekSleepChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekSleepChartFragment.java index 4582d2b0f..98cddf1f4 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekSleepChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekSleepChartFragment.java @@ -1,12 +1,18 @@ package nodomain.freeyourgadget.gadgetbridge.activities.charts; +import com.github.mikephil.charting.data.Entry; +import com.github.mikephil.charting.formatter.IValueFormatter; +import com.github.mikephil.charting.utils.ViewPortHandler; + import java.util.List; +import java.util.concurrent.TimeUnit; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.model.ActivityAmount; import nodomain.freeyourgadget.gadgetbridge.model.ActivityAmounts; import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; +import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils; public class WeekSleepChartFragment extends AbstractWeekChartFragment { @Override @@ -31,4 +37,19 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment { } return (int) (totalSeconds / 60); } + + @Override + IValueFormatter getFormatter() { + return new IValueFormatter() { + @Override + public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) { + return DateTimeUtils.formatDurationHoursMinutes((long) value, TimeUnit.MINUTES); + } + }; + } + + @Override + Integer getMainColor() { + return akLightSleep.color; + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java index d4dd6ce8d..97a1a9c91 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java @@ -1,5 +1,7 @@ package nodomain.freeyourgadget.gadgetbridge.activities.charts; +import com.github.mikephil.charting.formatter.IValueFormatter; + import java.util.List; import nodomain.freeyourgadget.gadgetbridge.R; @@ -27,4 +29,14 @@ public class WeekStepsChartFragment extends AbstractWeekChartFragment { ActivityAnalysis analysis = new ActivityAnalysis(); return analysis.calculateTotalSteps(activitySamples); } + + @Override + IValueFormatter getFormatter() { + return null; + } + + @Override + Integer getMainColor() { + return akActivity.color; + } } From 49e1b55ad873ca5bae835628c0e55a9501fd3935 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 23 Feb 2017 21:15:57 +0100 Subject: [PATCH 51/53] Format center-text for week-sleep-pie --- .../charts/AbstractWeekChartFragment.java | 13 +++++++------ .../activities/charts/WeekSleepChartFragment.java | 7 ++++++- .../activities/charts/WeekStepsChartFragment.java | 5 +++++ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractWeekChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractWeekChartFragment.java index 4dec8275e..572036943 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractWeekChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractWeekChartFragment.java @@ -23,7 +23,6 @@ import com.github.mikephil.charting.formatter.IValueFormatter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.text.NumberFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.List; @@ -60,7 +59,7 @@ public abstract class AbstractWeekChartFragment extends AbstractChartFragment { MyChartsData mcd = (MyChartsData) chartsData; // setupLegend(mWeekChart); - mTodayPieChart.setCenterText(NumberFormat.getNumberInstance(mLocale).format(mcd.getDayData().totalValue)); + mTodayPieChart.setCenterText(mcd.getDayData().centerText); mTodayPieChart.setData(mcd.getDayData().data); mWeekChart.setData(null); // workaround for https://github.com/PhilJay/MPAndroidChart/issues/2317 @@ -128,9 +127,11 @@ public abstract class AbstractWeekChartFragment extends AbstractChartFragment { //this hides the values (numeric) added to the set. These would be shown aside the strings set with addXValue above data.setDrawValues(false); - return new DayData(data, totalValue); + return new DayData(data, formatPieValue(totalValue)); } + protected abstract String formatPieValue(int value); + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -234,11 +235,11 @@ public abstract class AbstractWeekChartFragment extends AbstractChartFragment { private static class DayData { private final PieData data; - private final int totalValue; + private final CharSequence centerText; - DayData(PieData data, int totalValue) { + DayData(PieData data, String centerText) { this.data = data; - this.totalValue = totalValue; + this.centerText = centerText; } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekSleepChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekSleepChartFragment.java index 98cddf1f4..9e85d1449 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekSleepChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekSleepChartFragment.java @@ -38,12 +38,17 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment { return (int) (totalSeconds / 60); } + @Override + protected String formatPieValue(int value) { + return DateTimeUtils.formatDurationHoursMinutes((long) value, TimeUnit.MINUTES); + } + @Override IValueFormatter getFormatter() { return new IValueFormatter() { @Override public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) { - return DateTimeUtils.formatDurationHoursMinutes((long) value, TimeUnit.MINUTES); + return formatPieValue((int) value); } }; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java index 97a1a9c91..5439f2531 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java @@ -30,6 +30,11 @@ public class WeekStepsChartFragment extends AbstractWeekChartFragment { return analysis.calculateTotalSteps(activitySamples); } + @Override + protected String formatPieValue(int value) { + return String.valueOf(value); + } + @Override IValueFormatter getFormatter() { return null; From 08080b02bbffb25a2ee4a7b4f6664dae9bf29517 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 23 Feb 2017 22:44:44 +0100 Subject: [PATCH 52/53] Drop support for legacy (pre 0.12.0) database --- .../gadgetbridge/GBApplication.java | 11 +- .../activities/DbManagementActivity.java | 92 +--------- .../activities/OnboardingActivity.java | 78 --------- .../database/ActivityDatabaseHandler.java | 105 ------------ .../gadgetbridge/database/DBConstants.java | 18 -- .../gadgetbridge/database/DBHelper.java | 160 ------------------ .../schema/ActivityDBCreationScript.java | 27 --- .../database/schema/ActivityDBUpdate_4.java | 31 ---- .../database/schema/ActivityDBUpdate_6.java | 27 --- .../database/schema/ActivityDBUpdate_7.java | 8 - .../service/DeviceCommunicationService.java | 15 -- .../res/layout/activity_db_management.xml | 16 -- .../main/res/layout/activity_onboarding.xml | 31 ---- app/src/main/res/values/strings.xml | 19 +-- 14 files changed, 6 insertions(+), 632 deletions(-) delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/OnboardingActivity.java delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/ActivityDatabaseHandler.java delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBConstants.java delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/ActivityDBCreationScript.java delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/ActivityDBUpdate_4.java delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/ActivityDBUpdate_6.java delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/ActivityDBUpdate_7.java delete mode 100644 app/src/main/res/layout/activity_onboarding.xml diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java index ea3abd190..1973e4e41 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java @@ -27,7 +27,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import nodomain.freeyourgadget.gadgetbridge.database.DBConstants; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; import nodomain.freeyourgadget.gadgetbridge.database.DBOpenHelper; @@ -335,11 +334,7 @@ public class GBApplication extends Application { if (lockHandler != null) { lockHandler.closeDb(); } - DBHelper dbHelper = new DBHelper(context); - boolean result = true; - if (dbHelper.existsDB(DBConstants.DATABASE_NAME)) { - result = getContext().deleteDatabase(DBConstants.DATABASE_NAME); - } + boolean result = deleteOldActivityDatabase(context); result &= getContext().deleteDatabase(DATABASE_NAME); return result; } @@ -352,8 +347,8 @@ public class GBApplication extends Application { public static synchronized boolean deleteOldActivityDatabase(Context context) { DBHelper dbHelper = new DBHelper(context); boolean result = true; - if (dbHelper.existsDB(DBConstants.DATABASE_NAME)) { - result = getContext().deleteDatabase(DBConstants.DATABASE_NAME); + if (dbHelper.existsDB("ActivityDatabase")) { + result = getContext().deleteDatabase("ActivityDatabase"); } return result; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DbManagementActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DbManagementActivity.java index 07e0d22a5..a155c7304 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DbManagementActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DbManagementActivity.java @@ -1,11 +1,9 @@ package nodomain.freeyourgadget.gadgetbridge.activities; import android.app.AlertDialog; -import android.app.ProgressDialog; import android.content.DialogInterface; import android.content.IntentFilter; import android.database.sqlite.SQLiteOpenHelper; -import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.NavUtils; import android.view.MenuItem; @@ -18,16 +16,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; -import java.util.Collections; -import java.util.List; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; -import nodomain.freeyourgadget.gadgetbridge.adapter.GBDeviceAdapter; -import nodomain.freeyourgadget.gadgetbridge.database.ActivityDatabaseHandler; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; -import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; import nodomain.freeyourgadget.gadgetbridge.util.GB; @@ -37,7 +30,6 @@ public class DbManagementActivity extends GBActivity { private Button exportDBButton; private Button importDBButton; - private Button importOldActivityDataButton; private Button deleteOldActivityDBButton; private Button deleteDBButton; private TextView dbPath; @@ -68,22 +60,7 @@ public class DbManagementActivity extends GBActivity { } }); - boolean hasOldDB = hasOldActivityDatabase(); - int oldDBVisibility = hasOldDB ? View.VISIBLE : View.GONE; - - View oldDBTitle = findViewById(R.id.mergeOldActivityDataTitle); - oldDBTitle.setVisibility(oldDBVisibility); - View oldDBText = findViewById(R.id.mergeOldActivityDataText); - oldDBText.setVisibility(oldDBVisibility); - - importOldActivityDataButton = (Button) findViewById(R.id.mergeOldActivityData); - importOldActivityDataButton.setVisibility(oldDBVisibility); - importOldActivityDataButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - mergeOldActivityDbContents(); - } - }); + int oldDBVisibility = hasOldActivityDatabase() ? View.VISIBLE : View.GONE; deleteOldActivityDBButton = (Button) findViewById(R.id.deleteOldActivityDB); deleteOldActivityDBButton.setVisibility(oldDBVisibility); @@ -104,7 +81,7 @@ public class DbManagementActivity extends GBActivity { } private boolean hasOldActivityDatabase() { - return new DBHelper(this).getOldActivityDatabaseHandler() != null; + return new DBHelper(this).existsDB("ActivityDatabase"); } private String getExternalPath() { @@ -156,67 +133,6 @@ public class DbManagementActivity extends GBActivity { .show(); } - private void mergeOldActivityDbContents() { - final DBHelper helper = new DBHelper(getBaseContext()); - final ActivityDatabaseHandler oldHandler = helper.getOldActivityDatabaseHandler(); - if (oldHandler == null) { - GB.toast(this, getString(R.string.dbmanagementactivity_no_old_activitydatabase_found), Toast.LENGTH_LONG, GB.ERROR); - return; - } - selectDeviceForMergingActivityDatabaseInto(new DeviceSelectionCallback() { - @Override - public void invoke(final GBDevice device) { - if (device == null) { - GB.toast(DbManagementActivity.this, getString(R.string.dbmanagementactivity_no_connected_device), Toast.LENGTH_LONG, GB.ERROR); - return; - } - try (DBHandler targetHandler = GBApplication.acquireDB()) { - final ProgressDialog progress = ProgressDialog.show(DbManagementActivity.this, getString(R.string.dbmanagementactivity_merging_activity_data_title), getString(R.string.dbmanagementactivity_please_wait_while_merging), true, false); - new AsyncTask() { - @Override - protected Object doInBackground(Object[] params) { - helper.importOldDb(oldHandler, device, targetHandler); - if (!isFinishing() && !isDestroyed()) { - progress.dismiss(); - } - return null; - } - }.execute((Object[]) null); - } catch (Exception ex) { - GB.toast(DbManagementActivity.this, getString(R.string.dbmanagementactivity_error_importing_old_activity_data), Toast.LENGTH_LONG, GB.ERROR, ex); - } - } - }); - } - - private void selectDeviceForMergingActivityDatabaseInto(final DeviceSelectionCallback callback) { - GBDevice connectedDevice = ((GBApplication)getApplication()).getDeviceManager().getSelectedDevice(); - if (connectedDevice == null) { - callback.invoke(null); - return; - } - final List availableDevices = Collections.singletonList(connectedDevice); - GBDeviceAdapter adapter = new GBDeviceAdapter(getBaseContext(), availableDevices); - - new AlertDialog.Builder(this) - .setCancelable(true) - .setTitle(R.string.dbmanagementactivity_associate_old_data_with_device) - .setAdapter(adapter, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - GBDevice device = availableDevices.get(which); - callback.invoke(device); - } - }) - .setNegativeButton(R.string.Cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - // ignore, just return - } - }) - .show(); - } - private void deleteActivityDatabase() { new AlertDialog.Builder(this) .setCancelable(true) @@ -271,8 +187,4 @@ public class DbManagementActivity extends GBActivity { } return super.onOptionsItemSelected(item); } - - public interface DeviceSelectionCallback { - void invoke(GBDevice device); - } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/OnboardingActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/OnboardingActivity.java deleted file mode 100644 index 043c3741c..000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/OnboardingActivity.java +++ /dev/null @@ -1,78 +0,0 @@ -package nodomain.freeyourgadget.gadgetbridge.activities; - -import android.app.ProgressDialog; -import android.os.AsyncTask; -import android.os.Bundle; -import android.view.View; -import android.widget.Button; -import android.widget.TextView; -import android.widget.Toast; - -import nodomain.freeyourgadget.gadgetbridge.GBApplication; -import nodomain.freeyourgadget.gadgetbridge.R; -import nodomain.freeyourgadget.gadgetbridge.database.ActivityDatabaseHandler; -import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; -import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; -import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; -import nodomain.freeyourgadget.gadgetbridge.util.GB; - -public class OnboardingActivity extends GBActivity { - - private Button importOldActivityDataButton; - private TextView importOldActivityDataText; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_onboarding); - - Bundle extras = getIntent().getExtras(); - - GBDevice device; - if (extras != null) { - device = extras.getParcelable(GBDevice.EXTRA_DEVICE); - } else { - throw new IllegalArgumentException("Must provide a device when invoking this activity"); - } - - importOldActivityDataText = (TextView) findViewById(R.id.textview_import_old_activitydata); - importOldActivityDataText.setText(String.format(getString(R.string.import_old_db_information), device.getName())); - importOldActivityDataButton = (Button) findViewById(R.id.button_import_old_activitydata); - final GBDevice finalDevice = device; - importOldActivityDataButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - mergeOldActivityDbContents(finalDevice); - } - }); - } - - private void mergeOldActivityDbContents(final GBDevice device) { - if (device == null) { - return; - } - - final DBHelper helper = new DBHelper(getBaseContext()); - final ActivityDatabaseHandler oldHandler = helper.getOldActivityDatabaseHandler(); - if (oldHandler == null) { - GB.toast(this, "No old activity database found, nothing to import.", Toast.LENGTH_LONG, GB.ERROR); - return; - } - - try (DBHandler targetHandler = GBApplication.acquireDB()) { - final ProgressDialog progress = ProgressDialog.show(OnboardingActivity.this, "Merging Activity Data", "Please wait while merging your activity data...", true, false); - new AsyncTask() { - @Override - protected Object doInBackground(Object[] params) { - helper.importOldDb(oldHandler, device, targetHandler); - progress.dismiss(); - finish(); - return null; - } - }.execute((Object[]) null); - } catch (Exception ex) { - GB.toast(OnboardingActivity.this, "Error importing old activity data into new database.", Toast.LENGTH_LONG, GB.ERROR, ex); - } - } - -} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/ActivityDatabaseHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/ActivityDatabaseHandler.java deleted file mode 100644 index 221cf410a..000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/ActivityDatabaseHandler.java +++ /dev/null @@ -1,105 +0,0 @@ -package nodomain.freeyourgadget.gadgetbridge.database; - -import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import android.widget.Toast; - -import java.io.File; - -import nodomain.freeyourgadget.gadgetbridge.database.schema.ActivityDBCreationScript; -import nodomain.freeyourgadget.gadgetbridge.database.schema.SchemaMigration; -import nodomain.freeyourgadget.gadgetbridge.entities.DaoMaster; -import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; -import nodomain.freeyourgadget.gadgetbridge.util.GB; - -import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.DATABASE_NAME; -import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_TIMESTAMP; -import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.TABLE_GBACTIVITYSAMPLES; - -/** - * @deprecated can be removed entirely, only used for backwards compatibility - */ -public class ActivityDatabaseHandler extends SQLiteOpenHelper implements DBHandler { - - private static final int DATABASE_VERSION = 7; - private static final String UPDATER_CLASS_NAME_PREFIX = "ActivityDBUpdate_"; - private final Context context; - - public ActivityDatabaseHandler(Context context) { - super(context, DATABASE_NAME, null, DATABASE_VERSION); - this.context = context; - } - - @Override - public void onCreate(SQLiteDatabase db) { - try { - ActivityDBCreationScript script = new ActivityDBCreationScript(); - script.createSchema(db); - } catch (RuntimeException ex) { - GB.toast("Error creating database.", Toast.LENGTH_SHORT, GB.ERROR, ex); - } - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - new SchemaMigration(UPDATER_CLASS_NAME_PREFIX).onUpgrade(db, oldVersion, newVersion); - } - - @Override - public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { - new SchemaMigration(UPDATER_CLASS_NAME_PREFIX).onDowngrade(db, oldVersion, newVersion); - } - - @Override - public SQLiteDatabase getDatabase() { - return super.getWritableDatabase(); - } - - @Override - public void closeDb() { - } - - @Override - public void openDb() { - } - - @Override - public SQLiteOpenHelper getHelper() { - return this; - } - - public Context getContext() { - return context; - } - - public boolean hasContent() { - File dbFile = getContext().getDatabasePath(getDatabaseName()); - if (dbFile == null || !dbFile.exists()) { - return false; - } - - try { - try (SQLiteDatabase db = this.getReadableDatabase()) { - try (Cursor cursor = db.query(TABLE_GBACTIVITYSAMPLES, new String[]{KEY_TIMESTAMP}, null, null, null, null, null, "1")) { - return cursor.moveToFirst(); - } - } - } catch (Exception ex) { - // can't expect anything - GB.log("Error looking for old activity data: " + ex.getMessage(), GB.ERROR, ex); - return false; - } - } - - @Override - public DaoSession getDaoSession() { - throw new UnsupportedOperationException(); - } - - @Override - public DaoMaster getDaoMaster() { - throw new UnsupportedOperationException(); - } -} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBConstants.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBConstants.java deleted file mode 100644 index 671b5af38..000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBConstants.java +++ /dev/null @@ -1,18 +0,0 @@ -package nodomain.freeyourgadget.gadgetbridge.database; - -/** - * TODO: Legacy, can be removed once migration support for old ActivityDatabase is removed - * @deprecated only for backwards compatibility - */ -public class DBConstants { - public static final String DATABASE_NAME = "ActivityDatabase"; - - public static final String TABLE_GBACTIVITYSAMPLES = "GBActivitySamples"; - - public static final String KEY_TIMESTAMP = "timestamp"; - public static final String KEY_PROVIDER = "provider"; - public static final String KEY_INTENSITY = "intensity"; - public static final String KEY_STEPS = "steps"; - public static final String KEY_CUSTOM_SHORT = "customShort"; - public static final String KEY_TYPE = "type"; -} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBHelper.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBHelper.java index 35f0efbf7..c6d894f9a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBHelper.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBHelper.java @@ -6,7 +6,6 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.widget.Toast; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -14,7 +13,6 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; -import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; @@ -26,11 +24,7 @@ import de.greenrobot.dao.query.Query; import de.greenrobot.dao.query.QueryBuilder; import de.greenrobot.dao.query.WhereCondition; import nodomain.freeyourgadget.gadgetbridge.GBApplication; -import nodomain.freeyourgadget.gadgetbridge.devices.AbstractSampleProvider; import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator; -import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleHealthSampleProvider; -import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleMisfitSampleProvider; -import nodomain.freeyourgadget.gadgetbridge.entities.AbstractActivitySample; import nodomain.freeyourgadget.gadgetbridge.entities.ActivityDescription; import nodomain.freeyourgadget.gadgetbridge.entities.ActivityDescriptionDao; import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; @@ -38,29 +32,18 @@ import nodomain.freeyourgadget.gadgetbridge.entities.Device; import nodomain.freeyourgadget.gadgetbridge.entities.DeviceAttributes; import nodomain.freeyourgadget.gadgetbridge.entities.DeviceAttributesDao; import nodomain.freeyourgadget.gadgetbridge.entities.DeviceDao; -import nodomain.freeyourgadget.gadgetbridge.entities.PebbleHealthActivityOverlay; -import nodomain.freeyourgadget.gadgetbridge.entities.PebbleHealthActivityOverlayDao; import nodomain.freeyourgadget.gadgetbridge.entities.Tag; import nodomain.freeyourgadget.gadgetbridge.entities.TagDao; import nodomain.freeyourgadget.gadgetbridge.entities.User; import nodomain.freeyourgadget.gadgetbridge.entities.UserAttributes; import nodomain.freeyourgadget.gadgetbridge.entities.UserDao; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; -import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind; -import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser; import nodomain.freeyourgadget.gadgetbridge.model.ValidByDate; import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils; import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper; import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; -import nodomain.freeyourgadget.gadgetbridge.util.GB; -import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_CUSTOM_SHORT; -import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_INTENSITY; -import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_STEPS; -import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_TIMESTAMP; -import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_TYPE; -import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.TABLE_GBACTIVITYSAMPLES; /** * Provides utiliy access to some common entities, so you won't need to use @@ -547,149 +530,6 @@ public class DBHelper { return tag; } - /** - * Returns the old activity database handler if there is any content in that - * db, or null otherwise. - * - * @return the old activity db handler or null - */ - @Nullable - public ActivityDatabaseHandler getOldActivityDatabaseHandler() { - ActivityDatabaseHandler handler = new ActivityDatabaseHandler(context); - if (handler.hasContent()) { - return handler; - } - return null; - } - - public void importOldDb(ActivityDatabaseHandler oldDb, GBDevice targetDevice, DBHandler targetDBHandler) { - DaoSession tempSession = targetDBHandler.getDaoMaster().newSession(); - try { - importActivityDatabase(oldDb, targetDevice, tempSession); - } finally { - tempSession.clear(); - } - } - - private boolean isEmpty(DaoSession session) { - long totalSamplesCount = session.getMiBandActivitySampleDao().count(); - totalSamplesCount += session.getPebbleHealthActivitySampleDao().count(); - return totalSamplesCount == 0; - } - - private void importActivityDatabase(ActivityDatabaseHandler oldDbHandler, GBDevice targetDevice, DaoSession session) { - try (SQLiteDatabase oldDB = oldDbHandler.getReadableDatabase()) { - User user = DBHelper.getUser(session); - for (DeviceCoordinator coordinator : DeviceHelper.getInstance().getAllCoordinators()) { - if (coordinator.supports(targetDevice)) { - AbstractSampleProvider sampleProvider = (AbstractSampleProvider) coordinator.getSampleProvider(targetDevice, session); - importActivitySamples(oldDB, targetDevice, session, sampleProvider, user); - break; - } - } - } - } - - private void importActivitySamples(SQLiteDatabase fromDb, GBDevice targetDevice, DaoSession targetSession, AbstractSampleProvider sampleProvider, User user) { - if (sampleProvider instanceof PebbleMisfitSampleProvider) { - GB.toast(context, "Migration of old Misfit data is not supported!", Toast.LENGTH_LONG, GB.WARN); - return; - } - - String order = "timestamp"; - final String where = "provider=" + sampleProvider.getID(); - - boolean convertActivityTypeToRange = false; - int currentTypeRun, previousTypeRun, currentTimeStamp, currentTypeStartTimeStamp, currentTypeEndTimeStamp; - List overlayList = new ArrayList<>(); - - final int BATCH_SIZE = 100000; // 100.000 samples = rougly 20 MB per batch - List newSamples; - if (sampleProvider instanceof PebbleHealthSampleProvider) { - convertActivityTypeToRange = true; - previousTypeRun = ActivitySample.NOT_MEASURED; - currentTypeStartTimeStamp = -1; - currentTypeEndTimeStamp = -1; - - } else { - previousTypeRun = currentTypeStartTimeStamp = currentTypeEndTimeStamp = 0; - } - try (Cursor cursor = fromDb.query(TABLE_GBACTIVITYSAMPLES, null, where, null, null, null, order)) { - int colTimeStamp = cursor.getColumnIndex(KEY_TIMESTAMP); - int colIntensity = cursor.getColumnIndex(KEY_INTENSITY); - int colSteps = cursor.getColumnIndex(KEY_STEPS); - int colType = cursor.getColumnIndex(KEY_TYPE); - int colCustomShort = cursor.getColumnIndex(KEY_CUSTOM_SHORT); - long deviceId = DBHelper.getDevice(targetDevice, targetSession).getId(); - long userId = user.getId(); - newSamples = new ArrayList<>(Math.min(BATCH_SIZE, cursor.getCount())); - while (cursor.moveToNext()) { - T newSample = sampleProvider.createActivitySample(); - newSample.setProvider(sampleProvider); - newSample.setUserId(userId); - newSample.setDeviceId(deviceId); - currentTimeStamp = cursor.getInt(colTimeStamp); - newSample.setTimestamp(currentTimeStamp); - newSample.setRawIntensity(getNullableInt(cursor, colIntensity, ActivitySample.NOT_MEASURED)); - currentTypeRun = getNullableInt(cursor, colType, ActivitySample.NOT_MEASURED); - newSample.setRawKind(currentTypeRun); - if (convertActivityTypeToRange) { - //at the beginning there is no start timestamp - if (currentTypeStartTimeStamp == -1) { - currentTypeStartTimeStamp = currentTypeEndTimeStamp = currentTimeStamp; - previousTypeRun = currentTypeRun; - } - - if (currentTypeRun != previousTypeRun) { - //we used not to store the last sample, now we do the opposite and we need to round up - currentTypeEndTimeStamp = currentTimeStamp; - //if the Type has changed, the run has ended. Only store light and deep sleep data - if (previousTypeRun == 4) { - overlayList.add(new PebbleHealthActivityOverlay(currentTypeStartTimeStamp, currentTypeEndTimeStamp, sampleProvider.toRawActivityKind(ActivityKind.TYPE_LIGHT_SLEEP), deviceId, userId, null)); - } else if (previousTypeRun == 5) { - overlayList.add(new PebbleHealthActivityOverlay(currentTypeStartTimeStamp, currentTypeEndTimeStamp, sampleProvider.toRawActivityKind(ActivityKind.TYPE_DEEP_SLEEP), deviceId, userId, null)); - } - currentTypeStartTimeStamp = currentTimeStamp; - previousTypeRun = currentTypeRun; - } else { - //just expand the run - currentTypeEndTimeStamp = currentTimeStamp; - } - - } - newSample.setSteps(getNullableInt(cursor, colSteps, ActivitySample.NOT_MEASURED)); - if (colCustomShort > -1) { - newSample.setHeartRate(getNullableInt(cursor, colCustomShort, ActivitySample.NOT_MEASURED)); - } else { - newSample.setHeartRate(ActivitySample.NOT_MEASURED); - } - newSamples.add(newSample); - - if ((newSamples.size() % BATCH_SIZE) == 0) { - sampleProvider.getSampleDao().insertOrReplaceInTx(newSamples, true); - targetSession.clear(); - newSamples.clear(); - } - } - // and insert the remaining samples - if (!newSamples.isEmpty()) { - sampleProvider.getSampleDao().insertOrReplaceInTx(newSamples, true); - } - // store the overlay records - if (!overlayList.isEmpty()) { - PebbleHealthActivityOverlayDao overlayDao = targetSession.getPebbleHealthActivityOverlayDao(); - overlayDao.insertOrReplaceInTx(overlayList); - } - } - } - - private int getNullableInt(Cursor cursor, int columnIndex, int defaultValue) { - if (cursor.isNull(columnIndex)) { - return defaultValue; - } - return cursor.getInt(columnIndex); - } - public static void clearSession() { try (DBHandler dbHandler = GBApplication.acquireDB()) { DaoSession session = dbHandler.getDaoSession(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/ActivityDBCreationScript.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/ActivityDBCreationScript.java deleted file mode 100644 index 20c4ac5b7..000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/ActivityDBCreationScript.java +++ /dev/null @@ -1,27 +0,0 @@ -package nodomain.freeyourgadget.gadgetbridge.database.schema; - -import android.database.sqlite.SQLiteDatabase; - -import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; - -import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_CUSTOM_SHORT; -import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_INTENSITY; -import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_PROVIDER; -import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_STEPS; -import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_TIMESTAMP; -import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_TYPE; -import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.TABLE_GBACTIVITYSAMPLES; - -public class ActivityDBCreationScript { - public void createSchema(SQLiteDatabase db) { - String CREATE_GBACTIVITYSAMPLES_TABLE = "CREATE TABLE " + TABLE_GBACTIVITYSAMPLES + " (" - + KEY_TIMESTAMP + " INT," - + KEY_PROVIDER + " TINYINT," - + KEY_INTENSITY + " SMALLINT," - + KEY_STEPS + " TINYINT," - + KEY_TYPE + " TINYINT," - + KEY_CUSTOM_SHORT + " INT," - + " PRIMARY KEY (" + KEY_TIMESTAMP + "," + KEY_PROVIDER + ") ON CONFLICT REPLACE)" + DBHelper.getWithoutRowId(); - db.execSQL(CREATE_GBACTIVITYSAMPLES_TABLE); - } -} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/ActivityDBUpdate_4.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/ActivityDBUpdate_4.java deleted file mode 100644 index c27b3dc7c..000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/ActivityDBUpdate_4.java +++ /dev/null @@ -1,31 +0,0 @@ -package nodomain.freeyourgadget.gadgetbridge.database.schema; - -import android.database.sqlite.SQLiteDatabase; - -import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; -import nodomain.freeyourgadget.gadgetbridge.database.DBUpdateScript; - -import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.TABLE_GBACTIVITYSAMPLES; - -/** - * Upgrade and downgrade with DB versions <= 5 is not supported. - * Just recreates the default schema. Those GB versions may or may not - * work with that, but this code will probably not create a DB for them - * anyway. - */ -public class ActivityDBUpdate_4 extends ActivityDBCreationScript implements DBUpdateScript { - @Override - public void upgradeSchema(SQLiteDatabase db) { - recreateSchema(db); - } - - @Override - public void downgradeSchema(SQLiteDatabase db) { - recreateSchema(db); - } - - private void recreateSchema(SQLiteDatabase db) { - DBHelper.dropTable(TABLE_GBACTIVITYSAMPLES, db); - createSchema(db); - } -} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/ActivityDBUpdate_6.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/ActivityDBUpdate_6.java deleted file mode 100644 index b6d157c9c..000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/ActivityDBUpdate_6.java +++ /dev/null @@ -1,27 +0,0 @@ -package nodomain.freeyourgadget.gadgetbridge.database.schema; - -import android.database.sqlite.SQLiteDatabase; - -import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; -import nodomain.freeyourgadget.gadgetbridge.database.DBUpdateScript; - -import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_CUSTOM_SHORT; -import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.TABLE_GBACTIVITYSAMPLES; - -/** - * Adds a column "customShort" to the table "GBActivitySamples" - */ -public class ActivityDBUpdate_6 implements DBUpdateScript { - @Override - public void upgradeSchema(SQLiteDatabase db) { - if (!DBHelper.existsColumn(TABLE_GBACTIVITYSAMPLES, KEY_CUSTOM_SHORT, db)) { - String ADD_COLUMN_CUSTOM_SHORT = "ALTER TABLE " + TABLE_GBACTIVITYSAMPLES + " ADD COLUMN " - + KEY_CUSTOM_SHORT + " INT;"; - db.execSQL(ADD_COLUMN_CUSTOM_SHORT); - } - } - - @Override - public void downgradeSchema(SQLiteDatabase db) { - } -} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/ActivityDBUpdate_7.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/ActivityDBUpdate_7.java deleted file mode 100644 index c7077451f..000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/ActivityDBUpdate_7.java +++ /dev/null @@ -1,8 +0,0 @@ -package nodomain.freeyourgadget.gadgetbridge.database.schema; - -/** - * Bugfix for users who installed 0.8.1 cleanly, i.e. without any previous - * database. Perform Update script 6 again. - */ -public class ActivityDBUpdate_7 extends ActivityDBUpdate_6 { -} 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 d88594e9c..cae037f72 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -23,7 +23,6 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; -import nodomain.freeyourgadget.gadgetbridge.activities.OnboardingActivity; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; @@ -40,7 +39,6 @@ import nodomain.freeyourgadget.gadgetbridge.model.Alarm; import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec; import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec; -import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; @@ -195,20 +193,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere if (device.isInitialized()) { try (DBHandler dbHandler = GBApplication.acquireDB()) { DaoSession session = dbHandler.getDaoSession(); - boolean askForDBMigration = false; - if (DBHelper.findDevice(device, session) == null && device.getType() != DeviceType.VIBRATISSIMO && (device.getType() != DeviceType.LIVEVIEW)) { - askForDBMigration = true; - } DBHelper.getDevice(device, session); // implicitly creates the device in database if not present, and updates device attributes - if (askForDBMigration) { - DBHelper dbHelper = new DBHelper(context); - if (dbHelper.getOldActivityDatabaseHandler() != null) { - Intent startIntent = new Intent(context, OnboardingActivity.class); - startIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startIntent.putExtra(GBDevice.EXTRA_DEVICE, device); - startActivity(startIntent); - } - } } catch (Exception ignore) { } } diff --git a/app/src/main/res/layout/activity_db_management.xml b/app/src/main/res/layout/activity_db_management.xml index feb005a4f..0bf641ccf 100644 --- a/app/src/main/res/layout/activity_db_management.xml +++ b/app/src/main/res/layout/activity_db_management.xml @@ -31,7 +31,6 @@ android:layout_height="wrap_content" android:layout_weight="1" - android:singleLine="false" android:text="Export DB" />