diff --git a/CHANGELOG.md b/CHANGELOG.md
index c34cdbdc9..19ab2fbbd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,12 @@
###Changelog
+####Version 0.10.1
+* Pebble: set extended music info by dissecting notifications on Android 5.0+
+* Pebble: various other improvemnts to music playback
+* Pebble: allow ignoring activity trackers indiviually (to keep the data on the pebble)
+* Mi Band: support for shifting the device time by N hours (for people who sleep at daytime)
+* Mi Band: initial and untested support for Mi Band 2
+* Allow setting the application language
+
####Version 0.10.0
* Pebble: option to send sunrise and sunset events to timeline
* Pebble: fix problems with unknown app keys while configuring watchfaces
diff --git a/app/build.gradle b/app/build.gradle
index 82f0d9a12..607ee74b9 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -18,8 +18,8 @@ android {
targetSdkVersion 23
// note: always bump BOTH versionCode and versionName!
- versionName "0.10.0"
- versionCode 53
+ versionName "0.10.1"
+ versionCode 54
}
buildTypes {
release {
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java
index f66bd7310..db758d3b0 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java
@@ -193,6 +193,9 @@ public class AppManagerActivity extends GBActivity {
if (!selectedApp.isConfigurable()) {
menu.removeItem(R.id.appmanager_app_configure);
}
+ if (mGBDevice != null && !mGBDevice.getFirmwareVersion().startsWith("v3")) {
+ menu.removeItem(R.id.appmanager_app_move_to_top);
+ }
menu.setHeaderTitle(selectedApp.getName());
}
@@ -256,6 +259,9 @@ public class AppManagerActivity extends GBActivity {
startIntent.putExtra(GBDevice.EXTRA_DEVICE, mGBDevice);
startActivity(startIntent);
return true;
+ case R.id.appmanager_app_move_to_top:
+ GBApplication.deviceService().onAppReorder(new UUID[]{selectedApp.getUUID()});
+ return true;
default:
return super.onContextItemSelected(item);
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java
index f53cf085e..c3526d7fc 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java
@@ -37,6 +37,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
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.util.FileUtils;
@@ -222,6 +223,15 @@ public class DebugActivity extends GBActivity {
musicSpec.trackNr = 2;
GBApplication.deviceService().onSetMusicInfo(musicSpec);
+
+ MusicStateSpec stateSpec = new MusicStateSpec();
+ stateSpec.position = 0;
+ stateSpec.state = 0x01; // playing
+ stateSpec.playRate = 100;
+ stateSpec.repeat = 1;
+ stateSpec.shuffle = 1;
+
+ GBApplication.deviceService().onSetMusicState(stateSpec);
}
});
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java
index 602ca5c85..97e0f8f6a 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java
@@ -9,6 +9,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
+import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
/**
@@ -25,6 +26,8 @@ public interface EventHandler {
void onSetCallState(CallSpec callSpec);
+ void onSetMusicState(MusicStateSpec stateSpec);
+
void onSetMusicInfo(MusicSpec musicSpec);
void onEnableRealtimeSteps(boolean enable);
@@ -39,6 +42,8 @@ public interface EventHandler {
void onAppConfiguration(UUID appUuid, String config);
+ void onAppReorder(UUID uuids[]);
+
void onFetchActivityData();
void onReboot();
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 67c7e8e70..3edfb8815 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/MusicPlaybackReceiver.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/MusicPlaybackReceiver.java
@@ -3,30 +3,54 @@ 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;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
+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();
@Override
public void onReceive(Context context, Intent intent) {
- String artist = intent.getStringExtra("artist");
- String album = intent.getStringExtra("album");
- String track = intent.getStringExtra("track");
-
- LOG.info("Current track: " + artist + ", " + album + ", " + track);
-
+ /*
+ Bundle bundle = intent.getExtras();
+ for (String key : bundle.keySet()) {
+ Object value = bundle.get(key);
+ LOG.info(String.format("%s %s (%s)", key,
+ value != null ? value.toString() : "null", value != null ? value.getClass().getName() : "no class"));
+ }
+ */
MusicSpec musicSpec = new MusicSpec();
- musicSpec.artist = artist;
- musicSpec.album = album;
- musicSpec.track = track;
+ musicSpec.artist = intent.getStringExtra("artist");
+ musicSpec.album = intent.getStringExtra("album");
+ musicSpec.track = intent.getStringExtra("track");
+ musicSpec.duration = intent.getIntExtra("duration", 0) / 1000;
- GBApplication.deviceService().onSetMusicInfo(musicSpec);
+ if (!lastMusicSpec.equals(musicSpec)) {
+ lastMusicSpec = musicSpec;
+ 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.");
+ }
+
+ 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);
+ } else {
+ LOG.info("got state changed intent, but not enough has changed, ignoring.");
+ }
+ lastStatecSpec = stateSpec;
+ }
}
}
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 a3c3d37c4..cf74be6a4 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java
@@ -11,6 +11,11 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.media.MediaMetadata;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.media.session.PlaybackState;
+import android.os.Build;
import android.os.Bundle;
import android.os.PowerManager;
import android.service.notification.NotificationListenerService;
@@ -25,6 +30,8 @@ import org.slf4j.LoggerFactory;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
+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.service.DeviceCommunicationService;
@@ -161,13 +168,6 @@ public class NotificationListener extends NotificationListenerService {
return;
}
- Prefs prefs = GBApplication.getPrefs();
- if (!prefs.getBoolean("notifications_generic_whenscreenon", false)) {
- PowerManager powermanager = (PowerManager) getSystemService(POWER_SERVICE);
- if (powermanager.isScreenOn()) {
- return;
- }
- }
switch (GBApplication.getGrantedInterruptionFilter()) {
case NotificationManager.INTERRUPTION_FILTER_ALL:
break;
@@ -182,6 +182,17 @@ public class NotificationListener extends NotificationListenerService {
String source = sbn.getPackageName();
Notification notification = sbn.getNotification();
+ if (handleMediaSessionNotification(notification))
+ return;
+
+ Prefs prefs = GBApplication.getPrefs();
+ if (!prefs.getBoolean("notifications_generic_whenscreenon", false)) {
+ PowerManager powermanager = (PowerManager) getSystemService(POWER_SERVICE);
+ if (powermanager.isScreenOn()) {
+ return;
+ }
+ }
+
if ((notification.flags & Notification.FLAG_ONGOING_EVENT) == Notification.FLAG_ONGOING_EVENT) {
return;
}
@@ -311,6 +322,79 @@ public class NotificationListener extends NotificationListenerService {
return false;
}
+ /**
+ * Try to handle media session notifications that tell info about the current play state.
+ *
+ * @param notification The notification to handle.
+ * @return true if notification was handled, false otherwise
+ */
+ public boolean handleMediaSessionNotification(Notification notification) {
+
+ // this code requires Android 5.0 or newer
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+ return false;
+ }
+
+ MusicSpec musicSpec = new MusicSpec();
+ MusicStateSpec stateSpec = new MusicStateSpec();
+
+ Bundle extras = notification.extras;
+ if (extras == null)
+ return false;
+
+ if (extras.get(Notification.EXTRA_MEDIA_SESSION) == null)
+ return false;
+
+ MediaController c;
+ try {
+ c = new MediaController(getApplicationContext(), (MediaSession.Token) extras.get(Notification.EXTRA_MEDIA_SESSION));
+ } 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
public void onNotificationRemoved(StatusBarNotification sbn) {
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 2e598eacf..1aa83c9c3 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java
@@ -14,9 +14,12 @@ import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
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.service.DeviceCommunicationService;
+//import java.util.UUID;
+
public class GBDeviceService implements DeviceService {
protected final Context mContext;
protected final Class extends Service> mServiceClass;
@@ -125,6 +128,17 @@ public class GBDeviceService implements DeviceService {
invokeService(intent);
}
+ @Override
+ public void onSetMusicState(MusicStateSpec stateSpec) {
+ Intent intent = createIntent().setAction(ACTION_SETMUSICSTATE)
+ .putExtra(EXTRA_MUSIC_REPEAT, stateSpec.repeat)
+ .putExtra(EXTRA_MUSIC_RATE, stateSpec.playRate)
+ .putExtra(EXTRA_MUSIC_STATE, stateSpec.state)
+ .putExtra(EXTRA_MUSIC_SHUFFLE, stateSpec.shuffle)
+ .putExtra(EXTRA_MUSIC_POSITION, stateSpec.position);
+ invokeService(intent);
+ }
+
@Override
public void onSetMusicInfo(MusicSpec musicSpec) {
Intent intent = createIntent().setAction(ACTION_SETMUSICINFO)
@@ -173,6 +187,13 @@ public class GBDeviceService implements DeviceService {
invokeService(intent);
}
+ @Override
+ public void onAppReorder(UUID[] uuids) {
+ Intent intent = createIntent().setAction(ACTION_APP_REORDER)
+ .putExtra(EXTRA_APP_UUID, uuids);
+ invokeService(intent);
+ }
+
@Override
public void onFetchActivityData() {
Intent intent = createIntent().setAction(ACTION_FETCH_ACTIVITY_DATA);
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 aaf02798b..59518f7ab 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java
@@ -18,12 +18,14 @@ public interface DeviceService extends EventHandler {
String ACTION_CALLSTATE = PREFIX + ".action.callstate";
String ACTION_SETTIME = PREFIX + ".action.settime";
String ACTION_SETMUSICINFO = PREFIX + ".action.setmusicinfo";
+ String ACTION_SETMUSICSTATE = PREFIX + ".action.setmusicstate";
String ACTION_REQUEST_DEVICEINFO = PREFIX + ".action.request_deviceinfo";
String ACTION_REQUEST_APPINFO = PREFIX + ".action.request_appinfo";
String ACTION_REQUEST_SCREENSHOT = PREFIX + ".action.request_screenshot";
String ACTION_STARTAPP = PREFIX + ".action.startapp";
String ACTION_DELETEAPP = PREFIX + ".action.deleteapp";
String ACTION_APP_CONFIGURE = PREFIX + ".action.app_configure";
+ String ACTION_APP_REORDER = PREFIX + ".action.app_reorder";
String ACTION_INSTALL = PREFIX + ".action.install";
String ACTION_REBOOT = PREFIX + ".action.reboot";
String ACTION_HEARTRATE_TEST = PREFIX + ".action.heartrate_test";
@@ -57,6 +59,11 @@ public interface DeviceService extends EventHandler {
String EXTRA_MUSIC_DURATION = "music_duration";
String EXTRA_MUSIC_TRACKNR = "music_tracknr";
String EXTRA_MUSIC_TRACKCOUNT = "music_trackcount";
+ String EXTRA_MUSIC_STATE = "music_state";
+ String EXTRA_MUSIC_SHUFFLE = "music_shuffle";
+ String EXTRA_MUSIC_REPEAT = "music_repeat";
+ String EXTRA_MUSIC_POSITION = "music_position";
+ String EXTRA_MUSIC_RATE = "music_rate";
String EXTRA_APP_UUID = "app_uuid";
String EXTRA_APP_START = "app_start";
String EXTRA_APP_CONFIG = "app_config";
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 af52f02f1..aa9f67ca9 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicSpec.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicSpec.java
@@ -1,5 +1,7 @@
package nodomain.freeyourgadget.gadgetbridge.model;
+import java.util.Objects;
+
public class MusicSpec {
public static final int MUSIC_UNDEFINED = 0;
public static final int MUSIC_PLAY = 1;
@@ -14,4 +16,23 @@ public class MusicSpec {
public int duration;
public int trackCount;
public int trackNr;
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof MusicSpec)) {
+ return false;
+ }
+ MusicSpec musicSpec = (MusicSpec) obj;
+
+ return Objects.equals(this.artist, musicSpec.artist) &&
+ Objects.equals(this.album, musicSpec.album) &&
+ Objects.equals(this.track, musicSpec.track) &&
+ this.duration == musicSpec.duration &&
+ this.trackCount == musicSpec.trackCount &&
+ this.trackNr == musicSpec.trackNr;
+
+ }
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicStateSpec.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicStateSpec.java
new file mode 100644
index 000000000..fb15948d7
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/MusicStateSpec.java
@@ -0,0 +1,34 @@
+package nodomain.freeyourgadget.gadgetbridge.model;
+
+/**
+ * Created by steffen on 07.06.16.
+ */
+public class MusicStateSpec {
+ public static final int STATE_PLAYING = 0;
+ public static final int STATE_PAUSED = 1;
+ public static final int STATE_STOPPED = 2;
+ public static final int STATE_UNKNOWN = 3;
+
+ public byte state;
+ public int position;
+ public int playRate;
+ public byte shuffle;
+ public byte repeat;
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof MusicStateSpec)) {
+ return false;
+ }
+ MusicStateSpec stateSpec = (MusicStateSpec) obj;
+
+ return this.state == stateSpec.state &&
+ Math.abs(this.position - stateSpec.position)<=2 &&
+ this.playRate == stateSpec.playRate &&
+ this.shuffle == stateSpec.shuffle &&
+ this.repeat == stateSpec.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 fdafa5265..f66ed5041 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java
@@ -38,6 +38,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
+import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
@@ -47,6 +48,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_ADD_CALENDAREVENT;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_APP_CONFIGURE;
+import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_APP_REORDER;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_CALLSTATE;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_CONNECT;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_DELETEAPP;
@@ -65,6 +67,7 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_RE
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_REQUEST_DEVICEINFO;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_REQUEST_SCREENSHOT;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_SETMUSICINFO;
+import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_SETMUSICSTATE;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_SETTIME;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_SET_ALARMS;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_START;
@@ -87,6 +90,11 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_FIN
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUSIC_ALBUM;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUSIC_ARTIST;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUSIC_DURATION;
+import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUSIC_POSITION;
+import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUSIC_RATE;
+import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUSIC_REPEAT;
+import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUSIC_SHUFFLE;
+import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUSIC_STATE;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUSIC_TRACK;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUSIC_TRACKCOUNT;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUSIC_TRACKNR;
@@ -351,6 +359,15 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
musicSpec.trackNr = intent.getIntExtra(EXTRA_MUSIC_TRACKNR, 0);
mDeviceSupport.onSetMusicInfo(musicSpec);
break;
+ case ACTION_SETMUSICSTATE:
+ MusicStateSpec stateSpec = new MusicStateSpec();
+ stateSpec.shuffle = intent.getByteExtra(EXTRA_MUSIC_SHUFFLE, (byte)0);
+ stateSpec.repeat = intent.getByteExtra(EXTRA_MUSIC_REPEAT, (byte)0);
+ stateSpec.position = intent.getIntExtra(EXTRA_MUSIC_POSITION, 0);
+ stateSpec.playRate = intent.getIntExtra(EXTRA_MUSIC_RATE, 0);
+ stateSpec.state = intent.getByteExtra(EXTRA_MUSIC_STATE, (byte)0);
+ mDeviceSupport.onSetMusicState(stateSpec);
+ break;
case ACTION_REQUEST_APPINFO:
mDeviceSupport.onAppInfoReq();
break;
@@ -372,6 +389,12 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
UUID uuid = (UUID) intent.getSerializableExtra(EXTRA_APP_UUID);
String config = intent.getStringExtra(EXTRA_APP_CONFIG);
mDeviceSupport.onAppConfiguration(uuid, config);
+ break;
+ }
+ case ACTION_APP_REORDER: {
+ UUID[] uuids = (UUID[]) intent.getSerializableExtra(EXTRA_APP_UUID);
+ mDeviceSupport.onAppReorder(uuids);
+ break;
}
case ACTION_INSTALL:
Uri uri = intent.getParcelableExtra(EXTRA_URI);
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java
index 019722b54..bf43077be 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java
@@ -16,6 +16,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
+import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
/**
@@ -150,6 +151,14 @@ public class ServiceDeviceSupport implements DeviceSupport {
delegate.onSetCallState(callSpec);
}
+ @Override
+ public void onSetMusicState(MusicStateSpec stateSpec) {
+ if (checkBusy("set music state")) {
+ return;
+ }
+ delegate.onSetMusicState(stateSpec);
+ }
+
@Override
public void onSetMusicInfo(MusicSpec musicSpec) {
if (checkBusy("set music info")) {
@@ -198,6 +207,14 @@ public class ServiceDeviceSupport implements DeviceSupport {
delegate.onAppConfiguration(uuid, config);
}
+ @Override
+ public void onAppReorder(UUID[] uuids) {
+ if (checkBusy("app reorder")) {
+ return;
+ }
+ delegate.onAppReorder(uuids);
+ }
+
@Override
public void onFetchActivityData() {
if (checkBusy("fetch activity data")) {
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 fd00d02ac..fbb73cc5d 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
@@ -38,6 +38,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
import nodomain.freeyourgadget.gadgetbridge.model.GenericItem;
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
+import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction;
@@ -599,6 +600,11 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
return telephoneRinging;
}
+ @Override
+ public void onSetMusicState(MusicStateSpec stateSpec) {
+ // not supported
+ }
+
@Override
public void onSetMusicInfo(MusicSpec musicSpec) {
// not supported
@@ -761,6 +767,11 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
// not supported
}
+ @Override
+ public void onAppReorder(UUID[] uuids) {
+ // not supported
+ }
+
@Override
public void onScreenshotReq() {
// not supported
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMisfit.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMisfit.java
index 65f28a5e4..1e4953e1a 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMisfit.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMisfit.java
@@ -18,7 +18,6 @@ import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes;
-import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.pebble.MisfitSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.AbstractActivitySample;
import nodomain.freeyourgadget.gadgetbridge.entities.PebbleActivitySample;
@@ -47,8 +46,7 @@ public class AppMessageHandlerMisfit extends AppMessageHandler {
@Override
public boolean isEnabled() {
Prefs prefs = GBApplication.getPrefs();
- int activityTracker = prefs.getInt("pebble_activitytracker", SampleProvider.PROVIDER_PEBBLE_HEALTH);
- return (activityTracker == SampleProvider.PROVIDER_PEBBLE_MISFIT);
+ return prefs.getBoolean("pebble_sync_misfit", true);
}
@Override
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMorpheuz.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMorpheuz.java
index 7bdc6a901..36e751d8b 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMorpheuz.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/AppMessageHandlerMorpheuz.java
@@ -62,8 +62,7 @@ public class AppMessageHandlerMorpheuz extends AppMessageHandler {
@Override
public boolean isEnabled() {
Prefs prefs = GBApplication.getPrefs();
- int activityTracker = prefs.getInt("pebble_activitytracker", SampleProvider.PROVIDER_PEBBLE_HEALTH);
- return (activityTracker == SampleProvider.PROVIDER_PEBBLE_MORPHEUZ);
+ return prefs.getBoolean("pebble_sync_morpheuz", true);
}
@Override
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 acbbe9f7d..6df7a7514 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
@@ -3,7 +3,6 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble;
import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
-import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
abstract class DatalogSessionPebbleHealth extends DatalogSession {
@@ -14,7 +13,6 @@ abstract class DatalogSessionPebbleHealth extends DatalogSession {
protected boolean isPebbleHealthEnabled() {
Prefs prefs = GBApplication.getPrefs();
- int activityTracker = prefs.getInt("pebble_activitytracker", SampleProvider.PROVIDER_PEBBLE_HEALTH);
- return (activityTracker == SampleProvider.PROVIDER_PEBBLE_HEALTH);
+ return prefs.getBoolean("pebble_sync_health", true);
}
}
\ 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 2b0069a9d..1f36c0362 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
@@ -36,6 +36,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
+import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol;
@@ -70,6 +71,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
static final short ENDPOINT_RUNKEEPER = 7000;
static final short ENDPOINT_SCREENSHOT = 8000;
static final short ENDPOINT_NOTIFICATIONACTION = 11440; // 3.x only, TODO: find a better name
+ static final short ENDPOINT_APPREORDER = (short) 0xabcd; // 3.x only
static final short ENDPOINT_BLOBDB = (short) 45531; // 3.x only
static final short ENDPOINT_PUTBYTES = (short) 48879;
@@ -1103,6 +1105,20 @@ public class PebbleProtocol extends GBDeviceProtocol {
}
public byte[] encodeSetMusicState(byte state, int position, int playRate, byte shuffle, byte repeat) {
+ byte playState;
+
+ switch (state) {
+ case MusicStateSpec.STATE_PLAYING:
+ playState = MUSICCONTROL_STATE_PLAYING;
+ break;
+ case MusicStateSpec.STATE_PAUSED:
+ playState = MUSICCONTROL_STATE_PAUSED;
+ break;
+ default:
+ playState = MUSICCONTROL_STATE_UNKNOWN;
+ break;
+ }
+
int length = LENGTH_PREFIX + 12;
// Encode Prefix
ByteBuffer buf = ByteBuffer.allocate(length);
@@ -1112,8 +1128,8 @@ public class PebbleProtocol extends GBDeviceProtocol {
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.put(MUSICCONTROL_SETPLAYSTATE);
- buf.put(state);
- buf.putInt(position);
+ buf.put(playState);
+ buf.putInt(position * 1000);
buf.putInt(playRate);
buf.put(shuffle);
buf.put(repeat);
@@ -1127,7 +1143,6 @@ public class PebbleProtocol extends GBDeviceProtocol {
if (duration == 0) {
return encodeMessage(ENDPOINT_MUSICCONTROL, MUSICCONTROL_SETMUSICINFO, 0, parts);
} else {
- byte[] stateMessage = encodeSetMusicState(MUSICCONTROL_STATE_PLAYING, 0, 100, (byte) 1, (byte) 1);
// Calculate length first
int length = LENGTH_PREFIX + 9;
if (parts != null) {
@@ -1141,7 +1156,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
}
// Encode Prefix
- ByteBuffer buf = ByteBuffer.allocate(length + stateMessage.length);
+ ByteBuffer buf = ByteBuffer.allocate(length);
buf.order(ByteOrder.BIG_ENDIAN);
buf.putShort((short) (length - LENGTH_PREFIX));
buf.putShort(ENDPOINT_MUSICCONTROL);
@@ -1165,8 +1180,6 @@ public class PebbleProtocol extends GBDeviceProtocol {
buf.putShort((short) (trackCount & 0xffff));
buf.putShort((short) (trackNr & 0xffff));
- buf.put(stateMessage);
-
return buf.array();
}
}
@@ -1281,6 +1294,23 @@ public class PebbleProtocol extends GBDeviceProtocol {
return encodeSimpleMessage(ENDPOINT_SCREENSHOT, SCREENSHOT_TAKE);
}
+ @Override
+ public byte[] encodeAppReorder(UUID[] uuids) {
+ int length = 2 + uuids.length * LENGTH_UUID;
+ ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + length);
+ buf.order(ByteOrder.BIG_ENDIAN);
+ buf.putShort((short) length);
+ buf.putShort(ENDPOINT_APPREORDER);
+ buf.put((byte) 0x01);
+ buf.put((byte) uuids.length);
+ for (UUID uuid : uuids) {
+ buf.putLong(uuid.getMostSignificantBits());
+ buf.putLong(uuid.getLeastSignificantBits());
+ }
+
+ return buf.array();
+ }
+
/* pebble specific install methods */
public byte[] encodeUploadStart(byte type, int app_id, int size, String filename) {
short length;
@@ -1936,6 +1966,16 @@ public class PebbleProtocol extends GBDeviceProtocol {
return sendBytes;
}
+ private GBDeviceEvent decodeAppReorder(ByteBuffer buf) {
+ byte status = buf.get();
+ if (status == 1) {
+ LOG.info("app reordering successful");
+ } else {
+ LOG.info("app reordering returned status " + status);
+ }
+ return null;
+ }
+
@Override
public GBDeviceEvent[] decodeResponse(byte[] responseData) {
ByteBuffer buf = ByteBuffer.wrap(responseData);
@@ -2186,6 +2226,8 @@ public class PebbleProtocol extends GBDeviceProtocol {
case ENDPOINT_BLOBDB:
devEvts = new GBDeviceEvent[]{decodeBlobDb(buf)};
break;
+ case ENDPOINT_APPREORDER:
+ devEvts = new GBDeviceEvent[]{decodeAppReorder(buf)};
default:
break;
}
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 042874d3a..9bf905b2c 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
@@ -15,6 +15,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
+import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
import nodomain.freeyourgadget.gadgetbridge.service.serial.AbstractSerialDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceIoThread;
@@ -108,6 +109,13 @@ public class PebbleSupport extends AbstractSerialDeviceSupport {
}
}
+ @Override
+ public void onSetMusicState(MusicStateSpec musicStateSpec) {
+ if (reconnect()) {
+ super.onSetMusicState(musicStateSpec);
+ }
+ }
+
@Override
public void onSetMusicInfo(MusicSpec musicSpec) {
if (reconnect()) {
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java
index 78e15667d..0e4f5bbff 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java
@@ -11,6 +11,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.EventHandler;
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
+import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
import nodomain.freeyourgadget.gadgetbridge.service.AbstractDeviceSupport;
@@ -123,6 +124,12 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport
sendToDevice(bytes);
}
+ @Override
+ public void onSetMusicState(MusicStateSpec stateSpec) {
+ byte[] bytes = gbDeviceProtocol.encodeSetMusicState(stateSpec.state, stateSpec.position, stateSpec.playRate, stateSpec.shuffle, stateSpec.repeat);
+ sendToDevice(bytes);
+ }
+
@Override
public void onSetMusicInfo(MusicSpec musicSpec) {
byte[] bytes = gbDeviceProtocol.encodeSetMusicInfo(musicSpec.artist, musicSpec.album, musicSpec.track, musicSpec.duration, musicSpec.trackCount, musicSpec.trackNr);
@@ -147,6 +154,12 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport
sendToDevice(bytes);
}
+ @Override
+ public void onAppReorder(UUID[] uuids) {
+ byte[] bytes = gbDeviceProtocol.encodeAppReorder(uuids);
+ sendToDevice(bytes);
+ }
+
@Override
public void onFetchActivityData() {
byte[] bytes = gbDeviceProtocol.encodeSynchronizeActivityData();
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java
index c12c65675..ec641e361 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java
@@ -31,6 +31,10 @@ public abstract class GBDeviceProtocol {
return null;
}
+ public byte[] encodeSetMusicState(byte state, int position, int playRate, byte shuffle, byte repeat) {
+ return null;
+ }
+
public byte[] encodeFirmwareVersionReq() {
return null;
}
@@ -51,6 +55,10 @@ public abstract class GBDeviceProtocol {
return null;
}
+ public byte[] encodeAppReorder(UUID[] uuids) {
+ return null;
+ }
+
public byte[] encodeSynchronizeActivityData() {
return null;
}
diff --git a/app/src/main/res/menu/appmanager_context.xml b/app/src/main/res/menu/appmanager_context.xml
index 873e0c246..72cb29300 100644
--- a/app/src/main/res/menu/appmanager_context.xml
+++ b/app/src/main/res/menu/appmanager_context.xml
@@ -18,4 +18,8 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index 6ca7ee3b6..3f0dc77a6 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -238,5 +238,4 @@
Firmware non inviato
Battito cardiaco
Battito cardiaco
- Offset orologio del dispositivo in ore (per l\'identificazione del sonno dei lavoratori a turni)
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index ccdfc41a4..2ec72ca73 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -37,6 +37,7 @@
テーマ
ライト
ダーク
+ 言語
通知
繰り返し
電話通知
@@ -57,7 +58,11 @@
開発者用設定
Mi Bandのアドレス
Pebbleの設定
+ アクティビティ トラッカー
お好みのアクティビティ トラッカー
+ Pebble Health 同期
+ Misfit 同期
+ Morpheuz 同期
第三者のアンドロイドアップにアクセス権利を与える
PebbleKitを使用してAndroidアプリ用の実験的なサポートを有効にします
日の出と日の入り
@@ -214,6 +219,7 @@
このファームウェアは、デバイスと互換性がありません
今後のイベントのために予約するアラーム
睡眠の検出を改善するために心拍センサーを使用する
+ デバイスの時刻オフセット時間 (交代勤務の睡眠検知用)
再接続の待機中
再インストール
あなたについて
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index 7f79179f6..766b99bb8 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -34,6 +34,7 @@
Тема
Світла
Темна
+ Мова
Сповіщення
Повтори
Виклики
@@ -203,4 +204,6 @@
Вимкнути
Конфігурація
Додати віджет
+ Пристрій: %1$s
+ ПЗ: %1$s
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 988e59050..3bc390d94 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -74,7 +74,13 @@
Mi Band address
Pebble Settings
+
+ Activity Trackers
Preferred Activitytracker
+ Sync Pebble Health
+ Sync Misfit
+ Sync Morpheuz
+
Allow 3rd Party Android App Access
Enable experimental support for Android Apps using PebbleKit
@@ -251,9 +257,11 @@
Weight in kg
Activate
Deactivate
+ Configure
+ Move to top
+
authenticating
authentication required
- Configure
Zzz
Add widget
diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml
index a49185489..30d19573d 100644
--- a/app/src/main/res/xml/changelog_master.xml
+++ b/app/src/main/res/xml/changelog_master.xml
@@ -1,5 +1,13 @@
+
+ Pebble: set extended music info by dissecting notifications on Android 5.0+
+ Pebble: various other improvemnts to music playback
+ Pebble: allow ignoring activity trackers indiviually (to keep the data on the pebble)
+ Mi Band: support for shifting the device time by N hours (for people who sleep at daytime)
+ Mi Band: initial and untested support for Mi Band 2
+ Allow setting the application language
+
Pebble: option to send sunrise and sunset events to timeline
Pebble: fix problems with unknown app keys while configuring watchfaces
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index aa7843311..7c5723b6b 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -215,17 +215,31 @@
android:key="pebble_reconnect_attempts"
android:maxLength="4"
android:title="@string/pref_title_pebble_reconnect_attempts" />
+
+
+
+ android:summary="%s"
+ android:title="@string/pref_title_pebble_activitytracker" />
+ android:defaultValue="true"
+ android:key="pebble_sync_health"
+ android:title="@string/pref_title_pebble_sync_health" />
+ >
+
diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java
index 8070cb1eb..241193f7a 100644
--- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java
+++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java
@@ -12,6 +12,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
+import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
public class TestDeviceSupport extends AbstractDeviceSupport {
@@ -66,6 +67,11 @@ public class TestDeviceSupport extends AbstractDeviceSupport {
}
+ @Override
+ public void onSetMusicState(MusicStateSpec stateSpec) {
+
+ }
+
@Override
public void onSetMusicInfo(MusicSpec musicSpec) {
@@ -96,6 +102,11 @@ public class TestDeviceSupport extends AbstractDeviceSupport {
}
+ @Override
+ public void onAppReorder(UUID[] uuids) {
+
+ }
+
@Override
public void onFetchActivityData() {
diff --git a/build.gradle b/build.gradle
index 819874a7d..86fd2bad3 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,7 +5,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.1.0'
+ classpath 'com.android.tools.build:gradle:2.1.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files