Merge branch 'master' of https://github.com/Freeyourgadget/Gadgetbridge into hplus-handle-data
This commit is contained in:
commit
13ec497127
|
@ -0,0 +1,8 @@
|
|||
####Your issue is:
|
||||
*In case of a bug, do not forget to attach logs!*
|
||||
|
||||
####Your wearable device is:
|
||||
|
||||
*Please specify model and firmware version if possible*
|
||||
|
||||
####Your android version is:
|
28
CHANGELOG.md
28
CHANGELOG.md
|
@ -1,5 +1,33 @@
|
|||
###Changelog
|
||||
|
||||
####Version 0.17.0 (next)
|
||||
* Add weather support through "Weather Notification" app
|
||||
* Pebble: Support for build-in weather system app (FW 4.x)
|
||||
* Pebble: Add weather support for various watchfaces
|
||||
* Pebble: Add option to disable call display
|
||||
* Pebble: Delete notifications that got dismissed on the phone
|
||||
* Pebble 2/LE: Improve reliablitly and transfer speed
|
||||
* Various fixes for K9 mail when using the generic notification receiver
|
||||
|
||||
####Version 0.16.0
|
||||
* New devices: HPlus (e.g. Zeblaze ZeBand), contributed by João Paulo Barraca
|
||||
* ZeBand: Initial support: notifications, heart rate, sleep monitoring, user configuration, date+time
|
||||
* Pebble 2: Fix Pebble Classic FW 3.x app variant being prioritized over native Pebble 2 app variant
|
||||
* Charts (Live Activity): Fix axis labels color in dark theme
|
||||
* Mi Band: Fix ginormous step count when using Live Activity
|
||||
* Mi Band: Improved performance during activity sync
|
||||
* Mi Band 2: Fix activity data missing after doing manual hr measurements or live activity
|
||||
* Support sharing firmwares/watchapps/watchfaces to Gadgetbridge
|
||||
* Support for the "Subsonic" music player (#474)
|
||||
|
||||
####Version 0.15.2
|
||||
* Mi Band: Fix crash with unknown notification sources
|
||||
|
||||
####Version 0.15.1
|
||||
* Improved handling of notifications for some apps
|
||||
* Pebble 2/LE: Add setting to limit GATT MTU for debugging broken BLE stacks
|
||||
* Mi Band 2: Display battery status
|
||||
|
||||
####Version 0.15.0
|
||||
* New device: Liveview
|
||||
* Liveview: initial support (set the time and receive notifications)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
names ()
|
||||
{
|
||||
echo -e "\n exit;\n**Contributors (sorted by number of commits):**\n";
|
||||
git log --all --format='%aN:%aE' | sed 's/@users.github.com/@users.noreply.github.com/g' | awk 'BEGIN{FS=":"}{ct[$2]+=1;if (length($1) > length(e[$2])) {e[$2]=$1}}END{for (i in e) { n[e[i]]=i;c[e[i]]+=ct[i] }; for (a in n) print c[a]"\t* "a" <"n[a]">";}' | sort -n -r | cut -f 2-
|
||||
git log --format='%aN:%aE' origin/master | sed 's/@users.github.com/@users.noreply.github.com/g' | awk 'BEGIN{FS=":"}{ct[$2]+=1;if (length($1) > length(e[$2])) {e[$2]=$1}}END{for (i in e) { n[e[i]]=i;c[e[i]]+=ct[i] }; for (a in n) print c[a]"\t* "a" <"n[a]">";}' | sort -n -r | cut -f 2-
|
||||
}
|
||||
quine ()
|
||||
{
|
||||
|
@ -26,15 +26,17 @@
|
|||
* Carsten Pfeiffer <cpfeiffer@users.noreply.github.com>
|
||||
* Daniele Gobbetti <daniele+github@gobbetti.name>
|
||||
* Julien Pivotto <roidelapluie@inuits.eu>
|
||||
* João Paulo Barraca <jpbarraca@gmail.com>
|
||||
* Steffen Liebergeld <perl@gmx.org>
|
||||
* Lem Dulfo <lemuel.dulfo@gmail.com>
|
||||
* Sergey Trofimov <sarg@sarg.org.ru>
|
||||
* JohnnySun <bmy001@gmail.com>
|
||||
* Uwe Hermann <uwe@hermann-uwe.de>
|
||||
* Gergely Peidl <gergely@peidl.net>
|
||||
* 0nse <0nse@users.noreply.github.com>
|
||||
* Gergely Peidl <gergely@peidl.net>
|
||||
* Christian Fischer <sw-dev@computerlyrik.de>
|
||||
* Normano64 <per.bergqwist@gmail.com>
|
||||
* 6arms1leg <m.brnsfld@googlemail.com>
|
||||
* Ⲇⲁⲛⲓ Φi <daniphii@outlook.com>
|
||||
* xzovy <caleb@caleb-cooper.net>
|
||||
* xphnx <xphnx@users.noreply.github.com>
|
||||
|
@ -56,7 +58,6 @@
|
|||
* atkyritsis <at.kyritsis@gmail.com>
|
||||
* andre <andre.buesgen@yahoo.de>
|
||||
* Alexey Afanasev <avafanasiev@gmail.com>
|
||||
* 6arms1leg <m.brnsfld@googlemail.com>
|
||||
|
||||
And all the Transifex translators, which I cannot automatically list, at the moment.
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ need to create an account and transmit any of your data to the vendor's servers.
|
|||
* Mi Band 2
|
||||
* Vibratissimo (experimental)
|
||||
* Liveview
|
||||
* HPlus Devices (e.g. ZeBand)
|
||||
|
||||
## Features (Pebble)
|
||||
|
||||
|
|
|
@ -26,8 +26,8 @@ android {
|
|||
targetSdkVersion 23
|
||||
|
||||
// note: always bump BOTH versionCode and versionName!
|
||||
versionName "0.15.0"
|
||||
versionCode 77
|
||||
versionName "0.17.0"
|
||||
versionCode 81
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
|
|
|
@ -191,6 +191,15 @@
|
|||
<data android:mimeType="application/zip" />
|
||||
<data android:mimeType="application/x-zip-compressed" />
|
||||
</intent-filter>
|
||||
<!-- to receive files from the "share" intent -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
<data android:mimeType="*/*" />
|
||||
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<service
|
||||
|
@ -203,6 +212,21 @@
|
|||
</service>
|
||||
<service android:name=".service.DeviceCommunicationService" />
|
||||
|
||||
<receiver
|
||||
android:name=".externalevents.WeatherNotificationReceiver"
|
||||
android:enabled="true">
|
||||
<intent-filter>
|
||||
<action android:name="ru.gelin.android.weather.notification.ACTION_WEATHER_UPDATE_2" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<activity android:name=".externalevents.WeatherNotificationConfig"
|
||||
android:label="mockup">
|
||||
<intent-filter>
|
||||
<action android:name="ru.gelin.android.weather.notification.ACTION_WEATHER_SKIN_PREFERENCES"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<receiver
|
||||
android:name=".externalevents.BluetoothStateChangeReceiver"
|
||||
android:exported="false">
|
||||
|
|
|
@ -171,6 +171,10 @@ public class GBApplication extends Application {
|
|||
return prefs.getBoolean("log_to_file", false);
|
||||
}
|
||||
|
||||
public static boolean minimizeNotification() {
|
||||
return prefs.getBoolean("minimize_priority", false);
|
||||
}
|
||||
|
||||
static void setupDatabase(Context context) {
|
||||
DBOpenHelper helper = new DBOpenHelper(context, DATABASE_NAME, null);
|
||||
SQLiteDatabase db = helper.getWritableDatabase();
|
||||
|
|
|
@ -152,6 +152,9 @@ public class FwAppInstallerActivity extends GBActivity implements InstallActivit
|
|||
});
|
||||
|
||||
uri = getIntent().getData();
|
||||
if (uri == null) { //for "share" intent
|
||||
uri = getIntent().getParcelableExtra(Intent.EXTRA_STREAM);
|
||||
}
|
||||
installHandler = findInstallHandlerFor(uri);
|
||||
if (installHandler == null) {
|
||||
setInfoText(getString(R.string.installer_activity_unable_to_find_handler));
|
||||
|
|
|
@ -199,6 +199,9 @@ public abstract class AbstractAppManagerFragment extends Fragment {
|
|||
if (baseName.equals("3af858c3-16cb-4561-91e7-f1ad2df8725f")) {
|
||||
cachedAppList.add(new GBDeviceApp(UUID.fromString(baseName), "Kickstart (System)", "Pebble Inc.", "", GBDeviceApp.Type.WATCHFACE_SYSTEM));
|
||||
}
|
||||
if (baseName.equals(PebbleProtocol.UUID_WEATHER.toString())) {
|
||||
cachedAppList.add(new GBDeviceApp(PebbleProtocol.UUID_WEATHER, "Weather (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (uuids == null) {
|
||||
|
@ -292,6 +295,10 @@ public abstract class AbstractAppManagerFragment extends Fragment {
|
|||
menu.removeItem(R.id.appmanager_hrm_activate);
|
||||
menu.removeItem(R.id.appmanager_hrm_deactivate);
|
||||
}
|
||||
if (!PebbleProtocol.UUID_WEATHER.equals(selectedApp.getUUID())) {
|
||||
menu.removeItem(R.id.appmanager_weather_activate);
|
||||
menu.removeItem(R.id.appmanager_weather_deactivate);
|
||||
}
|
||||
if (selectedApp.getType() == GBDeviceApp.Type.APP_SYSTEM || selectedApp.getType() == GBDeviceApp.Type.WATCHFACE_SYSTEM) {
|
||||
menu.removeItem(R.id.appmanager_app_delete);
|
||||
}
|
||||
|
@ -367,8 +374,12 @@ public abstract class AbstractAppManagerFragment extends Fragment {
|
|||
case R.id.appmanager_hrm_activate:
|
||||
GBApplication.deviceService().onInstallApp(Uri.parse("fake://hrm"));
|
||||
return true;
|
||||
case R.id.appmanager_weather_activate:
|
||||
GBApplication.deviceService().onInstallApp(Uri.parse("fake://weather"));
|
||||
return true;
|
||||
case R.id.appmanager_health_deactivate:
|
||||
case R.id.appmanager_hrm_deactivate:
|
||||
case R.id.appmanager_weather_deactivate:
|
||||
GBApplication.deviceService().onAppDelete(selectedApp.getUUID());
|
||||
return true;
|
||||
case R.id.appmanager_app_configure:
|
||||
|
|
|
@ -16,7 +16,7 @@ public class AppManagerFragmentInstalledApps extends AbstractAppManagerFragment
|
|||
//systemApps.add(new GBDeviceApp(UUID.fromString("4dab81a6-d2fc-458a-992c-7a1f3b96a970"), "Sports (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM));
|
||||
//systemApps.add(new GBDeviceApp(UUID.fromString("cf1e816a-9db0-4511-bbb8-f60c48ca8fac"), "Golf (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM));
|
||||
systemApps.add(new GBDeviceApp(UUID.fromString("1f03293d-47af-4f28-b960-f2b02a6dd757"), "Music (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM));
|
||||
systemApps.add(new GBDeviceApp(UUID.fromString("b2cae818-10f8-46df-ad2b-98ad2254a3c1"), "Notifications (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM));
|
||||
systemApps.add(new GBDeviceApp(PebbleProtocol.UUID_NOTIFICATIONS, "Notifications (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM));
|
||||
systemApps.add(new GBDeviceApp(UUID.fromString("67a32d95-ef69-46d4-a0b9-854cc62f97f9"), "Alarms (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM));
|
||||
systemApps.add(new GBDeviceApp(UUID.fromString("18e443ce-38fd-47c8-84d5-6d0c775fbe55"), "Watchfaces (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM));
|
||||
|
||||
|
@ -28,6 +28,9 @@ public class AppManagerFragmentInstalledApps extends AbstractAppManagerFragment
|
|||
if (PebbleUtils.hasHRM(mGBDevice.getModel())) {
|
||||
systemApps.add(new GBDeviceApp(PebbleProtocol.UUID_WORKOUT, "Workout (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM));
|
||||
}
|
||||
if (PebbleUtils.getFwMajor(mGBDevice.getFirmwareVersion()) >= 4) {
|
||||
systemApps.add(new GBDeviceApp(PebbleProtocol.UUID_WEATHER, "Weather (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM));
|
||||
}
|
||||
}
|
||||
|
||||
return systemApps;
|
||||
|
|
|
@ -72,8 +72,6 @@ public class LiveActivityFragment extends AbstractChartFragment {
|
|||
private TimestampTranslation tsTranslation;
|
||||
|
||||
private class Steps {
|
||||
private int initialSteps;
|
||||
|
||||
private int steps;
|
||||
private int lastTimestamp;
|
||||
private int currentStepsPerMinute;
|
||||
|
@ -90,39 +88,29 @@ public class LiveActivityFragment extends AbstractChartFragment {
|
|||
}
|
||||
|
||||
public int getTotalSteps() {
|
||||
return steps - initialSteps;
|
||||
return steps;
|
||||
}
|
||||
|
||||
public int getMaxStepsPerMinute() {
|
||||
return maxStepsPerMinute;
|
||||
}
|
||||
|
||||
public void updateCurrentSteps(int newSteps, int timestamp) {
|
||||
public void updateCurrentSteps(int stepsDelta, int timestamp) {
|
||||
try {
|
||||
if (steps == 0) {
|
||||
steps = newSteps;
|
||||
steps += stepsDelta;
|
||||
lastTimestamp = timestamp;
|
||||
|
||||
if (newSteps > 0) {
|
||||
initialSteps = newSteps;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (newSteps >= steps) {
|
||||
int stepsDelta = newSteps - steps;
|
||||
int timeDelta = timestamp - lastTimestamp;
|
||||
currentStepsPerMinute = calculateStepsPerMinute(stepsDelta, timeDelta);
|
||||
if (currentStepsPerMinute > maxStepsPerMinute) {
|
||||
maxStepsPerMinute = currentStepsPerMinute;
|
||||
maxStepsResetCounter = 0;
|
||||
}
|
||||
steps = newSteps;
|
||||
lastTimestamp = timestamp;
|
||||
} else {
|
||||
// TODO: handle new day?
|
||||
|
||||
int timeDelta = timestamp - lastTimestamp;
|
||||
currentStepsPerMinute = calculateStepsPerMinute(stepsDelta, timeDelta);
|
||||
if (currentStepsPerMinute > maxStepsPerMinute) {
|
||||
maxStepsPerMinute = currentStepsPerMinute;
|
||||
maxStepsResetCounter = 0;
|
||||
}
|
||||
steps += stepsDelta;
|
||||
lastTimestamp = timestamp;
|
||||
} catch (Exception ex) {
|
||||
GB.toast(LiveActivityFragment.this.getContext(), ex.getMessage(), Toast.LENGTH_SHORT, GB.ERROR, ex);
|
||||
}
|
||||
|
@ -136,7 +124,7 @@ public class LiveActivityFragment extends AbstractChartFragment {
|
|||
throw new IllegalArgumentException("delta in seconds is <= 0 -- time change?");
|
||||
}
|
||||
|
||||
int oneMinute = 60 * 1000;
|
||||
int oneMinute = 60;
|
||||
float factor = oneMinute / seconds;
|
||||
int result = (int) (stepsDelta * factor);
|
||||
if (result > MAX_STEPS_PER_MINUTE) {
|
||||
|
@ -152,24 +140,27 @@ public class LiveActivityFragment extends AbstractChartFragment {
|
|||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
switch (action) {
|
||||
case DeviceService.ACTION_REALTIME_STEPS: {
|
||||
int steps = intent.getIntExtra(DeviceService.EXTRA_REALTIME_STEPS, 0);
|
||||
int timestamp = translateTimestampFrom(intent);
|
||||
addEntries(steps, timestamp);
|
||||
break;
|
||||
}
|
||||
case DeviceService.ACTION_HEARTRATE_MEASUREMENT: {
|
||||
int heartRate = intent.getIntExtra(DeviceService.EXTRA_HEART_RATE_VALUE, 0);
|
||||
int timestamp = translateTimestampFrom(intent);
|
||||
if (isValidHeartRateValue(heartRate)) {
|
||||
setCurrentHeartRate(heartRate, timestamp);
|
||||
}
|
||||
case DeviceService.ACTION_REALTIME_SAMPLES: {
|
||||
ActivitySample sample = (ActivitySample) intent.getSerializableExtra(DeviceService.EXTRA_REALTIME_SAMPLE);
|
||||
addSample(sample);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private void addSample(ActivitySample sample) {
|
||||
int heartRate = sample.getHeartRate();
|
||||
int timestamp = tsTranslation.shorten(sample.getTimestamp());
|
||||
if (isValidHeartRateValue(heartRate)) {
|
||||
setCurrentHeartRate(heartRate, timestamp);
|
||||
}
|
||||
int steps = sample.getSteps();
|
||||
if (steps != ActivitySample.NOT_MEASURED) {
|
||||
addEntries(steps, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
private int translateTimestampFrom(Intent intent) {
|
||||
return translateTimestamp(intent.getLongExtra(DeviceService.EXTRA_TIMESTAMP, System.currentTimeMillis()));
|
||||
}
|
||||
|
@ -251,8 +242,7 @@ public class LiveActivityFragment extends AbstractChartFragment {
|
|||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
IntentFilter filterLocal = new IntentFilter();
|
||||
filterLocal.addAction(DeviceService.ACTION_REALTIME_STEPS);
|
||||
filterLocal.addAction(DeviceService.ACTION_HEARTRATE_MEASUREMENT);
|
||||
filterLocal.addAction(DeviceService.ACTION_REALTIME_SAMPLES);
|
||||
heartRateValues = new ArrayList<>();
|
||||
tsTranslation = new TimestampTranslation();
|
||||
|
||||
|
@ -377,6 +367,9 @@ public class LiveActivityFragment extends AbstractChartFragment {
|
|||
// chart.getXAxis().setPosition(XAxis.XAxisPosition.TOP);
|
||||
chart.getXAxis().setDrawLabels(false);
|
||||
chart.getXAxis().setEnabled(false);
|
||||
chart.getXAxis().setTextColor(CHART_TEXT_COLOR);
|
||||
chart.getAxisLeft().setTextColor(CHART_TEXT_COLOR);
|
||||
|
||||
chart.setBackgroundColor(BACKGROUND_COLOR);
|
||||
chart.getDescription().setTextColor(DESCRIPTION_COLOR);
|
||||
chart.getDescription().setText(title);
|
||||
|
|
|
@ -12,6 +12,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
|||
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
|
||||
/**
|
||||
* Specifies all events that Gadgetbridge intends to send to the gadget device.
|
||||
|
@ -21,6 +22,8 @@ import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
|||
public interface EventHandler {
|
||||
void onNotification(NotificationSpec notificationSpec);
|
||||
|
||||
void onDeleteNotification(int id);
|
||||
|
||||
void onSetTime();
|
||||
|
||||
void onSetAlarms(ArrayList<? extends Alarm> alarms);
|
||||
|
@ -75,4 +78,6 @@ public interface EventHandler {
|
|||
void onSendConfiguration(String config);
|
||||
|
||||
void onTestNewFunction();
|
||||
|
||||
void onSendWeather(WeatherSpec weatherSpec);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
|||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.UriHelper;
|
||||
|
||||
/**
|
||||
* Also see Mi1SFirmwareInfo.
|
||||
|
@ -26,12 +27,13 @@ public abstract class AbstractMiBandFWHelper {
|
|||
private final byte[] fw;
|
||||
|
||||
public AbstractMiBandFWHelper(Uri uri, Context context) throws IOException {
|
||||
UriHelper uriHelper = UriHelper.get(uri, context);
|
||||
String pebblePattern = ".*\\.(pbw|pbz|pbl)";
|
||||
if (uri.getPath().matches(pebblePattern)) {
|
||||
if (uriHelper.getFileName().matches(pebblePattern)) {
|
||||
throw new IOException("Firmware has a filename that looks like a Pebble app/firmware.");
|
||||
}
|
||||
|
||||
try (InputStream in = new BufferedInputStream(context.getContentResolver().openInputStream(uri))) {
|
||||
try (InputStream in = new BufferedInputStream(uriHelper.openInputStream())) {
|
||||
this.fw = FileUtils.readAll(in, 1024 * 1024); // 1 MB
|
||||
determineFirmwareInfo(fw);
|
||||
} catch (IOException ex) {
|
||||
|
|
|
@ -60,6 +60,10 @@ public class PBWInstallHandler implements InstallHandler {
|
|||
installActivity.setInfoText("file not found");
|
||||
installActivity.setInstallEnabled(false);
|
||||
return;
|
||||
} catch (IOException e) {
|
||||
installActivity.setInfoText("error reading file");
|
||||
installActivity.setInstallEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mPBWReader.isValid()) {
|
||||
|
@ -168,18 +172,22 @@ public class PBWInstallHandler implements InstallHandler {
|
|||
}
|
||||
|
||||
InputStream jsConfigFile = mPBWReader.getInputStreamFile("pebble-js-app.js");
|
||||
|
||||
if (jsConfigFile != null) {
|
||||
outputFile = new File(destDir, app.getUUID().toString() + "_config.js");
|
||||
try {
|
||||
outputFile = new File(destDir, app.getUUID().toString() + "_config.js");
|
||||
FileUtils.copyStreamToFile(jsConfigFile, outputFile);
|
||||
} catch (IOException e) {
|
||||
LOG.error("Failed to open output file: " + e.getMessage(), e);
|
||||
} finally {
|
||||
try {
|
||||
jsConfigFile.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
// always pretend it is valid, as we can't know yet about hw/fw version
|
||||
return true;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package nodomain.freeyourgadget.gadgetbridge.devices.pebble;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
|
@ -9,9 +8,7 @@ import org.json.JSONObject;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -26,6 +23,7 @@ import java.util.zip.ZipInputStream;
|
|||
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.PebbleProtocol;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.UriHelper;
|
||||
|
||||
public class PBWReader {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(PBWReader.class);
|
||||
|
@ -45,8 +43,7 @@ public class PBWReader {
|
|||
fwFileTypesMap.put("resources", PebbleProtocol.PUTBYTES_TYPE_SYSRESOURCES);
|
||||
}
|
||||
|
||||
private final Uri uri;
|
||||
private final ContentResolver cr;
|
||||
private final UriHelper uriHelper;
|
||||
private GBDeviceApp app;
|
||||
private ArrayList<PebbleInstallable> pebbleInstallables = null;
|
||||
private boolean isFirmware = false;
|
||||
|
@ -60,100 +57,45 @@ public class PBWReader {
|
|||
|
||||
private JSONObject mAppKeys = null;
|
||||
|
||||
public PBWReader(Uri uri, Context context, String platform) throws FileNotFoundException {
|
||||
this.uri = uri;
|
||||
cr = context.getContentResolver();
|
||||
public PBWReader(Uri uri, Context context, String platform) throws IOException {
|
||||
uriHelper = UriHelper.get(uri, context);
|
||||
|
||||
InputStream fin = new BufferedInputStream(cr.openInputStream(uri));
|
||||
|
||||
if (uri.toString().endsWith(".pbl")) {
|
||||
if (uriHelper.getFileName().endsWith(".pbl")) {
|
||||
STM32CRC stm32crc = new STM32CRC();
|
||||
try {
|
||||
try (InputStream fin = uriHelper.openInputStream()) {
|
||||
byte[] buf = new byte[2000];
|
||||
while (fin.available() > 0) {
|
||||
int count = fin.read(buf);
|
||||
stm32crc.addData(buf, count);
|
||||
}
|
||||
fin.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
int crc = stm32crc.getResult();
|
||||
// language file
|
||||
app = new GBDeviceApp(UUID.randomUUID(), "Language File", "unknown", "unknown", GBDeviceApp.Type.UNKNOWN);
|
||||
File f = new File(uri.getPath());
|
||||
|
||||
pebbleInstallables = new ArrayList<>();
|
||||
pebbleInstallables.add(new PebbleInstallable("lang", (int) f.length(), crc, PebbleProtocol.PUTBYTES_TYPE_FILE));
|
||||
pebbleInstallables.add(new PebbleInstallable("lang", (int) uriHelper.getFileSize(), crc, PebbleProtocol.PUTBYTES_TYPE_FILE));
|
||||
|
||||
isValid = true;
|
||||
isLanguage = true;
|
||||
return;
|
||||
}
|
||||
|
||||
String platformDir = "";
|
||||
|
||||
if (!uri.toString().endsWith(".pbz")) {
|
||||
/*
|
||||
* for aplite and basalt it is possible to install 2.x apps which have no subfolder
|
||||
* we still prefer the subfolders if present.
|
||||
* chalk needs to be its subfolder
|
||||
*/
|
||||
String[] platformDirs;
|
||||
switch (platform) {
|
||||
case "basalt":
|
||||
platformDirs = new String[]{"basalt/"};
|
||||
break;
|
||||
case "chalk":
|
||||
platformDirs = new String[]{"chalk/"};
|
||||
break;
|
||||
case "diorite":
|
||||
platformDirs = new String[]{"diorite/", "aplite/"};
|
||||
break;
|
||||
case "emery":
|
||||
platformDirs = new String[]{"emery/", "basalt/"};
|
||||
break;
|
||||
default:
|
||||
platformDirs = new String[]{"aplite/"};
|
||||
}
|
||||
|
||||
for (String dir : platformDirs) {
|
||||
InputStream afin = new BufferedInputStream(cr.openInputStream(uri));
|
||||
|
||||
ZipInputStream zis = new ZipInputStream(afin);
|
||||
ZipEntry ze;
|
||||
try {
|
||||
while ((ze = zis.getNextEntry()) != null) {
|
||||
if (ze.getName().startsWith(dir)) {
|
||||
platformDir = dir;
|
||||
break;
|
||||
}
|
||||
}
|
||||
zis.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (platform.equals("chalk") && platformDir.equals("")) {
|
||||
return;
|
||||
}
|
||||
String platformDir = determinePlatformDir(uriHelper, platform);
|
||||
if (platform.equals("chalk") && platformDir.equals("")) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG.info("using platformdir: '" + platformDir + "'");
|
||||
String appName = null;
|
||||
String appCreator = null;
|
||||
String appVersion = null;
|
||||
UUID appUUID = null;
|
||||
|
||||
ZipInputStream zis = new ZipInputStream(fin);
|
||||
ZipEntry ze;
|
||||
pebbleInstallables = new ArrayList<>();
|
||||
byte[] buffer = new byte[1024];
|
||||
int count;
|
||||
|
||||
try {
|
||||
try (ZipInputStream zis = new ZipInputStream(uriHelper.openInputStream())) {
|
||||
while ((ze = zis.getNextEntry()) != null) {
|
||||
String fileName = ze.getName();
|
||||
if (fileName.equals(platformDir + "manifest.json")) {
|
||||
|
@ -249,7 +191,6 @@ public class PBWReader {
|
|||
// more follows but, not interesting for us
|
||||
}
|
||||
}
|
||||
zis.close();
|
||||
if (appUUID != null && appName != null && appCreator != null && appVersion != null) {
|
||||
GBDeviceApp.Type appType = GBDeviceApp.Type.APP_GENERIC;
|
||||
|
||||
|
@ -260,11 +201,58 @@ public class PBWReader {
|
|||
}
|
||||
app = new GBDeviceApp(appUUID, appName, appCreator, appVersion, appType);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the platform dir to use for the given uri and platform.
|
||||
* @param uriHelper
|
||||
* @param platform
|
||||
* @return the platform dir to use
|
||||
* @throws IOException
|
||||
*/
|
||||
private String determinePlatformDir(UriHelper uriHelper, String platform) throws IOException {
|
||||
String platformDir = "";
|
||||
|
||||
if (uriHelper.getFileName().endsWith(".pbz")) {
|
||||
return platformDir;
|
||||
}
|
||||
/*
|
||||
* for aplite and basalt it is possible to install 2.x apps which have no subfolder
|
||||
* we still prefer the subfolders if present.
|
||||
* chalk needs to be its subfolder
|
||||
*/
|
||||
String[] platformDirs;
|
||||
switch (platform) {
|
||||
case "basalt":
|
||||
platformDirs = new String[]{"basalt/"};
|
||||
break;
|
||||
case "chalk":
|
||||
platformDirs = new String[]{"chalk/"};
|
||||
break;
|
||||
case "diorite":
|
||||
platformDirs = new String[]{"diorite/", "aplite/"};
|
||||
break;
|
||||
case "emery":
|
||||
platformDirs = new String[]{"emery/", "basalt/"};
|
||||
break;
|
||||
default:
|
||||
platformDirs = new String[]{"aplite/"};
|
||||
}
|
||||
|
||||
for (String dir : platformDirs) {
|
||||
try (ZipInputStream zis = new ZipInputStream(uriHelper.openInputStream())) {
|
||||
ZipEntry ze;
|
||||
while ((ze = zis.getNextEntry()) != null) {
|
||||
if (ze.getName().startsWith(dir)) {
|
||||
return dir;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return platformDir;
|
||||
}
|
||||
|
||||
public boolean isFirmware() {
|
||||
return isFirmware;
|
||||
}
|
||||
|
@ -282,28 +270,29 @@ public class PBWReader {
|
|||
}
|
||||
|
||||
public InputStream getInputStreamFile(String filename) {
|
||||
InputStream fin;
|
||||
try {
|
||||
fin = new BufferedInputStream(cr.openInputStream(uri));
|
||||
if (isLanguage) {
|
||||
return fin;
|
||||
if (isLanguage) {
|
||||
try {
|
||||
return uriHelper.openInputStream();
|
||||
} catch (FileNotFoundException e) {
|
||||
LOG.warn("file not found: " + e);
|
||||
return null;
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
ZipInputStream zis = new ZipInputStream(fin);
|
||||
ZipInputStream zis = null;
|
||||
ZipEntry ze;
|
||||
try {
|
||||
zis = new ZipInputStream(uriHelper.openInputStream());
|
||||
while ((ze = zis.getNextEntry()) != null) {
|
||||
if (ze.getName().equals(filename)) {
|
||||
return zis;
|
||||
return zis; // return WITHOUT closing the stream!
|
||||
}
|
||||
}
|
||||
zis.close();
|
||||
} catch (Throwable e) {
|
||||
try {
|
||||
zis.close();
|
||||
if (zis != null) {
|
||||
zis.close();
|
||||
}
|
||||
} catch (IOException e1) {
|
||||
// ignore
|
||||
}
|
||||
|
|
|
@ -29,7 +29,13 @@ public class MusicPlaybackReceiver extends BroadcastReceiver {
|
|||
MusicSpec musicSpec = new MusicSpec();
|
||||
musicSpec.artist = intent.getStringExtra("artist");
|
||||
musicSpec.album = intent.getStringExtra("album");
|
||||
musicSpec.track = intent.getStringExtra("track");
|
||||
if (intent.hasExtra("track")) {
|
||||
musicSpec.track = intent.getStringExtra("track");
|
||||
}
|
||||
else if (intent.hasExtra("title")) {
|
||||
musicSpec.track = intent.getStringExtra("title");
|
||||
}
|
||||
|
||||
musicSpec.duration = intent.getIntExtra("duration", 0) / 1000;
|
||||
|
||||
if (!lastMusicSpec.equals(musicSpec)) {
|
||||
|
|
|
@ -34,6 +34,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.AppNotificationType;
|
|||
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;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||
|
@ -251,6 +252,18 @@ public class NotificationListener extends NotificationListenerService {
|
|||
|
||||
notificationSpec.type = AppNotificationType.getInstance().get(source);
|
||||
|
||||
if (source.equals("com.fsck.k9")) {
|
||||
// we dont want group summaries at all for k9
|
||||
if ((notification.flags & Notification.FLAG_GROUP_SUMMARY) == Notification.FLAG_GROUP_SUMMARY) {
|
||||
return;
|
||||
}
|
||||
preferBigText = true;
|
||||
}
|
||||
|
||||
if (notificationSpec.type == null) {
|
||||
notificationSpec.type = NotificationType.UNKNOWN;
|
||||
}
|
||||
|
||||
LOG.info("Processing notification from source " + source + " with flags: " + notification.flags);
|
||||
|
||||
dissectNotificationTo(notification, notificationSpec, preferBigText);
|
||||
|
@ -383,7 +396,23 @@ public class NotificationListener extends NotificationListenerService {
|
|||
|
||||
@Override
|
||||
public void onNotificationRemoved(StatusBarNotification sbn) {
|
||||
//FIXME: deduplicate code
|
||||
String source = sbn.getPackageName();
|
||||
Notification notification = sbn.getNotification();
|
||||
if ((notification.flags & Notification.FLAG_ONGOING_EVENT) == Notification.FLAG_ONGOING_EVENT) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (source.equals("android") ||
|
||||
source.equals("com.android.systemui") ||
|
||||
source.equals("com.android.dialer") ||
|
||||
source.equals("com.cyanogenmod.eleven")) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG.info("notification removed, will ask device to delete it");
|
||||
|
||||
GBApplication.deviceService().onDeleteNotification((int) sbn.getPostTime()); //FIMXE: a truly unique id would be better
|
||||
}
|
||||
|
||||
private void dumpExtras(Bundle bundle) {
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package nodomain.freeyourgadget.gadgetbridge.externalevents;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
public class WeatherNotificationConfig extends Activity {
|
||||
|
||||
//TODO: we just need the user to enable us in the weather notification settings. There must be a better way
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package nodomain.freeyourgadget.gadgetbridge.externalevents;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
import ru.gelin.android.weather.notification.ParcelableWeather2;
|
||||
|
||||
|
||||
public class WeatherNotificationReceiver extends BroadcastReceiver {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(WeatherNotificationReceiver.class);
|
||||
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (!intent.getAction().contains("WEATHER_UPDATE_2")) {
|
||||
LOG.info("Wrong action");
|
||||
return;
|
||||
}
|
||||
ParcelableWeather2 weather = null;
|
||||
try {
|
||||
weather = intent.getParcelableExtra("ru.gelin.android.weather.notification.EXTRA_WEATHER");
|
||||
} catch (RuntimeException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (weather != null) {
|
||||
Weather.getInstance().setWeather2(weather);
|
||||
LOG.info("weather in " + weather.location + " is " + weather.currentCondition + " (" + (weather.currentTemp - 273) + "°C)");
|
||||
|
||||
WeatherSpec weatherSpec = new WeatherSpec();
|
||||
weatherSpec.timestamp = (int) (weather.queryTime / 1000);
|
||||
weatherSpec.location = weather.location;
|
||||
weatherSpec.currentTemp = weather.currentTemp;
|
||||
weatherSpec.currentCondition = weather.currentCondition;
|
||||
weatherSpec.currentConditionCode = weather.currentConditionCode;
|
||||
weatherSpec.todayMaxTemp = weather.todayHighTemp;
|
||||
weatherSpec.todayMinTemp = weather.todayLowTemp;
|
||||
weatherSpec.tomorrowConditionCode = weather.forecastConditionCode;
|
||||
weatherSpec.tomorrowMaxTemp = weather.forecastHighTemp;
|
||||
weatherSpec.tomorrowMinTemp = weather.forecastLowTemp;
|
||||
Weather.getInstance().setWeatherSpec(weatherSpec);
|
||||
GBApplication.deviceService().onSendWeather(weatherSpec);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,13 +17,12 @@ 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.WeatherSpec;
|
||||
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;
|
||||
private final Class<? extends Service> mServiceClass;
|
||||
|
||||
public GBDeviceService(Context context) {
|
||||
mContext = context;
|
||||
|
@ -106,6 +105,14 @@ public class GBDeviceService implements DeviceService {
|
|||
invokeService(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleteNotification(int id) {
|
||||
Intent intent = createIntent().setAction(ACTION_DELETE_NOTIFICATION)
|
||||
.putExtra(EXTRA_NOTIFICATION_ID, id);
|
||||
invokeService(intent);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetTime() {
|
||||
Intent intent = createIntent().setAction(ACTION_SETTIME);
|
||||
|
@ -293,4 +300,20 @@ public class GBDeviceService implements DeviceService {
|
|||
Intent intent = createIntent().setAction(ACTION_TEST_NEW_FUNCTION);
|
||||
invokeService(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
||||
Intent intent = createIntent().setAction(ACTION_SEND_WEATHER)
|
||||
.putExtra(EXTRA_WEATHER_TIMESTAMP, weatherSpec.timestamp)
|
||||
.putExtra(EXTRA_WEATHER_LOCATION, weatherSpec.location)
|
||||
.putExtra(EXTRA_WEATHER_CURRENTTEMP, weatherSpec.currentTemp)
|
||||
.putExtra(EXTRA_WEATHER_CURRENTCONDITIONCODE, weatherSpec.currentConditionCode)
|
||||
.putExtra(EXTRA_WEATHER_CURRENTCONDITION, weatherSpec.currentCondition)
|
||||
.putExtra(EXTRA_WEATHER_TODAYMAXTEMP, weatherSpec.todayMaxTemp)
|
||||
.putExtra(EXTRA_WEATHER_TODAYMINTEMP, weatherSpec.todayMinTemp)
|
||||
.putExtra(EXTRA_WEATHER_TOMORROWMAXTEMP, weatherSpec.tomorrowMaxTemp)
|
||||
.putExtra(EXTRA_WEATHER_TOMORROWMINTEMP, weatherSpec.tomorrowMinTemp)
|
||||
.putExtra(EXTRA_WEATHER_TOMORROWCONDITIONCODE, weatherSpec.tomorrowConditionCode);
|
||||
invokeService(intent);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,9 @@ public class AppNotificationType extends HashMap<String, NotificationType> {
|
|||
// Conversations
|
||||
put("eu.siacs.conversations", NotificationType.CONVERSATIONS);
|
||||
|
||||
// Riot
|
||||
put("im.vector.alpha", NotificationType.RIOT);
|
||||
|
||||
// Signal
|
||||
put("org.thoughtcrime.securesms", NotificationType.SIGNAL);
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ public interface DeviceService extends EventHandler {
|
|||
String ACTION_START = PREFIX + ".action.start";
|
||||
String ACTION_CONNECT = PREFIX + ".action.connect";
|
||||
String ACTION_NOTIFICATION = PREFIX + ".action.notification";
|
||||
String ACTION_DELETE_NOTIFICATION = PREFIX + ".action.delete_notification";
|
||||
String ACTION_CALLSTATE = PREFIX + ".action.callstate";
|
||||
String ACTION_SETCANNEDMESSAGES = PREFIX + ".action.setcannedmessages";
|
||||
String ACTION_SETTIME = PREFIX + ".action.settime";
|
||||
|
@ -38,17 +39,13 @@ public interface DeviceService extends EventHandler {
|
|||
String ACTION_SET_ALARMS = PREFIX + ".action.set_alarms";
|
||||
String ACTION_ENABLE_REALTIME_STEPS = PREFIX + ".action.enable_realtime_steps";
|
||||
String ACTION_REALTIME_SAMPLES = PREFIX + ".action.realtime_samples";
|
||||
/**
|
||||
* Use EXTRA_REALTIME_SAMPLE instead
|
||||
*/
|
||||
@Deprecated
|
||||
String ACTION_REALTIME_STEPS = PREFIX + ".action.realtime_steps";
|
||||
String ACTION_ENABLE_REALTIME_HEARTRATE_MEASUREMENT = PREFIX + ".action.realtime_hr_measurement";
|
||||
String ACTION_ENABLE_HEARTRATE_SLEEP_SUPPORT = PREFIX + ".action.enable_heartrate_sleep_support";
|
||||
String ACTION_HEARTRATE_MEASUREMENT = PREFIX + ".action.hr_measurement";
|
||||
String ACTION_ADD_CALENDAREVENT = PREFIX + ".action.add_calendarevent";
|
||||
String ACTION_DELETE_CALENDAREVENT = PREFIX + ".action.delete_calendarevent";
|
||||
String ACTION_SEND_CONFIGURATION = PREFIX + ".action.send_configuration";
|
||||
String ACTION_SEND_WEATHER = PREFIX + ".action.send_weather";
|
||||
String ACTION_TEST_NEW_FUNCTION = PREFIX + ".action.test_new_function";
|
||||
String EXTRA_DEVICE_ADDRESS = "device_address";
|
||||
String EXTRA_NOTIFICATION_BODY = "notification_body";
|
||||
|
@ -85,6 +82,18 @@ public interface DeviceService extends EventHandler {
|
|||
String EXTRA_ALARMS = "alarms";
|
||||
String EXTRA_PERFORM_PAIR = "perform_pair";
|
||||
String EXTRA_BOOLEAN_ENABLE = "enable_realtime_steps";
|
||||
|
||||
String EXTRA_WEATHER_TIMESTAMP = "weather_timestamp";
|
||||
String EXTRA_WEATHER_LOCATION = "weather_location";
|
||||
String EXTRA_WEATHER_CURRENTTEMP = "weather_currenttemp";
|
||||
String EXTRA_WEATHER_CURRENTCONDITIONCODE = "weather_currentconditioncode";
|
||||
String EXTRA_WEATHER_CURRENTCONDITION = "currentcondition";
|
||||
String EXTRA_WEATHER_TODAYMAXTEMP = "weather_todaymaxtemp";
|
||||
String EXTRA_WEATHER_TODAYMINTEMP = "weather_todaymintemp";
|
||||
String EXTRA_WEATHER_TOMORROWMAXTEMP = "weather_tomorrowmaxtemp";
|
||||
String EXTRA_WEATHER_TOMORROWMINTEMP = "weather_tomorrowmintemp";
|
||||
String EXTRA_WEATHER_TOMORROWCONDITIONCODE = "weather_tomorrowconditioncode";
|
||||
|
||||
/**
|
||||
* Use EXTRA_REALTIME_SAMPLE instead
|
||||
*/
|
||||
|
|
|
@ -13,6 +13,7 @@ public enum NotificationType {
|
|||
GENERIC_SMS(PebbleIconID.GENERIC_SMS, PebbleColor.VividViolet),
|
||||
FACEBOOK(PebbleIconID.NOTIFICATION_FACEBOOK, PebbleColor.Liberty),
|
||||
FACEBOOK_MESSENGER(PebbleIconID.NOTIFICATION_FACEBOOK_MESSENGER, PebbleColor.VeryLightBlue),
|
||||
RIOT(PebbleIconID.NOTIFICATION_HIPCHAT, PebbleColor.LavenderIndigo),
|
||||
SIGNAL(PebbleIconID.NOTIFICATION_HIPCHAT, PebbleColor.BlueMoon),
|
||||
TWITTER(PebbleIconID.NOTIFICATION_TWITTER, PebbleColor.BlueMoon),
|
||||
TELEGRAM(PebbleIconID.NOTIFICATION_TELEGRAM, PebbleColor.PictonBlue),
|
||||
|
@ -46,6 +47,7 @@ public enum NotificationType {
|
|||
return "generic_social";
|
||||
case CONVERSATIONS:
|
||||
case FACEBOOK_MESSENGER:
|
||||
case RIOT:
|
||||
case SIGNAL:
|
||||
case TELEGRAM:
|
||||
case WHATSAPP:
|
||||
|
|
|
@ -0,0 +1,351 @@
|
|||
package nodomain.freeyourgadget.gadgetbridge.model;
|
||||
|
||||
import ru.gelin.android.weather.notification.ParcelableWeather2;
|
||||
|
||||
public class Weather {
|
||||
private ParcelableWeather2 weather2 = null;
|
||||
private WeatherSpec weatherSpec = null;
|
||||
|
||||
public ParcelableWeather2 getWeather2() {
|
||||
return weather2;
|
||||
}
|
||||
|
||||
public void setWeather2(ParcelableWeather2 weather2) {
|
||||
this.weather2 = weather2;
|
||||
}
|
||||
|
||||
public WeatherSpec getWeatherSpec() {
|
||||
return weatherSpec;
|
||||
}
|
||||
|
||||
public void setWeatherSpec(WeatherSpec weatherSpec) {
|
||||
this.weatherSpec = weatherSpec;
|
||||
}
|
||||
|
||||
private static final Weather weather = new Weather();
|
||||
public static Weather getInstance() {return weather;}
|
||||
|
||||
public static byte mapToPebbleCondition(int openWeatherMapCondition) {
|
||||
/* deducted values:
|
||||
0 = sun + cloud
|
||||
1 = clouds
|
||||
2 = some snow
|
||||
3 = some rain
|
||||
4 = heavy rain
|
||||
5 = heavy snow
|
||||
6 = sun + cloud + rain (default icon?)
|
||||
7 = sun
|
||||
8 = rain + snow
|
||||
9 = 6
|
||||
10, 11, ... = empty icon
|
||||
*/
|
||||
switch (openWeatherMapCondition) {
|
||||
//Group 2xx: Thunderstorm
|
||||
case 200: //thunderstorm with light rain: //11d
|
||||
case 201: //thunderstorm with rain: //11d
|
||||
case 202: //thunderstorm with heavy rain: //11d
|
||||
case 210: //light thunderstorm:: //11d
|
||||
case 211: //thunderstorm: //11d
|
||||
case 230: //thunderstorm with light drizzle: //11d
|
||||
case 231: //thunderstorm with drizzle: //11d
|
||||
case 232: //thunderstorm with heavy drizzle: //11d
|
||||
case 212: //heavy thunderstorm: //11d
|
||||
case 221: //ragged thunderstorm: //11d
|
||||
return 4;
|
||||
//Group 3xx: Drizzle
|
||||
case 300: //light intensity drizzle: //09d
|
||||
case 301: //drizzle: //09d
|
||||
case 302: //heavy intensity drizzle: //09d
|
||||
case 310: //light intensity drizzle rain: //09d
|
||||
case 311: //drizzle rain: //09d
|
||||
case 312: //heavy intensity drizzle rain: //09d
|
||||
case 313: //shower rain and drizzle: //09d
|
||||
case 314: //heavy shower rain and drizzle: //09d
|
||||
case 321: //shower drizzle: //09d
|
||||
case 500: //light rain: //10d
|
||||
case 501: //moderate rain: //10d
|
||||
return 3;
|
||||
//Group 5xx: Rain
|
||||
case 502: //heavy intensity rain: //10d
|
||||
case 503: //very heavy rain: //10d
|
||||
case 504: //extreme rain: //10d
|
||||
case 511: //freezing rain: //13d
|
||||
case 520: //light intensity shower rain: //09d
|
||||
case 521: //shower rain: //09d
|
||||
case 522: //heavy intensity shower rain: //09d
|
||||
case 531: //ragged shower rain: //09d
|
||||
return 4;
|
||||
//Group 6xx: Snow
|
||||
case 600: //light snow: //[[file:13d.png]]
|
||||
case 601: //snow: //[[file:13d.png]]
|
||||
case 620: //light shower snow: //[[file:13d.png]]
|
||||
return 2;
|
||||
case 602: //heavy snow: //[[file:13d.png]]
|
||||
case 611: //sleet: //[[file:13d.png]]
|
||||
case 612: //shower sleet: //[[file:13d.png]]
|
||||
case 621: //shower snow: //[[file:13d.png]]
|
||||
case 622: //heavy shower snow: //[[file:13d.png]]
|
||||
return 5;
|
||||
case 615: //light rain and snow: //[[file:13d.png]]
|
||||
case 616: //rain and snow: //[[file:13d.png]]
|
||||
return 8;
|
||||
//Group 7xx: Atmosphere
|
||||
case 701: //mist: //[[file:50d.png]]
|
||||
case 711: //smoke: //[[file:50d.png]]
|
||||
case 721: //haze: //[[file:50d.png]]
|
||||
case 731: //sandcase dust whirls: //[[file:50d.png]]
|
||||
case 741: //fog: //[[file:50d.png]]
|
||||
case 751: //sand: //[[file:50d.png]]
|
||||
case 761: //dust: //[[file:50d.png]]
|
||||
case 762: //volcanic ash: //[[file:50d.png]]
|
||||
case 771: //squalls: //[[file:50d.png]]
|
||||
case 781: //tornado: //[[file:50d.png]]
|
||||
case 900: //tornado
|
||||
return 6;
|
||||
//Group 800: Clear
|
||||
case 800: //clear sky: //[[file:01d.png]] [[file:01n.png]]
|
||||
return 7;
|
||||
//Group 80x: Clouds
|
||||
case 801: //few clouds: //[[file:02d.png]] [[file:02n.png]]
|
||||
case 802: //scattered clouds: //[[file:03d.png]] [[file:03d.png]]
|
||||
case 803: //broken clouds: //[[file:04d.png]] [[file:03d.png]]
|
||||
case 804: //overcast clouds: //[[file:04d.png]] [[file:04d.png]]
|
||||
return 0;
|
||||
//Group 90x: Extreme
|
||||
case 901: //tropical storm
|
||||
case 903: //cold
|
||||
case 904: //hot
|
||||
case 905: //windy
|
||||
case 906: //hail
|
||||
//Group 9xx: Additional
|
||||
case 951: //calm
|
||||
case 952: //light breeze
|
||||
case 953: //gentle breeze
|
||||
case 954: //moderate breeze
|
||||
case 955: //fresh breeze
|
||||
case 956: //strong breeze
|
||||
case 957: //high windcase near gale
|
||||
case 958: //gale
|
||||
case 959: //severe gale
|
||||
case 960: //storm
|
||||
case 961: //violent storm
|
||||
case 902: //hurricane
|
||||
case 962: //hurricane
|
||||
default:
|
||||
return 6;
|
||||
|
||||
}
|
||||
}
|
||||
public static int mapToYahooCondition(int openWeatherMapCondition) {
|
||||
// openweathermap.org conditions:
|
||||
// http://openweathermap.org/weather-conditions
|
||||
switch (openWeatherMapCondition) {
|
||||
//Group 2xx: Thunderstorm
|
||||
case 200: //thunderstorm with light rain: //11d
|
||||
case 201: //thunderstorm with rain: //11d
|
||||
case 202: //thunderstorm with heavy rain: //11d
|
||||
case 210: //light thunderstorm:: //11d
|
||||
case 211: //thunderstorm: //11d
|
||||
case 230: //thunderstorm with light drizzle: //11d
|
||||
case 231: //thunderstorm with drizzle: //11d
|
||||
case 232: //thunderstorm with heavy drizzle: //11d
|
||||
return 4;
|
||||
case 212: //heavy thunderstorm: //11d
|
||||
case 221: //ragged thunderstorm: //11d
|
||||
return 3;
|
||||
//Group 3xx: Drizzle
|
||||
case 300: //light intensity drizzle: //09d
|
||||
case 301: //drizzle: //09d
|
||||
case 302: //heavy intensity drizzle: //09d
|
||||
case 310: //light intensity drizzle rain: //09d
|
||||
case 311: //drizzle rain: //09d
|
||||
case 312: //heavy intensity drizzle rain: //09d
|
||||
return 9;
|
||||
case 313: //shower rain and drizzle: //09d
|
||||
case 314: //heavy shower rain and drizzle: //09d
|
||||
case 321: //shower drizzle: //09d
|
||||
return 11;
|
||||
//Group 5xx: Rain
|
||||
case 500: //light rain: //10d
|
||||
case 501: //moderate rain: //10d
|
||||
case 502: //heavy intensity rain: //10d
|
||||
case 503: //very heavy rain: //10d
|
||||
case 504: //extreme rain: //10d
|
||||
case 511: //freezing rain: //13d
|
||||
return 10;
|
||||
case 520: //light intensity shower rain: //09d
|
||||
return 40;
|
||||
case 521: //shower rain: //09d
|
||||
case 522: //heavy intensity shower rain: //09d
|
||||
case 531: //ragged shower rain: //09d
|
||||
return 12;
|
||||
//Group 6xx: Snow
|
||||
case 600: //light snow: //[[file:13d.png]]
|
||||
return 7;
|
||||
case 601: //snow: //[[file:13d.png]]
|
||||
return 16;
|
||||
case 602: //heavy snow: //[[file:13d.png]]
|
||||
return 15;
|
||||
case 611: //sleet: //[[file:13d.png]]
|
||||
case 612: //shower sleet: //[[file:13d.png]]
|
||||
return 18;
|
||||
case 615: //light rain and snow: //[[file:13d.png]]
|
||||
case 616: //rain and snow: //[[file:13d.png]]
|
||||
return 5;
|
||||
case 620: //light shower snow: //[[file:13d.png]]
|
||||
return 14;
|
||||
case 621: //shower snow: //[[file:13d.png]]
|
||||
return 46;
|
||||
case 622: //heavy shower snow: //[[file:13d.png]]
|
||||
//Group 7xx: Atmosphere
|
||||
case 701: //mist: //[[file:50d.png]]
|
||||
case 711: //smoke: //[[file:50d.png]]
|
||||
return 22;
|
||||
case 721: //haze: //[[file:50d.png]]
|
||||
return 21;
|
||||
case 731: //sandcase dust whirls: //[[file:50d.png]]
|
||||
return 3200;
|
||||
case 741: //fog: //[[file:50d.png]]
|
||||
return 20;
|
||||
case 751: //sand: //[[file:50d.png]]
|
||||
case 761: //dust: //[[file:50d.png]]
|
||||
return 19;
|
||||
case 762: //volcanic ash: //[[file:50d.png]]
|
||||
case 771: //squalls: //[[file:50d.png]]
|
||||
return 3200;
|
||||
case 781: //tornado: //[[file:50d.png]]
|
||||
case 900: //tornado
|
||||
return 0;
|
||||
//Group 800: Clear
|
||||
case 800: //clear sky: //[[file:01d.png]] [[file:01n.png]]
|
||||
return 32;
|
||||
//Group 80x: Clouds
|
||||
case 801: //few clouds: //[[file:02d.png]] [[file:02n.png]]
|
||||
case 802: //scattered clouds: //[[file:03d.png]] [[file:03d.png]]
|
||||
return 34;
|
||||
case 803: //broken clouds: //[[file:04d.png]] [[file:03d.png]]
|
||||
case 804: //overcast clouds: //[[file:04d.png]] [[file:04d.png]]
|
||||
return 44;
|
||||
//Group 90x: Extreme
|
||||
case 901: //tropical storm
|
||||
return 1;
|
||||
case 903: //cold
|
||||
return 25;
|
||||
case 904: //hot
|
||||
return 36;
|
||||
case 905: //windy
|
||||
return 24;
|
||||
case 906: //hail
|
||||
return 17;
|
||||
//Group 9xx: Additional
|
||||
case 951: //calm
|
||||
case 952: //light breeze
|
||||
case 953: //gentle breeze
|
||||
case 954: //moderate breeze
|
||||
case 955: //fresh breeze
|
||||
return 34;
|
||||
case 956: //strong breeze
|
||||
case 957: //high windcase near gale
|
||||
return 24;
|
||||
case 958: //gale
|
||||
case 959: //severe gale
|
||||
case 960: //storm
|
||||
case 961: //violent storm
|
||||
return 3200;
|
||||
case 902: //hurricane
|
||||
case 962: //hurricane
|
||||
return 2;
|
||||
default:
|
||||
return 3200;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static int mapToOpenWeatherMapCondition(int yahooCondition) {
|
||||
switch (yahooCondition) {
|
||||
//yahoo weather conditions:
|
||||
//https://developer.yahoo.com/weather/documentation.html
|
||||
case 0: //tornado
|
||||
return 900;
|
||||
case 1: //tropical storm
|
||||
return 901;
|
||||
case 2: //hurricane
|
||||
return 962;
|
||||
case 3: //severe thunderstorms
|
||||
return 212;
|
||||
case 4: //thunderstorms
|
||||
return 211;
|
||||
case 5: //mixed rain and snow
|
||||
case 6: //mixed rain and sleet
|
||||
return 616;
|
||||
case 7: //mixed snow and sleet
|
||||
return 600;
|
||||
case 8: //freezing drizzle
|
||||
case 9: //drizzle
|
||||
return 301;
|
||||
case 10: //freezing rain
|
||||
return 511;
|
||||
case 11: //showers
|
||||
case 12: //showers
|
||||
return 521;
|
||||
case 13: //snow flurries
|
||||
case 14: //light snow showers
|
||||
return 620;
|
||||
case 15: //blowing snow
|
||||
case 41: //heavy snow
|
||||
case 42: //scattered snow showers
|
||||
case 43: //heavy snow
|
||||
case 46: //snow showers
|
||||
return 602;
|
||||
case 16: //snow
|
||||
return 601;
|
||||
case 17: //hail
|
||||
case 35: //mixed rain and hail
|
||||
return 906;
|
||||
case 18: //sleet
|
||||
return 611;
|
||||
case 19: //dust
|
||||
return 761;
|
||||
case 20: //foggy
|
||||
return 741;
|
||||
case 21: //haze
|
||||
return 721;
|
||||
case 22: //smoky
|
||||
return 711;
|
||||
case 23: //blustery
|
||||
case 24: //windy
|
||||
return 905;
|
||||
case 25: //cold
|
||||
return 903;
|
||||
case 26: //cloudy
|
||||
case 27: //mostly cloudy (night)
|
||||
case 28: //mostly cloudy (day)
|
||||
return 804;
|
||||
case 29: //partly cloudy (night)
|
||||
case 30: //partly cloudy (day)
|
||||
return 801;
|
||||
case 31: //clear (night)
|
||||
case 32: //sunny
|
||||
return 800;
|
||||
case 33: //fair (night)
|
||||
case 34: //fair (day)
|
||||
return 801;
|
||||
case 36: //hot
|
||||
return 904;
|
||||
case 37: //isolated thunderstorms
|
||||
case 38: //scattered thunderstorms
|
||||
case 39: //scattered thunderstorms
|
||||
return 210;
|
||||
case 40: //scattered showers
|
||||
return 520;
|
||||
case 44: //partly cloudy
|
||||
return 801;
|
||||
case 45: //thundershowers
|
||||
case 47: //isolated thundershowers
|
||||
return 621;
|
||||
case 3200: //not available
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package nodomain.freeyourgadget.gadgetbridge.model;
|
||||
|
||||
public class WeatherSpec {
|
||||
public int timestamp;
|
||||
public String location;
|
||||
public int currentTemp;
|
||||
public int currentConditionCode;
|
||||
public String currentCondition;
|
||||
public int todayMaxTemp;
|
||||
public int todayMinTemp;
|
||||
public int tomorrowMaxTemp;
|
||||
public int tomorrowMinTemp;
|
||||
public int tomorrowConditionCode;
|
||||
}
|
|
@ -47,6 +47,7 @@ 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.util.DeviceHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
|
||||
|
@ -59,6 +60,7 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_CA
|
|||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_CONNECT;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_DELETEAPP;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_DELETE_CALENDAREVENT;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_DELETE_NOTIFICATION;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_DISCONNECT;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_ENABLE_HEARTRATE_SLEEP_SUPPORT;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_ENABLE_REALTIME_HEARTRATE_MEASUREMENT;
|
||||
|
@ -73,6 +75,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_SEND_CONFIGURATION;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_SEND_WEATHER;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_SETCANNEDMESSAGES;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_SETMUSICINFO;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_SETMUSICSTATE;
|
||||
|
@ -123,6 +126,16 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOT
|
|||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_PERFORM_PAIR;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_URI;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_VIBRATION_INTENSITY;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_CURRENTCONDITION;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_CURRENTCONDITIONCODE;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_CURRENTTEMP;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_LOCATION;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_TIMESTAMP;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_TODAYMAXTEMP;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_TODAYMINTEMP;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_TOMORROWCONDITIONCODE;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_TOMORROWMAXTEMP;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_TOMORROWMINTEMP;
|
||||
|
||||
public class DeviceCommunicationService extends Service implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DeviceCommunicationService.class);
|
||||
|
@ -343,6 +356,10 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
|
|||
mDeviceSupport.onNotification(notificationSpec);
|
||||
break;
|
||||
}
|
||||
case ACTION_DELETE_NOTIFICATION: {
|
||||
mDeviceSupport.onDeleteNotification(intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1));
|
||||
break;
|
||||
}
|
||||
case ACTION_ADD_CALENDAREVENT: {
|
||||
CalendarEventSpec calendarEventSpec = new CalendarEventSpec();
|
||||
calendarEventSpec.id = intent.getLongExtra(EXTRA_CALENDAREVENT_ID, -1);
|
||||
|
@ -501,6 +518,21 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
|
|||
mDeviceSupport.onTestNewFunction();
|
||||
break;
|
||||
}
|
||||
case ACTION_SEND_WEATHER: {
|
||||
WeatherSpec weatherSpec = new WeatherSpec();
|
||||
weatherSpec.timestamp = intent.getIntExtra(EXTRA_WEATHER_TIMESTAMP, 0);
|
||||
weatherSpec.location = intent.getStringExtra(EXTRA_WEATHER_LOCATION);
|
||||
weatherSpec.currentTemp = intent.getIntExtra(EXTRA_WEATHER_CURRENTTEMP, 0);
|
||||
weatherSpec.currentConditionCode = intent.getIntExtra(EXTRA_WEATHER_CURRENTCONDITIONCODE, 0);
|
||||
weatherSpec.currentCondition = intent.getStringExtra(EXTRA_WEATHER_CURRENTCONDITION);
|
||||
weatherSpec.todayMaxTemp = intent.getIntExtra(EXTRA_WEATHER_TODAYMAXTEMP, 0);
|
||||
weatherSpec.todayMinTemp = intent.getIntExtra(EXTRA_WEATHER_TODAYMINTEMP, 0);
|
||||
weatherSpec.tomorrowMaxTemp = intent.getIntExtra(EXTRA_WEATHER_TOMORROWMAXTEMP, 0);
|
||||
weatherSpec.tomorrowMinTemp = intent.getIntExtra(EXTRA_WEATHER_TOMORROWMINTEMP, 0);
|
||||
weatherSpec.tomorrowConditionCode = intent.getIntExtra(EXTRA_WEATHER_TOMORROWCONDITIONCODE, 0);
|
||||
mDeviceSupport.onSendWeather(weatherSpec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return START_STICKY;
|
||||
|
@ -576,6 +608,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
|
|||
mMusicPlaybackReceiver = new MusicPlaybackReceiver();
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction("com.android.music.metachanged");
|
||||
filter.addAction("net.sourceforge.subsonic.androidapp.EVENT_META_CHANGED");
|
||||
//filter.addAction("com.android.music.playstatechanged");
|
||||
registerReceiver(mMusicPlaybackReceiver, filter);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
|||
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
|
||||
/**
|
||||
* Wraps another device support instance and supports busy-checking and throttling of events.
|
||||
|
@ -134,6 +135,11 @@ public class ServiceDeviceSupport implements DeviceSupport {
|
|||
delegate.onNotification(notificationSpec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleteNotification(int id) {
|
||||
delegate.onDeleteNotification(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetTime() {
|
||||
if (checkBusy("set time") || checkThrottle("set time")) {
|
||||
|
@ -335,4 +341,12 @@ public class ServiceDeviceSupport implements DeviceSupport {
|
|||
}
|
||||
delegate.onTestNewFunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
||||
if (checkBusy("send weather event")) {
|
||||
return;
|
||||
}
|
||||
delegate.onSendWeather(weatherSpec);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
package nodomain.freeyourgadget.gadgetbridge.service.btle;
|
||||
|
||||
import android.bluetooth.BluetoothGattCharacteristic;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
@ -178,64 +181,12 @@ public class GattCharacteristic {
|
|||
public static final UUID UUID_CHARACTERISTIC_WIND_CHILL = UUID.fromString((String.format(AbstractBTLEDeviceSupport.BASE_UUID, "2A79")));
|
||||
|
||||
|
||||
//do we need this?
|
||||
private static Map<UUID, String> GATTCHARACTERISTIC_DEBUG;
|
||||
|
||||
private static final Map<UUID, String> GATTCHARACTERISTIC_DEBUG;
|
||||
|
||||
static {
|
||||
GATTCHARACTERISTIC_DEBUG = new HashMap<>();
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_ALERT_CATEGORY_ID, "Alert AlertCategory ID");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_ALERT_CATEGORY_ID_BIT_MASK, "Alert AlertCategory ID Bit Mask");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_ALERT_LEVEL, "Alert Level");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_ALERT_NOTIFICATION_CONTROL_POINT, "Alert Notification Control Point");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_ALERT_STATUS, "Alert Status");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_GAP_APPEARANCE, "Appearance");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_BLOOD_PRESSURE_FEATURE, "Blood Pressure Feature");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_BLOOD_PRESSURE_MEASUREMENT, "Blood Pressure Measurement");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_BODY_SENSOR_LOCATION, "Body Sensor Location");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_CURRENT_TIME, "Current Time");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_DATE_TIME, "Date Time");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_DAY_DATE_TIME, "Day Date Time");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_DAY_OF_WEEK, "Day of Week");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_GAP_DEVICE_NAME, "Device Name");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_DST_OFFSET, "DST Offset");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_EXACT_TIME_256, "Exact Time 256");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_FIRMWARE_REVISION_STRING, "Firmware Revision String");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_HARDWARE_REVISION_STRING, "Hardware Revision String");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT, "Heart Rate Control Point");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_HEART_RATE_MEASUREMENT, "Heart Rate Measurement");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_IEEE_11073_20601_REGULATORY_CERTIFICATION_DATA_LIST, "IEEE 11073-20601 Regulatory");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_INTERMEDIATE_BLOOD_PRESSURE, "Intermediate Cuff Pressure");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_INTERMEDIATE_TEMPERATURE, "Intermediate Temperature");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_LOCAL_TIME_INFORMATION, "Local Time Information");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_MANUFACTURER_NAME_STRING, "Manufacturer Name String");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_MEASUREMENT_INTERVAL, "Measurement Interval");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_MODEL_NUMBER_STRING, "Model Number String");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_NEW_ALERT, "New Alert");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_GAP_PERIPHERAL_PREFERRED_CONNECTION_PARAMETERS, "Peripheral Preferred Connection Parameters");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_GAP_PERIPHERAL_PRIVACY_FLAG, "Peripheral Privacy Flag");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_GAP_RECONNECTION_ADDRESS, "Reconnection Address");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_REFERENCE_TIME_INFORMATION, "Reference Time Information");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_RINGER_CONTROL_POINT, "Ringer Control Point");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_RINGER_SETTING, "Ringer Setting");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_SERIAL_NUMBER_STRING, "Serial Number String");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_GATT_SERVICE_CHANGED, "Service Changed");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_SOFTWARE_REVISION_STRING, "Software Revision String");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_SUPPORTED_NEW_ALERT_CATEGORY, "Supported New Alert AlertCategory");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_SUPPORTED_UNREAD_ALERT_CATEGORY, "Supported Unread Alert AlertCategory");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_SYSTEM_ID, "System ID");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_TEMPERATURE_MEASUREMENT, "Temperature Measurement");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_TEMPERATURE_TYPE, "Temperature DeviceType");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_TIME_ACCURACY, "Time Accuracy");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_TIME_SOURCE, "Time Source");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_TIME_UPDATE_CONTROL_POINT, "Time Update Control Point");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_TIME_UPDATE_STATE, "Time Update State");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_TIME_WITH_DST, "Time with DST");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_TIME_ZONE, "Time Zone");
|
||||
GATTCHARACTERISTIC_DEBUG.put(UUID_CHARACTERISTIC_TX_POWER_LEVEL, "Tx Power Level");
|
||||
}
|
||||
|
||||
public static String lookup(UUID uuid, String fallback) {
|
||||
public static synchronized String lookup(UUID uuid, String fallback) {
|
||||
if (GATTCHARACTERISTIC_DEBUG == null) {
|
||||
GATTCHARACTERISTIC_DEBUG = initDebugMap();
|
||||
}
|
||||
String name = GATTCHARACTERISTIC_DEBUG.get(uuid);
|
||||
if (name == null) {
|
||||
name = fallback;
|
||||
|
@ -243,6 +194,42 @@ public class GattCharacteristic {
|
|||
return name;
|
||||
}
|
||||
|
||||
private static Map<UUID, String> initDebugMap() {
|
||||
Map<UUID,String> map = new HashMap<>();
|
||||
|
||||
try {
|
||||
for (Field field : GattCharacteristic.class.getDeclaredFields()) {
|
||||
if ((field.getModifiers() & Modifier.STATIC) != 0 && field.getType() == UUID.class) {
|
||||
UUID uuid = (UUID) field.get(null);
|
||||
if (uuid != null) {
|
||||
map.put(uuid, toPrettyName(field.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Log.w(GattCharacteristic.class.getName(), "Error reading UUID fields by reflection: " + ex.getMessage(), ex);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private static String toPrettyName(String fieldName) {
|
||||
String[] words = fieldName.split("_");
|
||||
if (words.length <= 1) {
|
||||
return fieldName.toLowerCase();
|
||||
}
|
||||
StringBuilder builder = new StringBuilder(fieldName.length());
|
||||
for (String word : words) {
|
||||
if (word.length() == 0 || "UUID".equals(word) || "CHARACTERISTIC".equals(word)) {
|
||||
continue;
|
||||
}
|
||||
if (builder.length() > 0) {
|
||||
builder.append(" ");
|
||||
}
|
||||
builder.append(word.toLowerCase());
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static String toString(BluetoothGattCharacteristic characteristic) {
|
||||
return characteristic.getUuid() + " (" + lookup(characteristic.getUuid(), "unknown") + ")";
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
|||
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
|
@ -429,6 +430,11 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
|
|||
showText(notificationSpec.title, notificationSpec.body);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleteNotification(int id) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetTime() {
|
||||
TransactionBuilder builder = new TransactionBuilder("time");
|
||||
|
@ -631,6 +637,11 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
|
|||
LOG.debug("Test New Function");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void showIncomingCall(String name, String number) {
|
||||
try {
|
||||
|
|
|
@ -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.WeatherSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic;
|
||||
|
@ -544,6 +545,11 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
|||
performPreferredNotification(origin + " received", origin, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleteNotification(int id) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetTime() {
|
||||
try {
|
||||
|
@ -950,30 +956,25 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
|||
MiBandSampleProvider provider = new MiBandSampleProvider(gbDevice, session);
|
||||
MiBandActivitySample sample = createActivitySample(device, user, ts, provider);
|
||||
sample.setHeartRate(getHeartrateBpm());
|
||||
sample.setSteps(getSteps());
|
||||
sample.setRawIntensity(ActivitySample.NOT_MEASURED);
|
||||
sample.setRawKind(MiBandSampleProvider.TYPE_ACTIVITY); // to make it visible in the charts TODO: add a MANUAL kind for that?
|
||||
|
||||
// TODO: remove this once fully ported to REALTIME_SAMPLES
|
||||
if (sample.getSteps() != ActivitySample.NOT_MEASURED) {
|
||||
Intent intent = new Intent(DeviceService.ACTION_REALTIME_STEPS)
|
||||
.putExtra(DeviceService.EXTRA_REALTIME_STEPS, sample.getSteps())
|
||||
.putExtra(DeviceService.EXTRA_TIMESTAMP, System.currentTimeMillis());
|
||||
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
|
||||
}
|
||||
if (sample.getHeartRate() != ActivitySample.NOT_MEASURED) {
|
||||
Intent intent = new Intent(DeviceService.ACTION_HEARTRATE_MEASUREMENT)
|
||||
.putExtra(DeviceService.EXTRA_HEART_RATE_VALUE, sample.getHeartRate())
|
||||
.putExtra(DeviceService.EXTRA_TIMESTAMP, System.currentTimeMillis());
|
||||
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
|
||||
}
|
||||
|
||||
// Intent intent = new Intent(DeviceService.ACTION_REALTIME_SAMPLES)
|
||||
// .putExtra(DeviceService.EXTRA_REALTIME_SAMPLE, sample);
|
||||
// LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
|
||||
|
||||
LOG.debug("Storing realtime sample: " + sample);
|
||||
provider.addGBActivitySample(sample);
|
||||
|
||||
// set the steps only afterwards, since realtime steps are also recorded
|
||||
// in the regular samples and we must not count them twice
|
||||
// Note: we know that the DAO sample is never committed again, so we simply
|
||||
// change the value here in memory.
|
||||
sample.setSteps(getSteps());
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("realtime sample: " + sample);
|
||||
}
|
||||
|
||||
Intent intent = new Intent(DeviceService.ACTION_REALTIME_SAMPLES)
|
||||
.putExtra(DeviceService.EXTRA_REALTIME_SAMPLE, sample);
|
||||
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
|
||||
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Unable to acquire db for saving realtime samples", e);
|
||||
}
|
||||
|
@ -1211,6 +1212,11 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
||||
|
||||
}
|
||||
|
||||
private void handleSensorData(byte[] value) {
|
||||
int counter=0, step=0, axis1=0, axis2=0, axis3 =0;
|
||||
if ((value.length - 2) % 6 != 0) {
|
||||
|
|
|
@ -22,6 +22,7 @@ public abstract class RealtimeSamplesSupport {
|
|||
|
||||
protected int steps;
|
||||
protected int heartrateBpm;
|
||||
private int lastSteps;
|
||||
// subclasses may add more
|
||||
|
||||
private Timer realtimeStorageTimer;
|
||||
|
@ -56,12 +57,27 @@ public abstract class RealtimeSamplesSupport {
|
|||
return realtimeStorageTimer != null;
|
||||
}
|
||||
|
||||
public void setSteps(int stepsPerMinute) {
|
||||
public synchronized void setSteps(int stepsPerMinute) {
|
||||
this.steps = stepsPerMinute;
|
||||
}
|
||||
|
||||
public int getSteps() {
|
||||
return steps;
|
||||
/**
|
||||
* Returns the number of steps recorded since the last measurements. If no
|
||||
* steps are available yet, ActivitySample.NOT_MEASURED is returned.
|
||||
* @return
|
||||
*/
|
||||
public synchronized int getSteps() {
|
||||
if (steps == ActivitySample.NOT_MEASURED) {
|
||||
return ActivitySample.NOT_MEASURED;
|
||||
}
|
||||
if (lastSteps == 0) {
|
||||
return ActivitySample.NOT_MEASURED; // wait until we have a delta between two samples
|
||||
}
|
||||
int delta = steps - lastSteps;
|
||||
if (delta < 0) {
|
||||
return 0;
|
||||
}
|
||||
return delta;
|
||||
}
|
||||
|
||||
public void setHeartrateBpm(int hrBpm) {
|
||||
|
@ -77,7 +93,10 @@ public abstract class RealtimeSamplesSupport {
|
|||
resetCurrentValues();
|
||||
}
|
||||
|
||||
protected void resetCurrentValues() {
|
||||
protected synchronized void resetCurrentValues() {
|
||||
if (steps >= lastSteps) {
|
||||
lastSteps = steps;
|
||||
}
|
||||
steps = ActivitySample.NOT_MEASURED;
|
||||
heartrateBpm = ActivitySample.NOT_MEASURED;
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ public class FetchActivityOperation extends AbstractMiBand1Operation {
|
|||
private final boolean hasExtendedActivityData;
|
||||
|
||||
private static class ActivityStruct {
|
||||
private int lastNotifiedProgress;
|
||||
private final byte[] activityDataHolder;
|
||||
private final int activityDataHolderSize;
|
||||
//index of the buffer above
|
||||
|
@ -129,6 +130,7 @@ public class FetchActivityOperation extends AbstractMiBand1Operation {
|
|||
public void bufferFlushed(int minutes) {
|
||||
activityDataTimestampProgress.add(Calendar.MINUTE, minutes);
|
||||
activityDataHolderProgress = 0;
|
||||
lastNotifiedProgress = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,9 +201,16 @@ public class FetchActivityOperation extends AbstractMiBand1Operation {
|
|||
} else {
|
||||
bufferActivityData(value);
|
||||
}
|
||||
LOG.debug("activity data: length: " + value.length + ", remaining bytes: " + activityStruct.activityDataRemainingBytes);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("activity data: length: " + value.length + ", remaining bytes: " + activityStruct.activityDataRemainingBytes);
|
||||
}
|
||||
|
||||
GB.updateTransferNotification(getContext().getString(R.string.busy_task_fetch_activity_data), true, (int) (((float) (activityStruct.activityDataUntilNextHeader - activityStruct.activityDataRemainingBytes)) / activityStruct.activityDataUntilNextHeader * 100), getContext());
|
||||
int progress = (int) (((float) (activityStruct.activityDataUntilNextHeader - activityStruct.activityDataRemainingBytes)) / activityStruct.activityDataUntilNextHeader * 100);
|
||||
// avoid too many notifications overloading the system
|
||||
if (progress - activityStruct.lastNotifiedProgress >= 8) {
|
||||
activityStruct.lastNotifiedProgress = progress;
|
||||
GB.updateTransferNotification(getContext().getString(R.string.busy_task_fetch_activity_data), true, progress, getContext());
|
||||
}
|
||||
|
||||
if (activityStruct.isBlockFinished()) {
|
||||
sendAckDataTransfer(activityStruct.activityDataTimestampToAck, activityStruct.activityDataUntilNextHeader);
|
||||
|
|
|
@ -57,6 +57,7 @@ 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.BLETypeConversions;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction;
|
||||
|
@ -70,7 +71,6 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.Dev
|
|||
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.heartrate.HeartRateProfile;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.CheckAuthenticationNeededAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.DeviceInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.MiBandSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.NotificationStrategy;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.RealtimeSamplesSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.operations.FetchActivityOperation;
|
||||
|
@ -594,6 +594,11 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
|
|||
performPreferredNotification(origin + " received", origin, alertLevel, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleteNotification(int id) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetTime() {
|
||||
try {
|
||||
|
@ -983,26 +988,22 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
|
|||
sample.setRawIntensity(ActivitySample.NOT_MEASURED);
|
||||
sample.setRawKind(MiBand2SampleProvider.TYPE_ACTIVITY); // to make it visible in the charts TODO: add a MANUAL kind for that?
|
||||
|
||||
// TODO: remove this once fully ported to REALTIME_SAMPLES
|
||||
if (sample.getSteps() != ActivitySample.NOT_MEASURED) {
|
||||
Intent intent = new Intent(DeviceService.ACTION_REALTIME_STEPS)
|
||||
.putExtra(DeviceService.EXTRA_REALTIME_STEPS, sample.getSteps())
|
||||
.putExtra(DeviceService.EXTRA_TIMESTAMP, System.currentTimeMillis());
|
||||
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
|
||||
}
|
||||
if (sample.getHeartRate() != ActivitySample.NOT_MEASURED) {
|
||||
Intent intent = new Intent(DeviceService.ACTION_HEARTRATE_MEASUREMENT)
|
||||
.putExtra(DeviceService.EXTRA_HEART_RATE_VALUE, sample.getHeartRate())
|
||||
.putExtra(DeviceService.EXTRA_TIMESTAMP, System.currentTimeMillis());
|
||||
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
|
||||
}
|
||||
|
||||
// Intent intent = new Intent(DeviceService.ACTION_REALTIME_SAMPLES)
|
||||
// .putExtra(DeviceService.EXTRA_REALTIME_SAMPLE, sample);
|
||||
// LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
|
||||
|
||||
LOG.debug("Storing realtime sample: " + sample);
|
||||
provider.addGBActivitySample(sample);
|
||||
|
||||
// set the steps only afterwards, since realtime steps are also recorded
|
||||
// in the regular samples and we must not count them twice
|
||||
// Note: we know that the DAO sample is never committed again, so we simply
|
||||
// change the value here in memory.
|
||||
sample.setSteps(getSteps());
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("realtime sample: " + sample);
|
||||
}
|
||||
|
||||
Intent intent = new Intent(DeviceService.ACTION_REALTIME_SAMPLES)
|
||||
.putExtra(DeviceService.EXTRA_REALTIME_SAMPLE, sample);
|
||||
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
|
||||
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Unable to acquire db for saving realtime samples", e);
|
||||
}
|
||||
|
@ -1251,6 +1252,11 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
|
|||
public void onTestNewFunction() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
||||
|
||||
}
|
||||
|
||||
private MiBand2Support setDateDisplay(TransactionBuilder builder) {
|
||||
DateTimeDisplay dateTimeDisplay = MiBand2Coordinator.getDateDisplay(getContext());
|
||||
LOG.info("Setting date display to " + dateTimeDisplay);
|
||||
|
|
|
@ -2,6 +2,8 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.operations;
|
|||
|
||||
import android.bluetooth.BluetoothGatt;
|
||||
import android.bluetooth.BluetoothGattCharacteristic;
|
||||
import android.content.SharedPreferences;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
@ -23,7 +25,6 @@ import nodomain.freeyourgadget.gadgetbridge.R;
|
|||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBand2SampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBand2Service;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
|
@ -73,7 +74,7 @@ public class FetchActivityOperation extends AbstractMiBand2Operation {
|
|||
builder.notify(characteristicFetch, true);
|
||||
BluetoothGattCharacteristic characteristicActivityData = getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_5_ACTIVITY_DATA);
|
||||
|
||||
GregorianCalendar sinceWhen = getLastSuccessfulSynchronizedTime();
|
||||
GregorianCalendar sinceWhen = getLastSuccessfulSyncTime();
|
||||
builder.write(characteristicFetch, BLETypeConversions.join(new byte[] { MiBand2Service.COMMAND_ACTIVITY_DATA_START_DATE, 0x01 }, getSupport().getTimeBytes(sinceWhen, TimeUnit.MINUTES)));
|
||||
builder.add(new WaitAction(1000)); // TODO: actually wait for the success-reply
|
||||
builder.notify(characteristicActivityData, true);
|
||||
|
@ -81,26 +82,28 @@ public class FetchActivityOperation extends AbstractMiBand2Operation {
|
|||
builder.queue(getQueue());
|
||||
}
|
||||
|
||||
private GregorianCalendar getLastSuccessfulSynchronizedTime() {
|
||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||
DaoSession session = dbHandler.getDaoSession();
|
||||
SampleProvider<MiBandActivitySample> sampleProvider = new MiBand2SampleProvider(getDevice(), session);
|
||||
MiBandActivitySample sample = sampleProvider.getLatestActivitySample();
|
||||
if (sample != null) {
|
||||
int timestamp = sample.getTimestamp();
|
||||
GregorianCalendar calendar = BLETypeConversions.createCalendar();
|
||||
calendar.setTimeInMillis((long) timestamp * 1000);
|
||||
return calendar;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Error querying for latest activity sample, synchronizing the last 10 days", ex);
|
||||
private GregorianCalendar getLastSuccessfulSyncTime() {
|
||||
long timeStampMillis = GBApplication.getPrefs().getLong(getLastSyncTimeKey(), 0);
|
||||
if (timeStampMillis != 0) {
|
||||
GregorianCalendar calendar = BLETypeConversions.createCalendar();
|
||||
calendar.setTimeInMillis(timeStampMillis);
|
||||
return calendar;
|
||||
}
|
||||
|
||||
GregorianCalendar calendar = BLETypeConversions.createCalendar();
|
||||
calendar.add(Calendar.DAY_OF_MONTH, -10);
|
||||
return calendar;
|
||||
}
|
||||
|
||||
private void saveLastSyncTimestamp(@NonNull GregorianCalendar timestamp) {
|
||||
SharedPreferences.Editor editor = GBApplication.getPrefs().getPreferences().edit();
|
||||
editor.putLong(getLastSyncTimeKey(), timestamp.getTimeInMillis());
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
private String getLastSyncTimeKey() {
|
||||
return getDevice().getAddress() + "_" + "lastSyncTimeMillis";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCharacteristicChanged(BluetoothGatt gatt,
|
||||
BluetoothGattCharacteristic characteristic) {
|
||||
|
@ -147,6 +150,7 @@ public class FetchActivityOperation extends AbstractMiBand2Operation {
|
|||
}
|
||||
sampleProvider.addGBActivitySamples(samples.toArray(new MiBandActivitySample[0]));
|
||||
|
||||
saveLastSyncTimestamp(timestamp);
|
||||
LOG.info("Mi2 activity data: last sample timestamp: " + DateTimeUtils.formatDateTime(timestamp.getTime()));
|
||||
|
||||
} catch (Exception ex) {
|
||||
|
|
|
@ -7,11 +7,13 @@ import java.util.ArrayList;
|
|||
import java.util.UUID;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
|
||||
public class AppMessageHandler {
|
||||
protected final PebbleProtocol mPebbleProtocol;
|
||||
protected final UUID mUUID;
|
||||
class AppMessageHandler {
|
||||
final PebbleProtocol mPebbleProtocol;
|
||||
final UUID mUUID;
|
||||
|
||||
AppMessageHandler(UUID uuid, PebbleProtocol pebbleProtocol) {
|
||||
mUUID = uuid;
|
||||
|
@ -27,10 +29,17 @@ public class AppMessageHandler {
|
|||
}
|
||||
|
||||
public GBDeviceEvent[] handleMessage(ArrayList<Pair<Integer, Object>> pairs) {
|
||||
// Just ACK
|
||||
GBDeviceEventSendBytes sendBytesAck = new GBDeviceEventSendBytes();
|
||||
sendBytesAck.encodedBytes = mPebbleProtocol.encodeApplicationMessageAck(mUUID, mPebbleProtocol.last_id);
|
||||
return new GBDeviceEvent[]{sendBytesAck};
|
||||
}
|
||||
|
||||
public GBDeviceEvent[] onAppStart() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public GBDeviceEvent[] pushMessage() {
|
||||
public byte[] encodeUpdateWeather(WeatherSpec weatherSpec) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble;
|
||||
|
||||
import android.util.Pair;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
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;
|
||||
|
||||
class AppMessageHandlerHealthify extends AppMessageHandler {
|
||||
private static final int KEY_TEMPERATURE = 10021;
|
||||
private static final int KEY_CONDITIONS = 10022;
|
||||
|
||||
AppMessageHandlerHealthify(UUID uuid, PebbleProtocol pebbleProtocol) {
|
||||
super(uuid, pebbleProtocol);
|
||||
}
|
||||
|
||||
private byte[] encodeMarioWeatherMessage(WeatherSpec weatherSpec) {
|
||||
if (weatherSpec == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayList<Pair<Integer, Object>> pairs = new ArrayList<>(2);
|
||||
pairs.add(new Pair<>(KEY_CONDITIONS, (Object) weatherSpec.currentCondition));
|
||||
pairs.add(new Pair<>(KEY_TEMPERATURE, (Object) (weatherSpec.currentTemp - 273)));
|
||||
byte[] weatherMessage = mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs);
|
||||
|
||||
ByteBuffer buf = ByteBuffer.allocate(weatherMessage.length);
|
||||
|
||||
buf.put(weatherMessage);
|
||||
|
||||
return buf.array();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GBDeviceEvent[] onAppStart() {
|
||||
WeatherSpec weatherSpec = Weather.getInstance().getWeatherSpec();
|
||||
if (weatherSpec == null) {
|
||||
return new GBDeviceEvent[]{null};
|
||||
}
|
||||
GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes();
|
||||
sendBytes.encodedBytes = encodeMarioWeatherMessage(weatherSpec);
|
||||
return new GBDeviceEvent[]{sendBytes};
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encodeUpdateWeather(WeatherSpec weatherSpec) {
|
||||
return encodeMarioWeatherMessage(weatherSpec);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble;
|
||||
|
||||
import android.util.Pair;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
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;
|
||||
|
||||
class AppMessageHandlerMarioTime extends AppMessageHandler {
|
||||
|
||||
private static final int KEY_WEATHER_ICON_ID = 10;
|
||||
private static final int KEY_WEATHER_TEMPERATURE = 11;
|
||||
|
||||
AppMessageHandlerMarioTime(UUID uuid, PebbleProtocol pebbleProtocol) {
|
||||
super(uuid, pebbleProtocol);
|
||||
}
|
||||
|
||||
private byte[] encodeMarioWeatherMessage(WeatherSpec weatherSpec) {
|
||||
if (weatherSpec == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayList<Pair<Integer, Object>> pairs = new ArrayList<>(2);
|
||||
pairs.add(new Pair<>(KEY_WEATHER_ICON_ID, (Object) (byte) 1));
|
||||
pairs.add(new Pair<>(KEY_WEATHER_TEMPERATURE, (Object) (byte) (weatherSpec.currentTemp - 273)));
|
||||
byte[] weatherMessage = mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs);
|
||||
|
||||
ByteBuffer buf = ByteBuffer.allocate(weatherMessage.length);
|
||||
|
||||
buf.put(weatherMessage);
|
||||
|
||||
return buf.array();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GBDeviceEvent[] onAppStart() {
|
||||
WeatherSpec weatherSpec = Weather.getInstance().getWeatherSpec();
|
||||
if (weatherSpec == null) {
|
||||
return new GBDeviceEvent[]{null};
|
||||
}
|
||||
GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes();
|
||||
sendBytes.encodedBytes = encodeMarioWeatherMessage(weatherSpec);
|
||||
return new GBDeviceEvent[]{sendBytes};
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encodeUpdateWeather(WeatherSpec weatherSpec) {
|
||||
return encodeMarioWeatherMessage(weatherSpec);
|
||||
}
|
||||
}
|
|
@ -22,21 +22,21 @@ import nodomain.freeyourgadget.gadgetbridge.entities.PebbleMisfitSample;
|
|||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||
|
||||
public class AppMessageHandlerMisfit extends AppMessageHandler {
|
||||
class AppMessageHandlerMisfit extends AppMessageHandler {
|
||||
|
||||
public static final int KEY_SLEEPGOAL = 1;
|
||||
public static final int KEY_STEP_ROGRESS = 2;
|
||||
public static final int KEY_SLEEP_PROGRESS = 3;
|
||||
public static final int KEY_VERSION = 4;
|
||||
public static final int KEY_SYNC = 5;
|
||||
public static final int KEY_INCOMING_DATA_BEGIN = 6;
|
||||
public static final int KEY_INCOMING_DATA = 7;
|
||||
public static final int KEY_INCOMING_DATA_END = 8;
|
||||
public static final int KEY_SYNC_RESULT = 9;
|
||||
private static final int KEY_SLEEPGOAL = 1;
|
||||
private static final int KEY_STEP_ROGRESS = 2;
|
||||
private static final int KEY_SLEEP_PROGRESS = 3;
|
||||
private static final int KEY_VERSION = 4;
|
||||
private static final int KEY_SYNC = 5;
|
||||
private static final int KEY_INCOMING_DATA_BEGIN = 6;
|
||||
private static final int KEY_INCOMING_DATA = 7;
|
||||
private static final int KEY_INCOMING_DATA_END = 8;
|
||||
private static final int KEY_SYNC_RESULT = 9;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AppMessageHandlerMisfit.class);
|
||||
|
||||
public AppMessageHandlerMisfit(UUID uuid, PebbleProtocol pebbleProtocol) {
|
||||
AppMessageHandlerMisfit(UUID uuid, PebbleProtocol pebbleProtocol) {
|
||||
super(uuid, pebbleProtocol);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,37 +20,37 @@ import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleMorpheuzSampleP
|
|||
import nodomain.freeyourgadget.gadgetbridge.entities.PebbleMorpheuzSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||
|
||||
public class AppMessageHandlerMorpheuz extends AppMessageHandler {
|
||||
class AppMessageHandlerMorpheuz extends AppMessageHandler {
|
||||
|
||||
public static final int KEY_POINT = 1;
|
||||
public static final int KEY_POINT_46 = 10000;
|
||||
public static final int KEY_CTRL = 2;
|
||||
public static final int KEY_CTRL_46 = 10001;
|
||||
public static final int KEY_FROM = 3;
|
||||
public static final int KEY_FROM_46 = 10002;
|
||||
public static final int KEY_TO = 4;
|
||||
public static final int KEY_TO_46 = 10003;
|
||||
public static final int KEY_BASE = 5;
|
||||
public static final int KEY_BASE_46 = 10004;
|
||||
public static final int KEY_VERSION = 6;
|
||||
public static final int KEY_VERSION_46 = 10005;
|
||||
public static final int KEY_GONEOFF = 7;
|
||||
public static final int KEY_GONEOFF_46 = 10006;
|
||||
public static final int KEY_TRANSMIT = 8;
|
||||
public static final int KEY_TRANSMIT_46 = 10007;
|
||||
public static final int KEY_AUTO_RESET = 9;
|
||||
public static final int KEY_AUTO_RESET_46 = 10008;
|
||||
public static final int KEY_SNOOZES = 10;
|
||||
public static final int KEY_SNOOZES_46 = 10009;
|
||||
public static final int KEY_FAULT_46 = 10010;
|
||||
private static final int KEY_POINT = 1;
|
||||
private static final int KEY_POINT_46 = 10000;
|
||||
private static final int KEY_CTRL = 2;
|
||||
private static final int KEY_CTRL_46 = 10001;
|
||||
private static final int KEY_FROM = 3;
|
||||
private static final int KEY_FROM_46 = 10002;
|
||||
private static final int KEY_TO = 4;
|
||||
private static final int KEY_TO_46 = 10003;
|
||||
private static final int KEY_BASE = 5;
|
||||
private static final int KEY_BASE_46 = 10004;
|
||||
private static final int KEY_VERSION = 6;
|
||||
private static final int KEY_VERSION_46 = 10005;
|
||||
private static final int KEY_GONEOFF = 7;
|
||||
private static final int KEY_GONEOFF_46 = 10006;
|
||||
private static final int KEY_TRANSMIT = 8;
|
||||
private static final int KEY_TRANSMIT_46 = 10007;
|
||||
private static final int KEY_AUTO_RESET = 9;
|
||||
private static final int KEY_AUTO_RESET_46 = 10008;
|
||||
private static final int KEY_SNOOZES = 10;
|
||||
private static final int KEY_SNOOZES_46 = 10009;
|
||||
private static final int KEY_FAULT_46 = 10010;
|
||||
|
||||
public static final int CTRL_TRANSMIT_DONE = 1;
|
||||
public static final int CTRL_VERSION_DONE = 2;
|
||||
public static final int CTRL_GONEOFF_DONE = 4;
|
||||
public static final int CTRL_DO_NEXT = 8;
|
||||
public static final int CTRL_SET_LAST_SENT = 16;
|
||||
public static final int CTRL_LAZARUS = 32;
|
||||
public static final int CTRL_SNOOZES_DONE = 64;
|
||||
private static final int CTRL_TRANSMIT_DONE = 1;
|
||||
private static final int CTRL_VERSION_DONE = 2;
|
||||
private static final int CTRL_GONEOFF_DONE = 4;
|
||||
private static final int CTRL_DO_NEXT = 8;
|
||||
private static final int CTRL_SET_LAST_SENT = 16;
|
||||
private static final int CTRL_LAZARUS = 32;
|
||||
private static final int CTRL_SNOOZES_DONE = 64;
|
||||
|
||||
// data received from Morpheuz in native format
|
||||
private int version = 0;
|
||||
|
|
|
@ -11,8 +11,10 @@ import java.util.UUID;
|
|||
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleColor;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
|
||||
import ru.gelin.android.weather.notification.ParcelableWeather2;
|
||||
|
||||
public class AppMessageHandlerPebStyle extends AppMessageHandler {
|
||||
class AppMessageHandlerPebStyle extends AppMessageHandler {
|
||||
public static final int KEY_AMPM_TEXT = 21;
|
||||
public static final int KEY_BLUETOOTH_ALERT = 2;
|
||||
public static final int KEY_BLUETOOTH_ICON = 20;
|
||||
|
@ -64,7 +66,7 @@ public class AppMessageHandlerPebStyle extends AppMessageHandler {
|
|||
pairs.add(new Pair<>(KEY_SIDEBAR_BG_COLOR, (Object) PebbleColor.MediumSpringGreen));
|
||||
|
||||
//DIGITAL settings
|
||||
/*
|
||||
/*
|
||||
pairs.add(new Pair<>(KEY_MAIN_CLOCK, (Object) 1)); //0 analog
|
||||
pairs.add(new Pair<>(KEY_SECONDARY_INFO_TYPE, (Object) 3)); //1 time, 2 location
|
||||
*/
|
||||
|
@ -74,12 +76,13 @@ public class AppMessageHandlerPebStyle extends AppMessageHandler {
|
|||
|
||||
|
||||
//WEATHER
|
||||
/*
|
||||
//comment the same key in the general section above!
|
||||
pairs.add(new Pair<>(KEY_LOCATION_SERVICE, (Object) 0)); //0 auto, 1 manual
|
||||
pairs.add(new Pair<>(KEY_WEATHER_CODE, (Object) 3));
|
||||
pairs.add(new Pair<>(KEY_WEATHER_TEMP, (Object) 10));
|
||||
*/
|
||||
ParcelableWeather2 weather = Weather.getInstance().getWeather2();
|
||||
if (weather != null) {
|
||||
//comment the same key in the general section above!
|
||||
pairs.add(new Pair<>(KEY_LOCATION_SERVICE, (Object) 0)); //0 auto, 1 manual
|
||||
pairs.add(new Pair<>(KEY_WEATHER_CODE, (Object) Weather.mapToYahooCondition(weather.currentConditionCode)));
|
||||
pairs.add(new Pair<>(KEY_WEATHER_TEMP, (Object) (weather.currentTemp - 273)));
|
||||
}
|
||||
|
||||
byte[] testMessage = mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs);
|
||||
|
||||
|
@ -107,7 +110,7 @@ public class AppMessageHandlerPebStyle extends AppMessageHandler {
|
|||
}
|
||||
|
||||
@Override
|
||||
public GBDeviceEvent[] pushMessage() {
|
||||
public GBDeviceEvent[] onAppStart() {
|
||||
return null;
|
||||
/*
|
||||
GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes();
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble;
|
||||
|
||||
import android.util.Pair;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
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;
|
||||
|
||||
class AppMessageHandlerSquare extends AppMessageHandler {
|
||||
// "CfgKeyCelsiusTemperature":10001,
|
||||
// CfgKeyConditions":10002,
|
||||
//"CfgKeyWeatherError":10003,
|
||||
// "CfgKeyWeatherMode":10004,
|
||||
// "CfgKeyUseCelsius":10005,"
|
||||
// CfgKeyWeatherLocation":10006,"
|
||||
// "CfgKeyTemperature":10000,
|
||||
//
|
||||
//
|
||||
private static final int KEY_TEMP = 10001; //celsius
|
||||
private static final int KEY_WEATHER = 10002;
|
||||
private static final int KEY_WEATHER_MODE = 10004;
|
||||
private static final int KEY_USE_CELSIUS = 10005; //celsius
|
||||
private static final int KEY_LOCATION = 10006;
|
||||
private static final int KEY_TEMP_F = 10000; //fahrenheit
|
||||
|
||||
AppMessageHandlerSquare(UUID uuid, PebbleProtocol pebbleProtocol) {
|
||||
super(uuid, pebbleProtocol);
|
||||
}
|
||||
|
||||
private byte[] encodeSquareWeatherMessage(WeatherSpec weatherSpec) {
|
||||
if (weatherSpec == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayList<Pair<Integer, Object>> pairs = new ArrayList<>(2);
|
||||
pairs.add(new Pair<>(KEY_WEATHER_MODE, (Object) 1));
|
||||
pairs.add(new Pair<>(KEY_WEATHER, (Object) weatherSpec.currentCondition));
|
||||
pairs.add(new Pair<>(KEY_USE_CELSIUS, (Object) 1));
|
||||
pairs.add(new Pair<>(KEY_TEMP, (Object) (weatherSpec.currentTemp - 273)));
|
||||
pairs.add(new Pair<>(KEY_LOCATION, (Object) (weatherSpec.location)));
|
||||
byte[] weatherMessage = mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs);
|
||||
|
||||
ByteBuffer buf = ByteBuffer.allocate(weatherMessage.length);
|
||||
|
||||
buf.put(weatherMessage);
|
||||
|
||||
return buf.array();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GBDeviceEvent[] onAppStart() {
|
||||
WeatherSpec weatherSpec = Weather.getInstance().getWeatherSpec();
|
||||
if (weatherSpec == null) {
|
||||
return new GBDeviceEvent[]{null};
|
||||
}
|
||||
GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes();
|
||||
sendBytes.encodedBytes = encodeSquareWeatherMessage(weatherSpec);
|
||||
return new GBDeviceEvent[]{sendBytes};
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encodeUpdateWeather(WeatherSpec weatherSpec) {
|
||||
return encodeSquareWeatherMessage(weatherSpec);
|
||||
}
|
||||
}
|
|
@ -1,109 +1,127 @@
|
|||
package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.util.Pair;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
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;
|
||||
|
||||
public class AppMessageHandlerTimeStylePebble extends AppMessageHandler {
|
||||
public static final int KEY_SETTING_SIDEBAR_LEFT = 9;
|
||||
public static final int KEY_CONDITION_CODE = 4;
|
||||
public static final int KEY_FORECAST_CONDITION = 25;
|
||||
public static final int KEY_FORECAST_TEMP_HIGH = 26;
|
||||
public static final int KEY_FORECAST_TEMP_LOW = 27;
|
||||
public static final int KEY_SETTING_ALTCLOCK_NAME = 28;
|
||||
public static final int KEY_SETTING_ALTCLOCK_OFFSET = 29;
|
||||
public static final int KEY_SETTING_BT_VIBE = 11;
|
||||
public static final int KEY_SETTING_CLOCK_FONT_ID = 18;
|
||||
public static final int KEY_SETTING_COLOR_BG = 7;
|
||||
public static final int KEY_SETTING_COLOR_SIDEBAR = 8;
|
||||
public static final int KEY_SETTING_COLOR_TIME = 6;
|
||||
public static final int KEY_SETTING_DISABLE_WEATHER = 17;
|
||||
public static final int KEY_SETTING_HOURLY_VIBE = 19;
|
||||
public static final int KEY_SETTING_LANGUAGE_ID = 13;
|
||||
public static final int KEY_SETTING_ONLY_SHOW_BATTERY_WHEN_LOW = 20;
|
||||
public static final int KEY_SETTING_SHOW_BATTERY_PCT = 16;
|
||||
public static final int KEY_SETTING_SHOW_LEADING_ZERO = 15;
|
||||
public static final int KEY_SETTING_SIDEBAR_TEXT_COLOR = 12;
|
||||
public static final int KEY_SETTING_USE_LARGE_FONTS = 21;
|
||||
public static final int KEY_SETTING_USE_METRIC = 10;
|
||||
public static final int KEY_TEMPERATURE = 3;
|
||||
public static final int KEY_USE_NIGHT_ICON = 5;
|
||||
public static final int KEY_WIDGET_0_ID = 22;
|
||||
public static final int KEY_WIDGET_1_ID = 23;
|
||||
public static final int KEY_WIDGET_2_ID = 24;
|
||||
class AppMessageHandlerTimeStylePebble extends AppMessageHandler {
|
||||
private static final int MESSAGE_KEY_WeatherCondition = 10000;
|
||||
private static final int MESSAGE_KEY_WeatherForecastCondition = 10002;
|
||||
private static final int MESSAGE_KEY_WeatherForecastHighTemp = 10003;
|
||||
private static final int MESSAGE_KEY_WeatherForecastLowTemp = 10004;
|
||||
private static final int MESSAGE_KEY_WeatherTemperature = 10001;
|
||||
private static final int MESSAGE_KEY_WeatherUseNightIcon = 10025;
|
||||
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AppMessageHandlerTimeStylePebble.class);
|
||||
private static final int ICON_CLEAR_DAY = 0;
|
||||
private static final int ICON_CLEAR_NIGHT = 1;
|
||||
private static final int ICON_CLOUDY_DAY = 2;
|
||||
private static final int ICON_HEAVY_RAIN = 3;
|
||||
private static final int ICON_HEAVY_SNOW = 4;
|
||||
private static final int ICON_LIGHT_RAIN = 5;
|
||||
private static final int ICON_LIGHT_SNOW = 6;
|
||||
private static final int ICON_PARTLY_CLOUDY_NIGHT = 7;
|
||||
private static final int ICON_PARTLY_CLOUDY = 8;
|
||||
private static final int ICON_RAINING_AND_SNOWING = 9;
|
||||
private static final int ICON_THUNDERSTORM = 10;
|
||||
private static final int ICON_WEATHER_GENERIC = 11;
|
||||
|
||||
public AppMessageHandlerTimeStylePebble(UUID uuid, PebbleProtocol pebbleProtocol) {
|
||||
AppMessageHandlerTimeStylePebble(UUID uuid, PebbleProtocol pebbleProtocol) {
|
||||
super(uuid, pebbleProtocol);
|
||||
}
|
||||
|
||||
private byte[] encodeTimeStylePebbleConfig() {
|
||||
ArrayList<Pair<Integer, Object>> pairs = new ArrayList<>();
|
||||
//settings that give good legibility on pebble time
|
||||
pairs.add(new Pair<>(KEY_SETTING_SIDEBAR_LEFT, (Object) 1));
|
||||
pairs.add(new Pair<>(KEY_SETTING_CLOCK_FONT_ID, (Object) 1));
|
||||
pairs.add(new Pair<>(KEY_SETTING_COLOR_BG, (Object) Color.parseColor("#ffffff")));
|
||||
pairs.add(new Pair<>(KEY_SETTING_COLOR_SIDEBAR, (Object) Color.parseColor("#00aaff")));
|
||||
pairs.add(new Pair<>(KEY_SETTING_COLOR_TIME, (Object) Color.parseColor("#000000")));
|
||||
pairs.add(new Pair<>(KEY_SETTING_SHOW_LEADING_ZERO, (Object) 1));
|
||||
pairs.add(new Pair<>(KEY_SETTING_LANGUAGE_ID, (Object) 2)); //2 = Deutsch
|
||||
pairs.add(new Pair<>(KEY_SETTING_USE_METRIC, (Object) 1));
|
||||
/*
|
||||
* converted to JAVA from original JS
|
||||
*/
|
||||
private int getIconForConditionCode(int conditionCode, boolean isNight) {
|
||||
int generalCondition = conditionCode / 100;
|
||||
int iconToLoad;
|
||||
// determine the correct icon
|
||||
switch (generalCondition) {
|
||||
case 2: //thunderstorm
|
||||
iconToLoad = ICON_THUNDERSTORM;
|
||||
break;
|
||||
case 3: //drizzle
|
||||
iconToLoad = ICON_LIGHT_RAIN;
|
||||
break;
|
||||
case 5: //rain
|
||||
if (conditionCode == 500) {
|
||||
iconToLoad = ICON_LIGHT_RAIN;
|
||||
} else if (conditionCode < 505) {
|
||||
iconToLoad = ICON_HEAVY_RAIN;
|
||||
} else if (conditionCode == 511) {
|
||||
iconToLoad = ICON_RAINING_AND_SNOWING;
|
||||
} else {
|
||||
iconToLoad = ICON_LIGHT_RAIN;
|
||||
}
|
||||
break;
|
||||
case 6: //snow
|
||||
if (conditionCode == 600 || conditionCode == 620) {
|
||||
iconToLoad = ICON_LIGHT_SNOW;
|
||||
} else if (conditionCode > 610 && conditionCode < 620) {
|
||||
iconToLoad = ICON_RAINING_AND_SNOWING;
|
||||
} else {
|
||||
iconToLoad = ICON_HEAVY_SNOW;
|
||||
}
|
||||
break;
|
||||
case 7: // fog, dust, etc
|
||||
iconToLoad = ICON_CLOUDY_DAY;
|
||||
break;
|
||||
case 8: // clouds
|
||||
if (conditionCode == 800) {
|
||||
iconToLoad = (!isNight) ? ICON_CLEAR_DAY : ICON_CLEAR_NIGHT;
|
||||
} else if (conditionCode < 803) {
|
||||
iconToLoad = (!isNight) ? ICON_PARTLY_CLOUDY : ICON_PARTLY_CLOUDY_NIGHT;
|
||||
} else {
|
||||
iconToLoad = ICON_CLOUDY_DAY;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
iconToLoad = ICON_WEATHER_GENERIC;
|
||||
break;
|
||||
}
|
||||
|
||||
pairs.add(new Pair<>(KEY_WIDGET_0_ID, (Object) 7)); //7 = current weather
|
||||
pairs.add(new Pair<>(KEY_WIDGET_1_ID, (Object) 2)); //2 = battery
|
||||
pairs.add(new Pair<>(KEY_WIDGET_2_ID, (Object) 4)); //4 = Date
|
||||
|
||||
/*
|
||||
pairs.add(new Pair<>(KEY_TEMPERATURE, (Object) 6));
|
||||
pairs.add(new Pair<>(KEY_CONDITION_CODE, (Object) 25));
|
||||
pairs.add(new Pair<>(KEY_FORECAST_CONDITION, (Object) 2));
|
||||
pairs.add(new Pair<>(KEY_FORECAST_TEMP_HIGH, (Object) 12));
|
||||
pairs.add(new Pair<>(KEY_FORECAST_TEMP_LOW, (Object) 0));
|
||||
*/
|
||||
|
||||
byte[] ackMessage = mPebbleProtocol.encodeApplicationMessageAck(mUUID, mPebbleProtocol.last_id);
|
||||
byte[] testMessage = mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs);
|
||||
|
||||
//byte[] weatherMessage=encodeTimeStylePebbleWeather();
|
||||
|
||||
ByteBuffer buf = ByteBuffer.allocate(ackMessage.length + testMessage.length);
|
||||
|
||||
// encode ack and put in front of push message (hack for acknowledging the last message)
|
||||
buf.put(ackMessage);
|
||||
buf.put(testMessage);
|
||||
|
||||
return buf.array();
|
||||
return iconToLoad;
|
||||
}
|
||||
|
||||
private byte[] encodeTimeStylePebbleWeather() {
|
||||
ArrayList<Pair<Integer, Object>> pairs = new ArrayList<>();
|
||||
pairs.add(new Pair<>(KEY_TEMPERATURE, (Object) 6));
|
||||
pairs.add(new Pair<>(KEY_CONDITION_CODE, (Object) 1));
|
||||
pairs.add(new Pair<>(KEY_FORECAST_CONDITION, (Object) 2));
|
||||
pairs.add(new Pair<>(KEY_FORECAST_TEMP_HIGH, (Object) 12));
|
||||
pairs.add(new Pair<>(KEY_FORECAST_TEMP_LOW, (Object) 0));
|
||||
private byte[] encodeTimeStylePebbleWeather(WeatherSpec weatherSpec) {
|
||||
|
||||
byte[] weatherMessage = mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs);
|
||||
return weatherMessage;
|
||||
if (weatherSpec == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayList<Pair<Integer, Object>> pairs = new ArrayList<>();
|
||||
boolean isNight = false; //TODO: use the night icons when night
|
||||
pairs.add(new Pair<>(MESSAGE_KEY_WeatherUseNightIcon, (Object) (isNight ? 1 : 0)));
|
||||
pairs.add(new Pair<>(MESSAGE_KEY_WeatherTemperature, (Object) (weatherSpec.currentTemp - 273)));
|
||||
pairs.add(new Pair<>(MESSAGE_KEY_WeatherCondition, (Object) (getIconForConditionCode(weatherSpec.currentConditionCode, isNight))));
|
||||
pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastCondition, (Object) (getIconForConditionCode(weatherSpec.tomorrowConditionCode, isNight))));
|
||||
pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastHighTemp, (Object) (weatherSpec.todayMaxTemp - 273)));
|
||||
|
||||
pairs.add(new Pair<>(MESSAGE_KEY_WeatherForecastLowTemp, (Object) (weatherSpec.todayMinTemp - 273)));
|
||||
|
||||
return mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GBDeviceEvent[] handleMessage(ArrayList<Pair<Integer, Object>> pairs) {
|
||||
return null;
|
||||
/*
|
||||
public GBDeviceEvent[] onAppStart() {
|
||||
WeatherSpec weatherSpec = Weather.getInstance().getWeatherSpec();
|
||||
if (weatherSpec == null) {
|
||||
return new GBDeviceEvent[]{null};
|
||||
}
|
||||
GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes();
|
||||
sendBytes.encodedBytes = encodeTimeStylePebbleConfig();
|
||||
sendBytes.encodedBytes = encodeTimeStylePebbleWeather(weatherSpec);
|
||||
return new GBDeviceEvent[]{sendBytes};
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encodeUpdateWeather(WeatherSpec weatherSpec) {
|
||||
return encodeTimeStylePebbleWeather(weatherSpec);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble;
|
||||
|
||||
import android.util.Pair;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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;
|
||||
|
||||
class AppMessageHandlerTrekVolle extends AppMessageHandler {
|
||||
private static final int MESSAGE_KEY_WEATHER_TEMPERATURE = 10000;
|
||||
private static final int MESSAGE_KEY_WEATHER_CONDITIONS = 10001;
|
||||
private static final int MESSAGE_KEY_WEATHER_ICON = 10002;
|
||||
private static final int MESSAGE_KEY_WEATHER_TEMPERATURE_MIN = 10024;
|
||||
private static final int MESSAGE_KEY_WEATHER_TEMPERATURE_MAX = 10025;
|
||||
private static final int MESSAGE_KEY_WEATHER_LOCATION = 10030;
|
||||
|
||||
AppMessageHandlerTrekVolle(UUID uuid, PebbleProtocol pebbleProtocol) {
|
||||
super(uuid, pebbleProtocol);
|
||||
}
|
||||
|
||||
private int getIconForConditionCode(int conditionCode, boolean isNight) {
|
||||
/*
|
||||
case 1: return RESOURCE_ID_IMAGE_WEATHER_CLEARNIGHT;
|
||||
case 2: return RESOURCE_ID_IMAGE_WEATHER_CLEAR;
|
||||
case 3: return RESOURCE_ID_IMAGE_WEATHER_CLOUDYNIGHT;
|
||||
case 4: return RESOURCE_ID_IMAGE_WEATHER_CLOUDY;
|
||||
case 5: return RESOURCE_ID_IMAGE_WEATHER_CLOUDS;
|
||||
case 6: return RESOURCE_ID_IMAGE_WEATHER_THICKCLOUDS;
|
||||
case 7: return RESOURCE_ID_IMAGE_WEATHER_RAIN;
|
||||
case 8: return RESOURCE_ID_IMAGE_WEATHER_RAINYNIGHT;
|
||||
case 9: return RESOURCE_ID_IMAGE_WEATHER_RAINY;
|
||||
case 10: return RESOURCE_ID_IMAGE_WEATHER_LIGHTNING;
|
||||
case 11: return RESOURCE_ID_IMAGE_WEATHER_SNOW;
|
||||
case 12: return RESOURCE_ID_IMAGE_WEATHER_MIST;
|
||||
*/
|
||||
return 2;
|
||||
}
|
||||
|
||||
private byte[] encodeTrekVolleWeather(WeatherSpec weatherSpec) {
|
||||
|
||||
if (weatherSpec == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean isNight = false; // FIXME
|
||||
ArrayList<Pair<Integer, Object>> pairs = new ArrayList<>();
|
||||
pairs.add(new Pair<>(MESSAGE_KEY_WEATHER_TEMPERATURE, (Object) (weatherSpec.currentTemp - 273)));
|
||||
pairs.add(new Pair<>(MESSAGE_KEY_WEATHER_CONDITIONS, (Object) (weatherSpec.currentCondition)));
|
||||
pairs.add(new Pair<>(MESSAGE_KEY_WEATHER_ICON, (Object) (getIconForConditionCode(weatherSpec.currentConditionCode, isNight))));
|
||||
pairs.add(new Pair<>(MESSAGE_KEY_WEATHER_TEMPERATURE_MAX, (Object) (weatherSpec.todayMaxTemp - 273)));
|
||||
pairs.add(new Pair<>(MESSAGE_KEY_WEATHER_TEMPERATURE_MIN, (Object) (weatherSpec.todayMinTemp - 273)));
|
||||
pairs.add(new Pair<>(MESSAGE_KEY_WEATHER_LOCATION, (Object) weatherSpec.location));
|
||||
|
||||
|
||||
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 = encodeTrekVolleWeather(weatherSpec);
|
||||
return new GBDeviceEvent[]{sendBytes};
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encodeUpdateWeather(WeatherSpec weatherSpec) {
|
||||
return encodeTrekVolleWeather(weatherSpec);
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble;
|
||||
|
||||
import android.util.Pair;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.UUID;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes;
|
||||
|
||||
public class AppMessageHandlerWeatherNeat extends AppMessageHandler {
|
||||
|
||||
public static final int KEY_REQUEST = 0;
|
||||
public static final int KEY_CITY = 1;
|
||||
public static final int KEY_TEMPERATUR = 2;
|
||||
public static final int KEY_CONDITION = 3;
|
||||
public static final int KEY_LIGHT_TIME = 5;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AppMessageHandlerWeatherNeat.class);
|
||||
|
||||
public AppMessageHandlerWeatherNeat(UUID uuid, PebbleProtocol pebbleProtocol) {
|
||||
super(uuid, pebbleProtocol);
|
||||
}
|
||||
|
||||
private byte[] encodeWeatherNeatMessage(String city, String temperature, String condition, int light_time) {
|
||||
ArrayList<Pair<Integer, Object>> pairs = new ArrayList<>(4);
|
||||
pairs.add(new Pair<>(1, (Object) city));
|
||||
pairs.add(new Pair<>(2, (Object) temperature));
|
||||
pairs.add(new Pair<>(3, (Object) condition));
|
||||
pairs.add(new Pair<>(5, (Object) light_time)); // seconds for backlight on shake
|
||||
|
||||
byte[] ackMessage = mPebbleProtocol.encodeApplicationMessageAck(mUUID, mPebbleProtocol.last_id);
|
||||
byte[] testMessage = mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs);
|
||||
|
||||
ByteBuffer buf = ByteBuffer.allocate(ackMessage.length + testMessage.length);
|
||||
|
||||
// encode ack and put in front of push message (hack for acknowledging the last message)
|
||||
buf.put(ackMessage);
|
||||
buf.put(testMessage);
|
||||
|
||||
return buf.array();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GBDeviceEvent[] handleMessage(ArrayList<Pair<Integer, Object>> pairs) {
|
||||
GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes();
|
||||
sendBytes.encodedBytes = encodeWeatherNeatMessage("Berlin", "22 C", "cloudy", 0);
|
||||
return new GBDeviceEvent[]{sendBytes};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble;
|
||||
|
||||
import android.util.Pair;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
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;
|
||||
|
||||
class AppMessageHandlerZalewszczak extends AppMessageHandler {
|
||||
private static final int KEY_ICON = 0;
|
||||
private static final int KEY_TEMP = 1; //celsius
|
||||
|
||||
AppMessageHandlerZalewszczak(UUID uuid, PebbleProtocol pebbleProtocol) {
|
||||
super(uuid, pebbleProtocol);
|
||||
}
|
||||
|
||||
/*
|
||||
* converted to JAVA from original JS
|
||||
*/
|
||||
private int getIconForConditionCode(int conditionCode) {
|
||||
if (conditionCode < 300) {
|
||||
return 7;
|
||||
} else if (conditionCode < 400) {
|
||||
return 6;
|
||||
} else if (conditionCode == 511) {
|
||||
return 8;
|
||||
} else if (conditionCode < 600) {
|
||||
return 6;
|
||||
} else if (conditionCode < 700) {
|
||||
return 8;
|
||||
} else if (conditionCode < 800) {
|
||||
return 10;
|
||||
} else if (conditionCode == 800) {
|
||||
return 1;
|
||||
} else if (conditionCode == 801) {
|
||||
return 2;
|
||||
} else if (conditionCode < 900) {
|
||||
return 5;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private byte[] encodeWeatherMessage(WeatherSpec weatherSpec) {
|
||||
if (weatherSpec == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayList<Pair<Integer, Object>> pairs = new ArrayList<>(2);
|
||||
pairs.add(new Pair<>(KEY_TEMP, (Object) (Math.round(weatherSpec.currentTemp - 273) + "C")));
|
||||
pairs.add(new Pair<>(KEY_ICON, (Object) (getIconForConditionCode(weatherSpec.currentConditionCode))));
|
||||
byte[] weatherMessage = mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, mUUID, pairs);
|
||||
|
||||
ByteBuffer buf = ByteBuffer.allocate(weatherMessage.length);
|
||||
|
||||
buf.put(weatherMessage);
|
||||
|
||||
return buf.array();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GBDeviceEvent[] onAppStart() {
|
||||
WeatherSpec weatherSpec = Weather.getInstance().getWeatherSpec();
|
||||
if (weatherSpec == null) {
|
||||
return new GBDeviceEvent[]{null};
|
||||
}
|
||||
GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes();
|
||||
sendBytes.encodedBytes = encodeWeatherMessage(weatherSpec);
|
||||
return new GBDeviceEvent[]{sendBytes};
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encodeUpdateWeather(WeatherSpec weatherSpec) {
|
||||
return encodeWeatherMessage(weatherSpec);
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@ import nodomain.freeyourgadget.gadgetbridge.entities.PebbleHealthActivitySample;
|
|||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
public class DatalogSessionHealthSteps extends DatalogSessionPebbleHealth {
|
||||
class DatalogSessionHealthSteps extends DatalogSessionPebbleHealth {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DatalogSessionHealthSteps.class);
|
||||
|
||||
|
|
|
@ -613,6 +613,10 @@ class PebbleIoThread extends GBDeviceIoThread {
|
|||
write(mPebbleProtocol.encodeActivateHRM(true));
|
||||
return;
|
||||
}
|
||||
if (uri.equals(Uri.parse("fake://weather"))) {
|
||||
write(mPebbleProtocol.encodeActivateWeather(true));
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIsInstalling) {
|
||||
return;
|
||||
|
@ -623,7 +627,10 @@ class PebbleIoThread extends GBDeviceIoThread {
|
|||
try {
|
||||
mPBWReader = new PBWReader(uri, getContext(), platformName);
|
||||
} catch (FileNotFoundException e) {
|
||||
LOG.warn("file not found!");
|
||||
LOG.warn("file not found: " + e.getMessage(), e);
|
||||
return;
|
||||
} catch (IOException e) {
|
||||
LOG.warn("unable to read file: " + e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,144 +38,145 @@ import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
|||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol;
|
||||
|
||||
public class PebbleProtocol extends GBDeviceProtocol {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(PebbleProtocol.class);
|
||||
|
||||
static final short ENDPOINT_TIME = 11;
|
||||
static final short ENDPOINT_FIRMWAREVERSION = 16;
|
||||
public static final short ENDPOINT_PHONEVERSION = 17;
|
||||
static final short ENDPOINT_SYSTEMMESSAGE = 18;
|
||||
static final short ENDPOINT_MUSICCONTROL = 32;
|
||||
static final short ENDPOINT_PHONECONTROL = 33;
|
||||
private static final short ENDPOINT_TIME = 11;
|
||||
private static final short ENDPOINT_FIRMWAREVERSION = 16;
|
||||
private static final short ENDPOINT_PHONEVERSION = 17;
|
||||
private static final short ENDPOINT_SYSTEMMESSAGE = 18;
|
||||
private static final short ENDPOINT_MUSICCONTROL = 32;
|
||||
private static final short ENDPOINT_PHONECONTROL = 33;
|
||||
static final short ENDPOINT_APPLICATIONMESSAGE = 48;
|
||||
static final short ENDPOINT_LAUNCHER = 49;
|
||||
static final short ENDPOINT_APPRUNSTATE = 52; // 3.x only
|
||||
static final short ENDPOINT_LOGS = 2000;
|
||||
static final short ENDPOINT_PING = 2001;
|
||||
static final short ENDPOINT_LOGDUMP = 2002;
|
||||
static final short ENDPOINT_RESET = 2003;
|
||||
static final short ENDPOINT_APP = 2004;
|
||||
static final short ENDPOINT_APPLOGS = 2006;
|
||||
static final short ENDPOINT_NOTIFICATION = 3000;
|
||||
static final short ENDPOINT_EXTENSIBLENOTIFS = 3010;
|
||||
static final short ENDPOINT_RESOURCE = 4000;
|
||||
static final short ENDPOINT_SYSREG = 5000;
|
||||
static final short ENDPOINT_FCTREG = 5001;
|
||||
static final short ENDPOINT_APPMANAGER = 6000;
|
||||
static final short ENDPOINT_APPFETCH = 6001; // 3.x only
|
||||
public static final short ENDPOINT_DATALOG = 6778;
|
||||
static final short ENDPOINT_RUNKEEPER = 7000;
|
||||
static final short ENDPOINT_SCREENSHOT = 8000;
|
||||
static final short ENDPOINT_AUDIOSTREAM = 10000;
|
||||
static final short ENDPOINT_VOICECONTROL = 11000;
|
||||
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;
|
||||
private static final short ENDPOINT_LAUNCHER = 49;
|
||||
private static final short ENDPOINT_APPRUNSTATE = 52; // FW >=3.x
|
||||
private static final short ENDPOINT_LOGS = 2000;
|
||||
private static final short ENDPOINT_PING = 2001;
|
||||
private static final short ENDPOINT_LOGDUMP = 2002;
|
||||
private static final short ENDPOINT_RESET = 2003;
|
||||
private static final short ENDPOINT_APP = 2004;
|
||||
private static final short ENDPOINT_APPLOGS = 2006;
|
||||
private static final short ENDPOINT_NOTIFICATION = 3000; // FW 1.x-2-x
|
||||
private static final short ENDPOINT_EXTENSIBLENOTIFS = 3010; // FW 2.x
|
||||
private static final short ENDPOINT_RESOURCE = 4000;
|
||||
private static final short ENDPOINT_SYSREG = 5000;
|
||||
private static final short ENDPOINT_FCTREG = 5001;
|
||||
private static final short ENDPOINT_APPMANAGER = 6000;
|
||||
private static final short ENDPOINT_APPFETCH = 6001; // FW >=3.x
|
||||
private static final short ENDPOINT_DATALOG = 6778;
|
||||
private static final short ENDPOINT_RUNKEEPER = 7000;
|
||||
private static final short ENDPOINT_SCREENSHOT = 8000;
|
||||
private static final short ENDPOINT_AUDIOSTREAM = 10000;
|
||||
private static final short ENDPOINT_VOICECONTROL = 11000;
|
||||
private static final short ENDPOINT_NOTIFICATIONACTION = 11440; // FW >=3.x, TODO: find a better name
|
||||
private static final short ENDPOINT_APPREORDER = (short) 0xabcd; // FW >=3.x
|
||||
private static final short ENDPOINT_BLOBDB = (short) 0xb1db; // FW >=3.x
|
||||
private static final short ENDPOINT_PUTBYTES = (short) 0xbeef;
|
||||
|
||||
static final byte APPRUNSTATE_START = 1;
|
||||
static final byte APPRUNSTATE_STOP = 2;
|
||||
private static final byte APPRUNSTATE_START = 1;
|
||||
private static final byte APPRUNSTATE_STOP = 2;
|
||||
|
||||
static final byte BLOBDB_INSERT = 1;
|
||||
static final byte BLOBDB_DELETE = 4;
|
||||
static final byte BLOBDB_CLEAR = 5;
|
||||
private static final byte BLOBDB_INSERT = 1;
|
||||
private static final byte BLOBDB_DELETE = 4;
|
||||
private static final byte BLOBDB_CLEAR = 5;
|
||||
|
||||
static final byte BLOBDB_PIN = 1;
|
||||
static final byte BLOBDB_APP = 2;
|
||||
static final byte BLOBDB_REMINDER = 3;
|
||||
static final byte BLOBDB_NOTIFICATION = 4;
|
||||
static final byte BLOBDB_CANNED_MESSAGES = 6;
|
||||
static final byte BLOBDB_PREFERENCES = 7;
|
||||
static final byte BLOBDB_APPGLANCE = 11;
|
||||
private static final byte BLOBDB_PIN = 1;
|
||||
private static final byte BLOBDB_APP = 2;
|
||||
private static final byte BLOBDB_REMINDER = 3;
|
||||
private static final byte BLOBDB_NOTIFICATION = 4;
|
||||
private static final byte BLOBDB_WEATHER = 5;
|
||||
private static final byte BLOBDB_CANNED_MESSAGES = 6;
|
||||
private static final byte BLOBDB_PREFERENCES = 7;
|
||||
private static final byte BLOBDB_APPSETTINGS = 9;
|
||||
private static final byte BLOBDB_APPGLANCE = 11;
|
||||
|
||||
static final byte BLOBDB_SUCCESS = 1;
|
||||
static final byte BLOBDB_GENERALFAILURE = 2;
|
||||
static final byte BLOBDB_INVALIDOPERATION = 3;
|
||||
static final byte BLOBDB_INVALIDDATABASEID = 4;
|
||||
static final byte BLOBDB_INVALIDDATA = 5;
|
||||
static final byte BLOBDB_KEYDOESNOTEXIST = 6;
|
||||
static final byte BLOBDB_DATABASEFULL = 7;
|
||||
static final byte BLOBDB_DATASTALE = 8;
|
||||
private static final byte BLOBDB_SUCCESS = 1;
|
||||
private static final byte BLOBDB_GENERALFAILURE = 2;
|
||||
private static final byte BLOBDB_INVALIDOPERATION = 3;
|
||||
private static final byte BLOBDB_INVALIDDATABASEID = 4;
|
||||
private static final byte BLOBDB_INVALIDDATA = 5;
|
||||
private static final byte BLOBDB_KEYDOESNOTEXIST = 6;
|
||||
private static final byte BLOBDB_DATABASEFULL = 7;
|
||||
private static final byte BLOBDB_DATASTALE = 8;
|
||||
|
||||
|
||||
// This is not in the Pebble protocol
|
||||
static final byte NOTIFICATION_UNDEFINED = -1;
|
||||
private static final byte NOTIFICATION_EMAIL = 0;
|
||||
private static final byte NOTIFICATION_SMS = 1;
|
||||
private static final byte NOTIFICATION_TWITTER = 2;
|
||||
private static final byte NOTIFICATION_FACEBOOK = 3;
|
||||
|
||||
static final byte NOTIFICATION_EMAIL = 0;
|
||||
static final byte NOTIFICATION_SMS = 1;
|
||||
static final byte NOTIFICATION_TWITTER = 2;
|
||||
static final byte NOTIFICATION_FACEBOOK = 3;
|
||||
private static final byte PHONECONTROL_ANSWER = 1;
|
||||
private static final byte PHONECONTROL_HANGUP = 2;
|
||||
private static final byte PHONECONTROL_GETSTATE = 3;
|
||||
private static final byte PHONECONTROL_INCOMINGCALL = 4;
|
||||
private static final byte PHONECONTROL_OUTGOINGCALL = 5;
|
||||
private static final byte PHONECONTROL_MISSEDCALL = 6;
|
||||
private static final byte PHONECONTROL_RING = 7;
|
||||
private static final byte PHONECONTROL_START = 8;
|
||||
private static final byte PHONECONTROL_END = 9;
|
||||
|
||||
static final byte PHONECONTROL_ANSWER = 1;
|
||||
static final byte PHONECONTROL_HANGUP = 2;
|
||||
static final byte PHONECONTROL_GETSTATE = 3;
|
||||
static final byte PHONECONTROL_INCOMINGCALL = 4;
|
||||
static final byte PHONECONTROL_OUTGOINGCALL = 5;
|
||||
static final byte PHONECONTROL_MISSEDCALL = 6;
|
||||
static final byte PHONECONTROL_RING = 7;
|
||||
static final byte PHONECONTROL_START = 8;
|
||||
static final byte PHONECONTROL_END = 9;
|
||||
private static final byte MUSICCONTROL_SETMUSICINFO = 0x10;
|
||||
private static final byte MUSICCONTROL_SETPLAYSTATE = 0x11;
|
||||
|
||||
static final byte MUSICCONTROL_SETMUSICINFO = 0x10;
|
||||
static final byte MUSICCONTROL_SETPLAYSTATE = 0x11;
|
||||
private static final byte MUSICCONTROL_PLAYPAUSE = 1;
|
||||
private static final byte MUSICCONTROL_PAUSE = 2;
|
||||
private static final byte MUSICCONTROL_PLAY = 3;
|
||||
private static final byte MUSICCONTROL_NEXT = 4;
|
||||
private static final byte MUSICCONTROL_PREVIOUS = 5;
|
||||
private static final byte MUSICCONTROL_VOLUMEUP = 6;
|
||||
private static final byte MUSICCONTROL_VOLUMEDOWN = 7;
|
||||
private static final byte MUSICCONTROL_GETNOWPLAYING = 8;
|
||||
|
||||
static final byte MUSICCONTROL_PLAYPAUSE = 1;
|
||||
static final byte MUSICCONTROL_PAUSE = 2;
|
||||
static final byte MUSICCONTROL_PLAY = 3;
|
||||
static final byte MUSICCONTROL_NEXT = 4;
|
||||
static final byte MUSICCONTROL_PREVIOUS = 5;
|
||||
static final byte MUSICCONTROL_VOLUMEUP = 6;
|
||||
static final byte MUSICCONTROL_VOLUMEDOWN = 7;
|
||||
static final byte MUSICCONTROL_GETNOWPLAYING = 8;
|
||||
private static final byte MUSICCONTROL_STATE_PAUSED = 0x00;
|
||||
private static final byte MUSICCONTROL_STATE_PLAYING = 0x01;
|
||||
private static final byte MUSICCONTROL_STATE_REWINDING = 0x02;
|
||||
private static final byte MUSICCONTROL_STATE_FASTWORWARDING = 0x03;
|
||||
private static final byte MUSICCONTROL_STATE_UNKNOWN = 0x04;
|
||||
|
||||
static final byte MUSICCONTROL_STATE_PAUSED = 0x00;
|
||||
static final byte MUSICCONTROL_STATE_PLAYING = 0x01;
|
||||
static final byte MUSICCONTROL_STATE_REWINDING = 0x02;
|
||||
static final byte MUSICCONTROL_STATE_FASTWORWARDING = 0x03;
|
||||
static final byte MUSICCONTROL_STATE_UNKNOWN = 0x04;
|
||||
private static final byte NOTIFICATIONACTION_ACK = 0;
|
||||
private static final byte NOTIFICATIONACTION_NACK = 1;
|
||||
private static final byte NOTIFICATIONACTION_INVOKE = 0x02;
|
||||
private static final byte NOTIFICATIONACTION_RESPONSE = 0x11;
|
||||
|
||||
static final byte NOTIFICATIONACTION_ACK = 0;
|
||||
static final byte NOTIFICATIONACTION_NACK = 1;
|
||||
static final byte NOTIFICATIONACTION_INVOKE = 0x02;
|
||||
static final byte NOTIFICATIONACTION_RESPONSE = 0x11;
|
||||
private static final byte TIME_GETTIME = 0;
|
||||
private static final byte TIME_SETTIME = 2;
|
||||
private static final byte TIME_SETTIME_UTC = 3;
|
||||
|
||||
static final byte TIME_GETTIME = 0;
|
||||
static final byte TIME_SETTIME = 2;
|
||||
static final byte TIME_SETTIME_UTC = 3;
|
||||
private static final byte FIRMWAREVERSION_GETVERSION = 0;
|
||||
|
||||
static final byte FIRMWAREVERSION_GETVERSION = 0;
|
||||
private static final byte APPMANAGER_GETAPPBANKSTATUS = 1;
|
||||
private static final byte APPMANAGER_REMOVEAPP = 2;
|
||||
private static final byte APPMANAGER_REFRESHAPP = 3;
|
||||
private static final byte APPMANAGER_GETUUIDS = 5;
|
||||
|
||||
static final byte APPMANAGER_GETAPPBANKSTATUS = 1;
|
||||
static final byte APPMANAGER_REMOVEAPP = 2;
|
||||
static final byte APPMANAGER_REFRESHAPP = 3;
|
||||
static final byte APPMANAGER_GETUUIDS = 5;
|
||||
private static final int APPMANAGER_RES_SUCCESS = 1;
|
||||
|
||||
static final int APPMANAGER_RES_SUCCESS = 1;
|
||||
private static final byte APPLICATIONMESSAGE_PUSH = 1;
|
||||
private static final byte APPLICATIONMESSAGE_REQUEST = 2;
|
||||
private static final byte APPLICATIONMESSAGE_ACK = (byte) 0xff;
|
||||
private static final byte APPLICATIONMESSAGE_NACK = (byte) 0x7f;
|
||||
|
||||
static final byte APPLICATIONMESSAGE_PUSH = 1;
|
||||
static final byte APPLICATIONMESSAGE_REQUEST = 2;
|
||||
static final byte APPLICATIONMESSAGE_ACK = (byte) 0xff;
|
||||
static final byte APPLICATIONMESSAGE_NACK = (byte) 0x7f;
|
||||
private static final byte DATALOG_OPENSESSION = 0x01;
|
||||
private static final byte DATALOG_SENDDATA = 0x02;
|
||||
private static final byte DATALOG_CLOSE = 0x03;
|
||||
private static final byte DATALOG_TIMEOUT = 0x07;
|
||||
private static final byte DATALOG_REPORTSESSIONS = (byte) 0x84;
|
||||
private static final byte DATALOG_ACK = (byte) 0x85;
|
||||
private static final byte DATALOG_NACK = (byte) 0x86;
|
||||
|
||||
static final byte DATALOG_OPENSESSION = 0x01;
|
||||
static final byte DATALOG_SENDDATA = 0x02;
|
||||
static final byte DATALOG_CLOSE = 0x03;
|
||||
static final byte DATALOG_TIMEOUT = 0x07;
|
||||
static final byte DATALOG_REPORTSESSIONS = (byte) 0x84;
|
||||
static final byte DATALOG_ACK = (byte) 0x85;
|
||||
static final byte DATALOG_NACK = (byte) 0x86;
|
||||
private static final byte PING_PING = 0;
|
||||
private static final byte PING_PONG = 1;
|
||||
|
||||
static final byte PING_PING = 0;
|
||||
static final byte PING_PONG = 1;
|
||||
|
||||
static final byte PUTBYTES_INIT = 1;
|
||||
static final byte PUTBYTES_SEND = 2;
|
||||
static final byte PUTBYTES_COMMIT = 3;
|
||||
static final byte PUTBYTES_ABORT = 4;
|
||||
static final byte PUTBYTES_COMPLETE = 5;
|
||||
private static final byte PUTBYTES_INIT = 1;
|
||||
private static final byte PUTBYTES_SEND = 2;
|
||||
private static final byte PUTBYTES_COMMIT = 3;
|
||||
private static final byte PUTBYTES_ABORT = 4;
|
||||
private static final byte PUTBYTES_COMPLETE = 5;
|
||||
|
||||
public static final byte PUTBYTES_TYPE_FIRMWARE = 1;
|
||||
public static final byte PUTBYTES_TYPE_RECOVERY = 2;
|
||||
|
@ -185,70 +186,54 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
public static final byte PUTBYTES_TYPE_FILE = 6;
|
||||
public static final byte PUTBYTES_TYPE_WORKER = 7;
|
||||
|
||||
static final byte RESET_REBOOT = 0;
|
||||
private static final byte RESET_REBOOT = 0;
|
||||
|
||||
static final byte SCREENSHOT_TAKE = 0;
|
||||
private static final byte SCREENSHOT_TAKE = 0;
|
||||
|
||||
static final byte SYSTEMMESSAGE_NEWFIRMWAREAVAILABLE = 0;
|
||||
static final byte SYSTEMMESSAGE_FIRMWARESTART = 1;
|
||||
static final byte SYSTEMMESSAGE_FIRMWARECOMPLETE = 2;
|
||||
static final byte SYSTEMMESSAGE_FIRMWAREFAIL = 3;
|
||||
static final byte SYSTEMMESSAGE_FIRMWARE_UPTODATE = 4;
|
||||
static final byte SYSTEMMESSAGE_FIRMWARE_OUTOFDATE = 5;
|
||||
static final byte SYSTEMMESSAGE_STOPRECONNECTING = 6;
|
||||
static final byte SYSTEMMESSAGE_STARTRECONNECTING = 7;
|
||||
private static final byte SYSTEMMESSAGE_NEWFIRMWAREAVAILABLE = 0;
|
||||
private static final byte SYSTEMMESSAGE_FIRMWARESTART = 1;
|
||||
private static final byte SYSTEMMESSAGE_FIRMWARECOMPLETE = 2;
|
||||
private static final byte SYSTEMMESSAGE_FIRMWAREFAIL = 3;
|
||||
private static final byte SYSTEMMESSAGE_FIRMWARE_UPTODATE = 4;
|
||||
private static final byte SYSTEMMESSAGE_FIRMWARE_OUTOFDATE = 5;
|
||||
private static final byte SYSTEMMESSAGE_STOPRECONNECTING = 6;
|
||||
private static final byte SYSTEMMESSAGE_STARTRECONNECTING = 7;
|
||||
|
||||
static final byte PHONEVERSION_REQUEST = 0;
|
||||
static final byte PHONEVERSION_APPVERSION_MAGIC = 2; // increase this if pebble complains
|
||||
static final byte PHONEVERSION_APPVERSION_MAJOR = 2;
|
||||
static final byte PHONEVERSION_APPVERSION_MINOR = 3;
|
||||
static final byte PHONEVERSION_APPVERSION_PATCH = 0;
|
||||
private static final byte PHONEVERSION_REQUEST = 0;
|
||||
private static final byte PHONEVERSION_APPVERSION_MAGIC = 2; // increase this if pebble complains
|
||||
private static final byte PHONEVERSION_APPVERSION_MAJOR = 2;
|
||||
private static final byte PHONEVERSION_APPVERSION_MINOR = 3;
|
||||
private static final byte PHONEVERSION_APPVERSION_PATCH = 0;
|
||||
|
||||
|
||||
static final int PHONEVERSION_SESSION_CAPS_GAMMARAY = 0x80000000;
|
||||
private static final int PHONEVERSION_SESSION_CAPS_GAMMARAY = 0x80000000;
|
||||
|
||||
static final int PHONEVERSION_REMOTE_CAPS_TELEPHONY = 0x00000010;
|
||||
static final int PHONEVERSION_REMOTE_CAPS_SMS = 0x00000020;
|
||||
static final int PHONEVERSION_REMOTE_CAPS_GPS = 0x00000040;
|
||||
static final int PHONEVERSION_REMOTE_CAPS_BTLE = 0x00000080;
|
||||
static final int PHONEVERSION_REMOTE_CAPS_REARCAMERA = 0x00000100;
|
||||
static final int PHONEVERSION_REMOTE_CAPS_ACCEL = 0x00000200;
|
||||
static final int PHONEVERSION_REMOTE_CAPS_GYRO = 0x00000400;
|
||||
static final int PHONEVERSION_REMOTE_CAPS_COMPASS = 0x00000800;
|
||||
private static final int PHONEVERSION_REMOTE_CAPS_TELEPHONY = 0x00000010;
|
||||
private static final int PHONEVERSION_REMOTE_CAPS_SMS = 0x00000020;
|
||||
private static final int PHONEVERSION_REMOTE_CAPS_GPS = 0x00000040;
|
||||
private static final int PHONEVERSION_REMOTE_CAPS_BTLE = 0x00000080;
|
||||
private static final int PHONEVERSION_REMOTE_CAPS_REARCAMERA = 0x00000100;
|
||||
private static final int PHONEVERSION_REMOTE_CAPS_ACCEL = 0x00000200;
|
||||
private static final int PHONEVERSION_REMOTE_CAPS_GYRO = 0x00000400;
|
||||
private static final int PHONEVERSION_REMOTE_CAPS_COMPASS = 0x00000800;
|
||||
|
||||
static final byte PHONEVERSION_REMOTE_OS_UNKNOWN = 0;
|
||||
static final byte PHONEVERSION_REMOTE_OS_IOS = 1;
|
||||
static final byte PHONEVERSION_REMOTE_OS_ANDROID = 2;
|
||||
static final byte PHONEVERSION_REMOTE_OS_OSX = 3;
|
||||
static final byte PHONEVERSION_REMOTE_OS_LINUX = 4;
|
||||
static final byte PHONEVERSION_REMOTE_OS_WINDOWS = 5;
|
||||
private static final byte PHONEVERSION_REMOTE_OS_UNKNOWN = 0;
|
||||
private static final byte PHONEVERSION_REMOTE_OS_IOS = 1;
|
||||
private static final byte PHONEVERSION_REMOTE_OS_ANDROID = 2;
|
||||
private static final byte PHONEVERSION_REMOTE_OS_OSX = 3;
|
||||
private static final byte PHONEVERSION_REMOTE_OS_LINUX = 4;
|
||||
private static final byte PHONEVERSION_REMOTE_OS_WINDOWS = 5;
|
||||
|
||||
static final byte TYPE_BYTEARRAY = 0;
|
||||
static final byte TYPE_CSTRING = 1;
|
||||
static final byte TYPE_UINT = 2;
|
||||
static final byte TYPE_INT = 3;
|
||||
private 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 short LENGTH_PREFIX = 4;
|
||||
static final short LENGTH_SIMPLEMESSAGE = 1;
|
||||
private final short LENGTH_PREFIX = 4;
|
||||
|
||||
static final short LENGTH_APPFETCH = 2;
|
||||
static final short LENGTH_APPRUNSTATE = 17;
|
||||
static final short LENGTH_PING = 5;
|
||||
static final short LENGTH_PHONEVERSION = 17;
|
||||
static final short LENGTH_REMOVEAPP_2X = 17;
|
||||
static final short LENGTH_REFRESHAPP = 5;
|
||||
static final short LENGTH_SETTIME = 5;
|
||||
static final short LENGTH_SYSTEMMESSAGE = 2;
|
||||
static final short LENGTH_UPLOADSTART_2X = 7;
|
||||
static final short LENGTH_UPLOADSTART_3X = 10;
|
||||
static final short LENGTH_UPLOADCHUNK = 9;
|
||||
static final short LENGTH_UPLOADCOMMIT = 9;
|
||||
static final short LENGTH_UPLOADCOMPLETE = 5;
|
||||
static final short LENGTH_UPLOADCANCEL = 5;
|
||||
private static final byte LENGTH_UUID = 16;
|
||||
|
||||
static final byte LENGTH_UUID = 16;
|
||||
|
||||
static final long GB_UUID_MASK = 0x4767744272646700L;
|
||||
private static final long GB_UUID_MASK = 0x4767744272646700L;
|
||||
|
||||
// base is -8
|
||||
private static final String[] hwRevisions = {
|
||||
|
@ -268,18 +253,18 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
private static final Random mRandom = new Random();
|
||||
|
||||
int mFwMajor = 3;
|
||||
boolean mForceProtocol = false;
|
||||
GBDeviceEventScreenshot mDevEventScreenshot = null;
|
||||
int mScreenshotRemaining = -1;
|
||||
private boolean mForceProtocol = false;
|
||||
private GBDeviceEventScreenshot mDevEventScreenshot = null;
|
||||
private int mScreenshotRemaining = -1;
|
||||
|
||||
//monochrome black + white
|
||||
static final byte[] clut_pebble = {
|
||||
private static final byte[] clut_pebble = {
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0xff, 0x00
|
||||
};
|
||||
|
||||
// linear BGR222 (6 bit, 64 entries)
|
||||
static final byte[] clut_pebbletime = new byte[]{
|
||||
private static final byte[] clut_pebbletime = new byte[]{
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x55, 0x00, 0x00, 0x00,
|
||||
(byte) 0xaa, 0x00, 0x00, 0x00,
|
||||
|
@ -368,28 +353,49 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
|
||||
public static final UUID UUID_PEBBLE_HEALTH = UUID.fromString("36d8c6ed-4c83-4fa1-a9e2-8f12dc941f8c"); // FIXME: store somewhere else, this is also accessed by other code
|
||||
public static final UUID UUID_WORKOUT = UUID.fromString("fef82c82-7176-4e22-88de-35a3fc18d43f"); // FIXME: store somewhere else, this is also accessed by other code
|
||||
public static final UUID UUID_WEATHER = UUID.fromString("61b22bc8-1e29-460d-a236-3fe409a439ff"); // FIXME: store somewhere else, this is also accessed by other code
|
||||
public static final UUID UUID_NOTIFICATIONS = UUID.fromString("b2cae818-10f8-46df-ad2b-98ad2254a3c1");
|
||||
|
||||
private static final UUID UUID_GBPEBBLE = UUID.fromString("61476764-7465-7262-6469-656775527a6c");
|
||||
private static final UUID UUID_MORPHEUZ = UUID.fromString("5be44f1d-d262-4ea6-aa30-ddbec1e3cab2");
|
||||
private static final UUID UUID_WHETHERNEAT = UUID.fromString("3684003b-a685-45f9-a713-abc6364ba051");
|
||||
private static final UUID UUID_MISFIT = UUID.fromString("0b73b76a-cd65-4dc2-9585-aaa213320858");
|
||||
private static final UUID UUID_PEBBLE_TIMESTYLE = UUID.fromString("4368ffa4-f0fb-4823-90be-f754b076bdaa");
|
||||
private static final UUID UUID_PEBSTYLE = UUID.fromString("da05e84d-e2a2-4020-a2dc-9cdcf265fcdd");
|
||||
private static final UUID UUID_MARIOTIME = UUID.fromString("43caa750-2896-4f46-94dc-1adbd4bc1ff3");
|
||||
private static final UUID UUID_HELTHIFY = UUID.fromString("7ee97b2c-95e8-4720-b94e-70fccd905d98");
|
||||
private static final UUID UUID_TREKVOLLE = UUID.fromString("2da02267-7a19-4e49-9ed1-439d25db14e4");
|
||||
private static final UUID UUID_SQUARE = UUID.fromString("cb332373-4ee5-4c5c-8912-4f62af2d756c");
|
||||
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_ZERO = new UUID(0, 0);
|
||||
|
||||
private static final UUID UUID_LOCATION = UUID.fromString("2c7e6a86-51e5-4ddd-b606-db43d1e4ad28"); // might be the location of "Berlin" or "Auto"
|
||||
|
||||
private final Map<UUID, AppMessageHandler> mAppMessageHandlers = new HashMap<>();
|
||||
|
||||
private UUID currentRunningApp = UUID_ZERO;
|
||||
|
||||
public PebbleProtocol(GBDevice device) {
|
||||
super(device);
|
||||
mAppMessageHandlers.put(UUID_MORPHEUZ, new AppMessageHandlerMorpheuz(UUID_MORPHEUZ, PebbleProtocol.this));
|
||||
mAppMessageHandlers.put(UUID_WHETHERNEAT, new AppMessageHandlerWeatherNeat(UUID_WHETHERNEAT, PebbleProtocol.this));
|
||||
mAppMessageHandlers.put(UUID_MISFIT, new AppMessageHandlerMisfit(UUID_MISFIT, PebbleProtocol.this));
|
||||
mAppMessageHandlers.put(UUID_PEBBLE_TIMESTYLE, new AppMessageHandlerTimeStylePebble(UUID_PEBBLE_TIMESTYLE, PebbleProtocol.this));
|
||||
mAppMessageHandlers.put(UUID_PEBSTYLE, new AppMessageHandlerPebStyle(UUID_PEBSTYLE, PebbleProtocol.this));
|
||||
//mAppMessageHandlers.put(UUID_PEBSTYLE, new AppMessageHandlerPebStyle(UUID_PEBSTYLE, PebbleProtocol.this));
|
||||
mAppMessageHandlers.put(UUID_MARIOTIME, new AppMessageHandlerMarioTime(UUID_MARIOTIME, PebbleProtocol.this));
|
||||
mAppMessageHandlers.put(UUID_HELTHIFY, new AppMessageHandlerHealthify(UUID_HELTHIFY, PebbleProtocol.this));
|
||||
mAppMessageHandlers.put(UUID_TREKVOLLE, new AppMessageHandlerTrekVolle(UUID_TREKVOLLE, PebbleProtocol.this));
|
||||
mAppMessageHandlers.put(UUID_SQUARE, new AppMessageHandlerSquare(UUID_SQUARE, PebbleProtocol.this));
|
||||
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));
|
||||
}
|
||||
|
||||
private final HashMap<Byte, DatalogSession> mDatalogSessions = new HashMap<>();
|
||||
|
||||
private byte[] encodeSimpleMessage(short endpoint, byte command) {
|
||||
final short LENGTH_SIMPLEMESSAGE = 1;
|
||||
ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_SIMPLEMESSAGE);
|
||||
buf.order(ByteOrder.BIG_ENDIAN);
|
||||
buf.putShort(LENGTH_SIMPLEMESSAGE);
|
||||
|
@ -477,6 +483,11 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encodeDeleteNotification(int id) {
|
||||
return encodeBlobdb(new UUID(GB_UUID_MASK, id), BLOBDB_DELETE, BLOBDB_NOTIFICATION, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encodeAddCalendarEvent(CalendarEventSpec calendarEventSpec) {
|
||||
long id = calendarEventSpec.id != -1 ? calendarEventSpec.id : mRandom.nextLong();
|
||||
|
@ -502,6 +513,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
|
||||
@Override
|
||||
public byte[] encodeSetTime() {
|
||||
final short LENGTH_SETTIME = 5;
|
||||
long ts = System.currentTimeMillis();
|
||||
long ts_offset = (SimpleTimeZone.getDefault().getOffset(ts));
|
||||
ByteBuffer buf;
|
||||
|
@ -532,6 +544,13 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
@Override
|
||||
public byte[] encodeFindDevice(boolean start) {
|
||||
return encodeSetCallState("Where are you?", "Gadgetbridge", start ? CallSpec.CALL_INCOMING : CallSpec.CALL_END);
|
||||
/*
|
||||
int ts = (int) (System.currentTimeMillis() / 1000);
|
||||
|
||||
if (start) {
|
||||
//return encodeWeatherPin(ts, "Weather", "1°/-1°", "Gadgetbridge is Sunny", "Berlin", 37);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
private byte[] encodeExtensibleNotification(int id, int timestamp, String title, String subtitle, String body, String sourceName, boolean hasHandle, String[] cannedReplies) {
|
||||
|
@ -762,6 +781,21 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
activate ? new byte[]{0x01} : new byte[]{0x00});
|
||||
}
|
||||
|
||||
byte[] encodeActivateWeather(boolean activate) {
|
||||
if (activate) {
|
||||
ByteBuffer buf = ByteBuffer.allocate(0x61);
|
||||
buf.put((byte) 1);
|
||||
buf.order(ByteOrder.BIG_ENDIAN);
|
||||
buf.putLong(UUID_LOCATION.getMostSignificantBits());
|
||||
buf.putLong(UUID_LOCATION.getLeastSignificantBits());
|
||||
// disable remaining 5 possible location
|
||||
buf.put(new byte[60 - LENGTH_UUID]);
|
||||
return encodeBlobdb("weatherApp", BLOBDB_INSERT, BLOBDB_APPSETTINGS, buf.array());
|
||||
} else {
|
||||
return encodeBlobdb("weatherApp", BLOBDB_DELETE, BLOBDB_APPSETTINGS, null);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] encodeReportDataLogSessions() {
|
||||
return encodeSimpleMessage(ENDPOINT_DATALOG, DATALOG_REPORTSESSIONS);
|
||||
}
|
||||
|
@ -888,19 +922,16 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
}
|
||||
}
|
||||
|
||||
UUID uuid = UUID.randomUUID();
|
||||
short pin_length = (short) (NOTIFICATION_PIN_LENGTH + attributes_length);
|
||||
|
||||
ByteBuffer buf = ByteBuffer.allocate(pin_length);
|
||||
|
||||
// pin - 46 bytes
|
||||
buf.order(ByteOrder.BIG_ENDIAN);
|
||||
buf.putLong(uuid.getMostSignificantBits());
|
||||
buf.putInt((int) (uuid.getLeastSignificantBits() >>> 32));
|
||||
buf.putInt(id);
|
||||
buf.putLong(uuid.getMostSignificantBits());
|
||||
buf.putInt((int) (uuid.getLeastSignificantBits() >>> 32));
|
||||
buf.putInt(id);
|
||||
buf.putLong(GB_UUID_MASK);
|
||||
buf.putLong(id);
|
||||
buf.putLong(UUID_NOTIFICATIONS.getMostSignificantBits());
|
||||
buf.putLong(UUID_NOTIFICATIONS.getLeastSignificantBits());
|
||||
buf.order(ByteOrder.LITTLE_ENDIAN);
|
||||
buf.putInt(timestamp); // 32-bit timestamp
|
||||
buf.putShort((short) 0); // duration
|
||||
|
@ -1002,6 +1033,178 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
return buf.array();
|
||||
}
|
||||
|
||||
private byte[] encodeWeatherPin(int timestamp, String title, String subtitle, String body, String location, int iconId) {
|
||||
final short NOTIFICATION_PIN_LENGTH = 46;
|
||||
final short ACTION_LENGTH_MIN = 10;
|
||||
|
||||
String[] parts = {title, subtitle, body, location, "test", "test"};
|
||||
|
||||
// Calculate length first
|
||||
byte actions_count = 1;
|
||||
short actions_length;
|
||||
String remove_string = "Remove";
|
||||
actions_length = (short) (ACTION_LENGTH_MIN * actions_count + remove_string.getBytes().length);
|
||||
|
||||
byte attributes_count = 3;
|
||||
short attributes_length = (short) (21 + actions_length);
|
||||
if (parts != null) {
|
||||
for (String s : parts) {
|
||||
if (s == null || s.equals("")) {
|
||||
continue;
|
||||
}
|
||||
attributes_count++;
|
||||
attributes_length += (3 + s.getBytes().length);
|
||||
}
|
||||
}
|
||||
|
||||
UUID uuid = UUID.fromString("61b22bc8-1e29-460d-a236-3fe409a43901");
|
||||
|
||||
short pin_length = (short) (NOTIFICATION_PIN_LENGTH + attributes_length);
|
||||
|
||||
ByteBuffer buf = ByteBuffer.allocate(pin_length);
|
||||
|
||||
// pin (46 bytes)
|
||||
buf.order(ByteOrder.BIG_ENDIAN);
|
||||
buf.putLong(uuid.getMostSignificantBits());
|
||||
buf.putLong(uuid.getLeastSignificantBits());
|
||||
buf.putLong(uuid.getMostSignificantBits());
|
||||
buf.putLong(uuid.getLeastSignificantBits() | 0xff);
|
||||
buf.order(ByteOrder.LITTLE_ENDIAN);
|
||||
buf.putInt(timestamp); // 32-bit timestamp
|
||||
buf.putShort((short) 0); // duration
|
||||
buf.put((byte) 0x02); // type (0x02 = pin)
|
||||
buf.putShort((short) 0x0001); // flags 0x0001 = ?
|
||||
buf.put((byte) 0x06); // layout (0x06 = weather)
|
||||
buf.putShort(attributes_length); // total length of all attributes and actions in bytes
|
||||
buf.put(attributes_count);
|
||||
buf.put(actions_count);
|
||||
|
||||
byte attribute_id = 0;
|
||||
// Encode Pascal-Style Strings
|
||||
if (parts != null) {
|
||||
for (String s : parts) {
|
||||
attribute_id++;
|
||||
if (s == null || s.equals("")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int partlength = s.getBytes().length;
|
||||
if (partlength > 512) partlength = 512;
|
||||
if (attribute_id == 4) {
|
||||
buf.put((byte) 11);
|
||||
} else if (attribute_id == 5) {
|
||||
buf.put((byte) 25);
|
||||
} else if (attribute_id == 6) {
|
||||
buf.put((byte) 26);
|
||||
} else {
|
||||
buf.put(attribute_id);
|
||||
}
|
||||
buf.putShort((short) partlength);
|
||||
buf.put(s.getBytes(), 0, partlength);
|
||||
}
|
||||
}
|
||||
|
||||
buf.put((byte) 4); // icon
|
||||
buf.putShort((short) 4); // length of int
|
||||
buf.putInt(0x80000000 | iconId);
|
||||
|
||||
buf.put((byte) 6); // icon
|
||||
buf.putShort((short) 4); // length of int
|
||||
buf.putInt(0x80000000 | iconId);
|
||||
|
||||
buf.put((byte) 14); // last updated
|
||||
buf.putShort((short) 4); // length of int
|
||||
buf.putInt(timestamp);
|
||||
|
||||
// remove action
|
||||
buf.put((byte) 123); // action id
|
||||
buf.put((byte) 0x09); // remove
|
||||
buf.put((byte) 0x01); // number attributes
|
||||
buf.put((byte) 0x01); // attribute id (title)
|
||||
buf.putShort((short) remove_string.getBytes().length);
|
||||
buf.put(remove_string.getBytes());
|
||||
|
||||
return encodeBlobdb(uuid, BLOBDB_INSERT, BLOBDB_PIN, buf.array());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public byte[] encodeSendWeather(WeatherSpec weatherSpec) {
|
||||
byte[] forecastProtocol = null;
|
||||
byte[] watchfaceProtocol = null;
|
||||
int length = 0;
|
||||
if (mFwMajor >= 4) {
|
||||
forecastProtocol = encodeWeatherForecast(weatherSpec);
|
||||
length += forecastProtocol.length;
|
||||
}
|
||||
AppMessageHandler handler = mAppMessageHandlers.get(currentRunningApp);
|
||||
if (handler != null) {
|
||||
watchfaceProtocol = handler.encodeUpdateWeather(weatherSpec);
|
||||
if (watchfaceProtocol != null) {
|
||||
length += watchfaceProtocol.length;
|
||||
}
|
||||
}
|
||||
ByteBuffer buf = ByteBuffer.allocate(length);
|
||||
|
||||
if (forecastProtocol != null) {
|
||||
buf.put(forecastProtocol);
|
||||
}
|
||||
if (watchfaceProtocol != null) {
|
||||
buf.put(watchfaceProtocol);
|
||||
}
|
||||
|
||||
return buf.array();
|
||||
}
|
||||
|
||||
private byte[] encodeWeatherForecast(WeatherSpec weatherSpec) {
|
||||
final short WEATHER_FORECAST_LENGTH = 20;
|
||||
|
||||
String[] parts = {weatherSpec.location, weatherSpec.currentCondition};
|
||||
|
||||
// Calculate length first
|
||||
short attributes_length = 0;
|
||||
if (parts != null) {
|
||||
for (String s : parts) {
|
||||
if (s == null || s.equals("")) {
|
||||
continue;
|
||||
}
|
||||
attributes_length += (2 + s.getBytes().length);
|
||||
}
|
||||
}
|
||||
|
||||
short pin_length = (short) (WEATHER_FORECAST_LENGTH + attributes_length);
|
||||
|
||||
ByteBuffer buf = ByteBuffer.allocate(pin_length);
|
||||
buf.order(ByteOrder.LITTLE_ENDIAN);
|
||||
buf.put((byte) 3); // unknown, always 3?
|
||||
buf.putShort((short) (weatherSpec.currentTemp - 273));
|
||||
buf.put(Weather.mapToPebbleCondition(weatherSpec.currentConditionCode));
|
||||
buf.putShort((short) (weatherSpec.todayMaxTemp - 273));
|
||||
buf.putShort((short) (weatherSpec.todayMinTemp - 273));
|
||||
buf.put(Weather.mapToPebbleCondition(weatherSpec.tomorrowConditionCode));
|
||||
buf.putShort((short) (weatherSpec.tomorrowMaxTemp - 273));
|
||||
buf.putShort((short) (weatherSpec.tomorrowMinTemp - 273));
|
||||
buf.putInt(weatherSpec.timestamp);
|
||||
buf.put((byte) 0); // automatic location 0=manual 1=auto
|
||||
buf.putShort(attributes_length);
|
||||
|
||||
// Encode Pascal-Style Strings
|
||||
if (parts != null) {
|
||||
for (String s : parts) {
|
||||
if (s == null || s.equals("")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int partlength = s.getBytes().length;
|
||||
if (partlength > 512) partlength = 512;
|
||||
buf.putShort((short) partlength);
|
||||
buf.put(s.getBytes(), 0, partlength);
|
||||
}
|
||||
}
|
||||
|
||||
return encodeBlobdb(UUID_LOCATION, BLOBDB_INSERT, BLOBDB_WEATHER, buf.array());
|
||||
}
|
||||
|
||||
private byte[] encodeActionResponse(UUID uuid, int iconId, String caption) {
|
||||
short length = (short) (29 + caption.getBytes().length);
|
||||
ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + length);
|
||||
|
@ -1045,7 +1248,8 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
return encodeBlobdb(uuid, BLOBDB_INSERT, BLOBDB_APP, buf.array());
|
||||
}
|
||||
|
||||
public byte[] encodeAppFetchAck() {
|
||||
byte[] encodeAppFetchAck() {
|
||||
final short LENGTH_APPFETCH = 2;
|
||||
ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_APPFETCH);
|
||||
buf.order(ByteOrder.BIG_ENDIAN);
|
||||
buf.putShort(LENGTH_APPFETCH);
|
||||
|
@ -1194,6 +1398,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
@Override
|
||||
public byte[] encodeAppStart(UUID uuid, boolean start) {
|
||||
if (mFwMajor >= 3) {
|
||||
final short LENGTH_APPRUNSTATE = 17;
|
||||
ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_APPRUNSTATE);
|
||||
buf.order(ByteOrder.BIG_ENDIAN);
|
||||
buf.putShort(LENGTH_APPRUNSTATE);
|
||||
|
@ -1219,8 +1424,12 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
if (UUID_WORKOUT.equals(uuid)) {
|
||||
return encodeActivateHRM(false);
|
||||
}
|
||||
if (UUID_WEATHER.equals(uuid)) { //TODO: probably it wasn't present in firmware 3
|
||||
return encodeActivateWeather(false);
|
||||
}
|
||||
return encodeBlobdb(uuid, BLOBDB_DELETE, BLOBDB_APP, null);
|
||||
} else {
|
||||
final short LENGTH_REMOVEAPP_2X = 17;
|
||||
ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_REMOVEAPP_2X);
|
||||
buf.order(ByteOrder.BIG_ENDIAN);
|
||||
buf.putShort(LENGTH_REMOVEAPP_2X);
|
||||
|
@ -1233,6 +1442,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
}
|
||||
|
||||
private byte[] encodePhoneVersion2x(byte os) {
|
||||
final short LENGTH_PHONEVERSION = 17;
|
||||
ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_PHONEVERSION);
|
||||
buf.order(ByteOrder.BIG_ENDIAN);
|
||||
buf.putShort(LENGTH_PHONEVERSION);
|
||||
|
@ -1359,10 +1569,10 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
byte[] encodeUploadStart(byte type, int app_id, int size, String filename) {
|
||||
short length;
|
||||
if (mFwMajor >= 3 && (type != PUTBYTES_TYPE_FILE)) {
|
||||
length = LENGTH_UPLOADSTART_3X;
|
||||
length = (short) 10;
|
||||
type |= 0b10000000;
|
||||
} else {
|
||||
length = LENGTH_UPLOADSTART_2X;
|
||||
length = (short) 7;
|
||||
}
|
||||
|
||||
if (type == PUTBYTES_TYPE_FILE && filename != null) {
|
||||
|
@ -1393,6 +1603,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
}
|
||||
|
||||
byte[] encodeUploadChunk(int token, byte[] buffer, int size) {
|
||||
final short LENGTH_UPLOADCHUNK = 9;
|
||||
ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_UPLOADCHUNK + size);
|
||||
buf.order(ByteOrder.BIG_ENDIAN);
|
||||
buf.putShort((short) (LENGTH_UPLOADCHUNK + size));
|
||||
|
@ -1405,6 +1616,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
}
|
||||
|
||||
byte[] encodeUploadCommit(int token, int crc) {
|
||||
final short LENGTH_UPLOADCOMMIT = 9;
|
||||
ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_UPLOADCOMMIT);
|
||||
buf.order(ByteOrder.BIG_ENDIAN);
|
||||
buf.putShort(LENGTH_UPLOADCOMMIT);
|
||||
|
@ -1416,6 +1628,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
}
|
||||
|
||||
byte[] encodeUploadComplete(int token) {
|
||||
final short LENGTH_UPLOADCOMPLETE = 5;
|
||||
ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_UPLOADCOMPLETE);
|
||||
buf.order(ByteOrder.BIG_ENDIAN);
|
||||
buf.putShort(LENGTH_UPLOADCOMPLETE);
|
||||
|
@ -1426,6 +1639,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
}
|
||||
|
||||
byte[] encodeUploadCancel(int token) {
|
||||
final short LENGTH_UPLOADCANCEL = 5;
|
||||
ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_UPLOADCANCEL);
|
||||
buf.order(ByteOrder.BIG_ENDIAN);
|
||||
buf.putShort(LENGTH_UPLOADCANCEL);
|
||||
|
@ -1436,6 +1650,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
}
|
||||
|
||||
private byte[] encodeSystemMessage(byte systemMessage) {
|
||||
final short LENGTH_SYSTEMMESSAGE = 2;
|
||||
ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_SYSTEMMESSAGE);
|
||||
buf.order(ByteOrder.BIG_ENDIAN);
|
||||
buf.putShort(LENGTH_SYSTEMMESSAGE);
|
||||
|
@ -1460,6 +1675,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
|
||||
|
||||
byte[] encodeAppRefresh(int index) {
|
||||
final short LENGTH_REFRESHAPP = 5;
|
||||
ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_REFRESHAPP);
|
||||
buf.order(ByteOrder.BIG_ENDIAN);
|
||||
buf.putShort(LENGTH_REFRESHAPP);
|
||||
|
@ -1496,6 +1712,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
}
|
||||
|
||||
private byte[] encodePing(byte command, int cookie) {
|
||||
final short LENGTH_PING = 5;
|
||||
ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_PING);
|
||||
buf.order(ByteOrder.BIG_ENDIAN);
|
||||
buf.putShort(LENGTH_PING);
|
||||
|
@ -1528,7 +1745,13 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
switch (type) {
|
||||
case TYPE_INT:
|
||||
case TYPE_UINT:
|
||||
dict.add(new Pair<Integer, Object>(key, buf.getInt()));
|
||||
if (length == 1) {
|
||||
dict.add(new Pair<Integer, Object>(key, buf.get()));
|
||||
} else if (length == 2) {
|
||||
dict.add(new Pair<Integer, Object>(key, buf.getShort()));
|
||||
} else {
|
||||
dict.add(new Pair<Integer, Object>(key, buf.getInt()));
|
||||
}
|
||||
break;
|
||||
case TYPE_CSTRING:
|
||||
case TYPE_BYTEARRAY:
|
||||
|
@ -1910,10 +2133,10 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
switch (command) {
|
||||
case APPRUNSTATE_START:
|
||||
LOG.info(ENDPOINT_NAME + ": started " + uuid);
|
||||
|
||||
currentRunningApp = uuid;
|
||||
AppMessageHandler handler = mAppMessageHandlers.get(uuid);
|
||||
if (handler != null) {
|
||||
return handler.pushMessage();
|
||||
return handler.onAppStart();
|
||||
}
|
||||
else {
|
||||
GBDeviceEventAppManagement gbDeviceEventAppManagement = new GBDeviceEventAppManagement();
|
||||
|
@ -2245,7 +2468,8 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
devEvts = handler.handleMessage(dict);
|
||||
}
|
||||
else {
|
||||
devEvts = handler.pushMessage();
|
||||
currentRunningApp = uuid;
|
||||
devEvts = handler.onAppStart();
|
||||
}
|
||||
} else {
|
||||
devEvts = new GBDeviceEvent[]{null};
|
||||
|
@ -2256,6 +2480,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||
devEvts = decodeDictToJSONAppMessage(uuid, buf);
|
||||
}
|
||||
else {
|
||||
currentRunningApp = uuid;
|
||||
GBDeviceEventAppManagement gbDeviceEventAppManagement = new GBDeviceEventAppManagement();
|
||||
gbDeviceEventAppManagement.uuid = uuid;
|
||||
gbDeviceEventAppManagement.type = GBDeviceEventAppManagement.EventType.START;
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.ArrayList;
|
|||
import java.util.Iterator;
|
||||
import java.util.UUID;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
|
||||
|
@ -18,6 +19,7 @@ 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.WeatherSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.serial.AbstractSerialDeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceIoThread;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol;
|
||||
|
@ -119,7 +121,11 @@ public class PebbleSupport extends AbstractSerialDeviceSupport {
|
|||
@Override
|
||||
public void onSetCallState(CallSpec callSpec) {
|
||||
if (reconnect()) {
|
||||
super.onSetCallState(callSpec);
|
||||
if (callSpec.command == CallSpec.CALL_OUTGOING) {
|
||||
if (GBApplication.getPrefs().getBoolean("pebble_enable_outgoing_call",true)) {
|
||||
super.onSetCallState(callSpec);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,4 +176,11 @@ public class PebbleSupport extends AbstractSerialDeviceSupport {
|
|||
super.onTestNewFunction();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
||||
if (reconnect()) {
|
||||
super.onSendWeather(weatherSpec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,6 +111,11 @@ class PebbleGATTServer extends BluetoothGattServerCallback {
|
|||
int serial = header >> 3;
|
||||
if (command == 0x01) {
|
||||
LOG.info("got ACK for serial = " + serial);
|
||||
if (mPebbleLESupport.mPPAck != null) {
|
||||
mPebbleLESupport.mPPAck.countDown();
|
||||
} else {
|
||||
LOG.warn("mPPAck countdownlatch is not present but it probably should");
|
||||
}
|
||||
}
|
||||
if (command == 0x02) { // some request?
|
||||
LOG.info("got command 0x02");
|
||||
|
|
|
@ -9,6 +9,9 @@ import org.slf4j.LoggerFactory;
|
|||
import java.io.IOException;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
|
||||
public class PebbleLESupport {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(PebbleLESupport.class);
|
||||
|
@ -19,7 +22,9 @@ public class PebbleLESupport {
|
|||
private PipedInputStream mPipedInputStream;
|
||||
private PipedOutputStream mPipedOutputStream;
|
||||
private int mMTU = 20;
|
||||
private int mMTULimit = Integer.MAX_VALUE;
|
||||
boolean mIsConnected = false;
|
||||
public CountDownLatch mPPAck;
|
||||
|
||||
public PebbleLESupport(Context context, final BluetoothDevice btDevice, PipedInputStream pipedInputStream, PipedOutputStream pipedOutputStream) throws IOException {
|
||||
mBtDevice = btDevice;
|
||||
|
@ -31,6 +36,9 @@ public class PebbleLESupport {
|
|||
} catch (IOException e) {
|
||||
LOG.warn("could not connect input stream");
|
||||
}
|
||||
mMTULimit = GBApplication.getPrefs().getInt("pebble_mtu_limit", 512);
|
||||
mMTULimit = Math.max(mMTULimit, 20);
|
||||
mMTULimit = Math.min(mMTULimit, 512);
|
||||
|
||||
mPebbleGATTServer = new PebbleGATTServer(this, context, mBtDevice);
|
||||
if (mPebbleGATTServer.initialize()) {
|
||||
|
@ -99,7 +107,7 @@ public class PebbleLESupport {
|
|||
}
|
||||
|
||||
void setMTU(int mtu) {
|
||||
mMTU = mtu;
|
||||
mMTU = Math.min(mtu, mMTULimit);
|
||||
}
|
||||
|
||||
private class PipeReader extends Thread {
|
||||
|
@ -129,6 +137,7 @@ public class PebbleLESupport {
|
|||
|
||||
int payloadToSend = bytesRead + 4;
|
||||
int srcPos = 0;
|
||||
mPPAck = new CountDownLatch(1);
|
||||
while (payloadToSend > 0) {
|
||||
int chunkSize = (payloadToSend < (mMTU - 4)) ? payloadToSend : mMTU - 4;
|
||||
byte[] outBuf = new byte[chunkSize + 1];
|
||||
|
@ -139,7 +148,9 @@ public class PebbleLESupport {
|
|||
payloadToSend -= chunkSize;
|
||||
}
|
||||
|
||||
Thread.sleep(500); // FIXME ugly wait 0.5s after each pebble package send to the pebble (we do not wait for the GATT chunks)
|
||||
mPPAck.await();
|
||||
mPPAck = null;
|
||||
|
||||
} catch (IOException | InterruptedException e) {
|
||||
LOG.info(e.getMessage());
|
||||
Thread.currentThread().interrupt();
|
||||
|
|
|
@ -25,6 +25,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
|||
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
|
@ -123,6 +124,11 @@ public class VibratissimoSupport extends AbstractBTLEDeviceSupport {
|
|||
public void onNotification(NotificationSpec notificationSpec) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleteNotification(int id) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetTime() {
|
||||
|
||||
|
@ -280,4 +286,9 @@ public class VibratissimoSupport extends AbstractBTLEDeviceSupport {
|
|||
public void onTestNewFunction() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
|||
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.AbstractDeviceSupport;
|
||||
|
||||
/**
|
||||
|
@ -27,7 +28,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.AbstractDeviceSupport;
|
|||
* to create the device specific message for the respective events and sends them to the device via {@link #sendToDevice(byte[])}.
|
||||
*/
|
||||
public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport {
|
||||
protected GBDeviceProtocol gbDeviceProtocol;
|
||||
private GBDeviceProtocol gbDeviceProtocol;
|
||||
protected GBDeviceIoThread gbDeviceIOThread;
|
||||
|
||||
/**
|
||||
|
@ -59,7 +60,7 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport
|
|||
/**
|
||||
* Lazily creates and returns the GBDeviceProtocol instance to be used.
|
||||
*/
|
||||
public synchronized GBDeviceProtocol getDeviceProtocol() {
|
||||
protected synchronized GBDeviceProtocol getDeviceProtocol() {
|
||||
if (gbDeviceProtocol == null) {
|
||||
gbDeviceProtocol = createDeviceProtocol();
|
||||
}
|
||||
|
@ -82,13 +83,13 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport
|
|||
*
|
||||
* @param bytes the message to send to the device
|
||||
*/
|
||||
protected void sendToDevice(byte[] bytes) {
|
||||
private void sendToDevice(byte[] bytes) {
|
||||
if (bytes != null && gbDeviceIOThread != null) {
|
||||
gbDeviceIOThread.write(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
public void handleGBDeviceEvent(GBDeviceEventSendBytes sendBytes) {
|
||||
private void handleGBDeviceEvent(GBDeviceEventSendBytes sendBytes) {
|
||||
sendToDevice(sendBytes.encodedBytes);
|
||||
}
|
||||
|
||||
|
@ -107,6 +108,12 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport
|
|||
sendToDevice(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleteNotification(int id) {
|
||||
byte[] bytes = gbDeviceProtocol.encodeDeleteNotification(id);
|
||||
sendToDevice(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetTime() {
|
||||
byte[] bytes = gbDeviceProtocol.encodeSetTime();
|
||||
|
@ -226,4 +233,10 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport
|
|||
byte[] bytes = gbDeviceProtocol.encodeTestNewFunction();
|
||||
sendToDevice(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
||||
byte[] bytes = gbDeviceProtocol.encodeSendWeather(weatherSpec);
|
||||
sendToDevice(bytes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
|||
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
|
||||
public abstract class GBDeviceProtocol {
|
||||
|
||||
|
@ -20,6 +21,10 @@ public abstract class GBDeviceProtocol {
|
|||
return null;
|
||||
}
|
||||
|
||||
public byte[] encodeDeleteNotification(int id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] encodeSetTime() {
|
||||
return null;
|
||||
}
|
||||
|
@ -108,4 +113,7 @@ public abstract class GBDeviceProtocol {
|
|||
return mDevice;
|
||||
}
|
||||
|
||||
public byte[] encodeSendWeather(WeatherSpec weatherSpec) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -46,14 +47,20 @@ public class FileUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the contents of the given input stream to the destination file.
|
||||
* @param inputStream the contents to write. Note: the caller has to close the input stream!
|
||||
* @param destFile the file to write to
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void copyStreamToFile(InputStream inputStream, File destFile) throws IOException {
|
||||
FileOutputStream fout = new FileOutputStream(destFile);
|
||||
byte[] buf = new byte[4096];
|
||||
while (inputStream.available() > 0) {
|
||||
int bytes = inputStream.read(buf);
|
||||
fout.write(buf, 0, bytes);
|
||||
try (FileOutputStream fout = new FileOutputStream(destFile)) {
|
||||
byte[] buf = new byte[4096];
|
||||
while (inputStream.available() > 0) {
|
||||
int bytes = inputStream.read(buf);
|
||||
fout.write(buf, 0, bytes);
|
||||
}
|
||||
}
|
||||
fout.close();
|
||||
}
|
||||
|
||||
public static void copyURItoFile(Context ctx, Uri uri, File destFile) throws IOException {
|
||||
|
@ -62,29 +69,47 @@ public class FileUtils {
|
|||
}
|
||||
|
||||
ContentResolver cr = ctx.getContentResolver();
|
||||
InputStream fin;
|
||||
try {
|
||||
fin = new BufferedInputStream(cr.openInputStream(uri));
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
InputStream in = cr.openInputStream(uri);
|
||||
if (in == null) {
|
||||
throw new IOException("unable to open input stream: " + uri);
|
||||
}
|
||||
try (InputStream fin = new BufferedInputStream(in)) {
|
||||
copyStreamToFile(fin, destFile);
|
||||
fin.close();
|
||||
}
|
||||
copyStreamToFile(fin, destFile);
|
||||
fin.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the textual contents of the given file. The contents is expected to be
|
||||
* in UTF-8 encoding.
|
||||
* @param file the file to read
|
||||
* @return the file contents as a newline-delimited string
|
||||
* @throws IOException
|
||||
* @see #getStringFromFile(File, String)
|
||||
*/
|
||||
public static String getStringFromFile(File file) throws IOException {
|
||||
return getStringFromFile(file, StandardCharsets.UTF_8.name());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the textual contents of the given file. The contents will be interpreted using the
|
||||
* given encoding.
|
||||
* @param file the file to read
|
||||
* @return the file contents as a newline-delimited string
|
||||
* @throws IOException
|
||||
* @see #getStringFromFile(File)
|
||||
*/
|
||||
public static String getStringFromFile(File file, String encoding) throws IOException {
|
||||
FileInputStream fin = new FileInputStream(file);
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(fin));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
sb.append(line).append("\n");
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(fin, encoding))) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
sb.append(line).append("\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
reader.close();
|
||||
fin.close();
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -65,6 +65,9 @@ public class GB {
|
|||
if (GBApplication.isRunningLollipopOrLater()) {
|
||||
builder.setVisibility(Notification.VISIBILITY_PUBLIC);
|
||||
}
|
||||
if (GBApplication.minimizeNotification()) {
|
||||
builder.setPriority(Notification.PRIORITY_MIN);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
package nodomain.freeyourgadget.gadgetbridge.util;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.provider.MediaStore;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class UriHelper {
|
||||
@NonNull
|
||||
private final Uri uri;
|
||||
@NonNull
|
||||
private final Context context;
|
||||
private String fileName;
|
||||
private long fileSize;
|
||||
@Nullable
|
||||
private File file;
|
||||
|
||||
private UriHelper(@NonNull Uri uri, @NonNull Context context) {
|
||||
this.uri = uri;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the uri as passed to #get(Uri, Context)
|
||||
*/
|
||||
@NonNull
|
||||
public Uri getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the context as passed to #get(Uri, Context)
|
||||
*/
|
||||
@NonNull
|
||||
public Context getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable helper to access the given Uri. In case the uri cannot be read/resolved
|
||||
* an IOException is thrown.
|
||||
* @param uri the uri to access
|
||||
* @param context the context for accessing uris
|
||||
* @throws IOException
|
||||
*/
|
||||
@NonNull
|
||||
public static UriHelper get(@NonNull Uri uri, @NonNull Context context) throws FileNotFoundException, IOException {
|
||||
UriHelper helper = new UriHelper(uri, context);
|
||||
helper.resolveMetadata();
|
||||
return helper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a stream to read the contents of the uri.
|
||||
* Note: the caller has to close the stream after usage.
|
||||
* Every invocation of this method will open a new stream.
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
@NonNull
|
||||
public InputStream openInputStream() throws FileNotFoundException {
|
||||
ContentResolver cr = context.getContentResolver();
|
||||
InputStream inputStream = cr.openInputStream(uri);
|
||||
if (inputStream != null) {
|
||||
return new BufferedInputStream(inputStream);
|
||||
}
|
||||
throw new FileNotFoundException("Unable to open inputstream for " + uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content length (file size) in bytes
|
||||
*/
|
||||
public long getFileSize() {
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the file referenced by the Uri. Does not include the path.
|
||||
*/
|
||||
@NonNull
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file behind the uri, or null in case it is not a file:/ Uri.
|
||||
* @return the file or null
|
||||
*/
|
||||
@Nullable
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
private void resolveMetadata() throws IOException {
|
||||
String uriScheme = uri.getScheme();
|
||||
if (ContentResolver.SCHEME_CONTENT.equals(uriScheme)) {
|
||||
Cursor cursor = context.getContentResolver().query(
|
||||
uri,
|
||||
new String[] {
|
||||
MediaStore.MediaColumns.DISPLAY_NAME,
|
||||
MediaStore.MediaColumns.SIZE
|
||||
}, null, null, null);
|
||||
if (cursor == null) {
|
||||
throw new IOException("Unable to query metadata for: " + uri);
|
||||
}
|
||||
if (cursor.moveToFirst()) {
|
||||
int name_index = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME);
|
||||
if (name_index == -1) {
|
||||
throw new IOException("Unable to retrieve name for: " + uri);
|
||||
}
|
||||
int size_index = cursor.getColumnIndex(MediaStore.MediaColumns.SIZE);
|
||||
if (size_index == -1) {
|
||||
throw new IOException("Unable to retrieve size for: " + uri);
|
||||
}
|
||||
try {
|
||||
fileName = cursor.getString(name_index);
|
||||
if (fileName == null) {
|
||||
throw new IOException("Unable to retrieve name for: " + uri);
|
||||
}
|
||||
fileSize = cursor.getLong(size_index);
|
||||
if (fileSize < 0) {
|
||||
throw new IOException("Unable to retrieve size for: " + uri);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new IOException("Unable to retrieve metadata for: " + uri + ": " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
} else if (ContentResolver.SCHEME_FILE.equals(uriScheme)) {
|
||||
file = new File(uri.getPath());
|
||||
if (!file.exists()) {
|
||||
throw new FileNotFoundException("Does not exist: " + file);
|
||||
}
|
||||
fileName = file.getName();
|
||||
fileSize = file.length();
|
||||
} else if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(uriScheme)) {
|
||||
// we could actually read it, but I don't see how we can determine the file size
|
||||
throw new IOException("Unsupported scheme for uri: " + uri);
|
||||
} else {
|
||||
throw new IOException("Unsupported scheme for uri: " + uri);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,201 @@
|
|||
package ru.gelin.android.weather.notification;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ParcelableWeather2 implements Parcelable {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ParcelableWeather2.class);
|
||||
|
||||
// getters and setters suck ;)
|
||||
|
||||
public long time = 0;
|
||||
public long queryTime = 0;
|
||||
public int version = 0;
|
||||
public String location = "";
|
||||
public int currentTemp = 0;
|
||||
public String currentCondition = "";
|
||||
|
||||
String[] currentConditionType = null;
|
||||
public int currentConditionCode = 3200;
|
||||
String[] forecastConditionType = null;
|
||||
public int forecastConditionCode = 3200;
|
||||
public int todayLowTemp = 0;
|
||||
public int todayHighTemp = 0;
|
||||
public int forecastLowTemp = 0;
|
||||
public int forecastHighTemp = 0;
|
||||
|
||||
|
||||
private ParcelableWeather2(Parcel in) {
|
||||
int version = in.readInt();
|
||||
if (version != 2) {
|
||||
return;
|
||||
}
|
||||
Bundle bundle = in.readBundle();
|
||||
|
||||
location = bundle.getString("weather_location");
|
||||
time = bundle.getLong("weather_time");
|
||||
queryTime = bundle.getLong("weather_query_time");
|
||||
bundle.getString("weather_forecast_url");
|
||||
int conditions = bundle.getInt("weather_conditions");
|
||||
if (conditions > 0) {
|
||||
Bundle conditionBundle = in.readBundle();
|
||||
currentCondition = conditionBundle.getString("weather_condition_text");
|
||||
conditionBundle.getStringArray("weather_condition_types");
|
||||
currentTemp = conditionBundle.getInt("weather_current_temp");
|
||||
|
||||
currentConditionType = conditionBundle.getStringArray("weather_condition_types");
|
||||
currentConditionCode = weatherConditionTypesToOpenWeatherMapIds(currentConditionType[0]);
|
||||
todayLowTemp = conditionBundle.getInt("weather_low_temp");
|
||||
todayHighTemp = conditionBundle.getInt("weather_high_temp");
|
||||
//fetch immediate next forecast
|
||||
if (--conditions > 0) {
|
||||
Bundle forecastBundle = in.readBundle();
|
||||
forecastConditionType = forecastBundle.getStringArray("weather_condition_types");
|
||||
forecastConditionCode = weatherConditionTypesToOpenWeatherMapIds(forecastConditionType[0]);
|
||||
forecastLowTemp = forecastBundle.getInt("weather_low_temp");
|
||||
forecastHighTemp = forecastBundle.getInt("weather_high_temp");
|
||||
}
|
||||
}
|
||||
// get the rest
|
||||
while (--conditions > 0) {
|
||||
Bundle conditionBundle = in.readBundle();
|
||||
conditionBundle.getString("weather_condition_text");
|
||||
conditionBundle.getStringArray("weather_condition_types");
|
||||
conditionBundle.getInt("weather_current_temp");
|
||||
}
|
||||
}
|
||||
|
||||
public static final Creator<ParcelableWeather2> CREATOR = new Creator<ParcelableWeather2>() {
|
||||
@Override
|
||||
public ParcelableWeather2 createFromParcel(Parcel in) {
|
||||
return new ParcelableWeather2(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParcelableWeather2[] newArray(int size) {
|
||||
return new ParcelableWeather2[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
// we do not really want to use this at all
|
||||
}
|
||||
|
||||
private int weatherConditionTypesToOpenWeatherMapIds(String weather_condition_type) {
|
||||
switch (weather_condition_type) {
|
||||
case "THUNDERSTORM_RAIN_LIGHT":
|
||||
return 200;
|
||||
case "THUNDERSTORM_RAIN":
|
||||
return 201;
|
||||
case "THUNDERSTORM_RAIN_HEAVY":
|
||||
return 202;
|
||||
case "THUNDERSTORM_LIGHT":
|
||||
return 210;
|
||||
case "THUNDERSTORM":
|
||||
return 211;
|
||||
case "THUNDERSTORM_HEAVY":
|
||||
return 212;
|
||||
case "THUNDERSTORM_RAGGED":
|
||||
return 221;
|
||||
case "THUNDERSTORM_DRIZZLE_LIGHT":
|
||||
return 230;
|
||||
case "THUNDERSTORM_DRIZZLE":
|
||||
return 231;
|
||||
case "THUNDERSTORM_DRIZZLE_HEAVY":
|
||||
return 232;
|
||||
|
||||
case "DRIZZLE_LIGHT":
|
||||
return 300;
|
||||
case "DRIZZLE":
|
||||
return 301;
|
||||
case "DRIZZLE_HEAVY":
|
||||
return 302;
|
||||
case "DRIZZLE_RAIN_LIGHT":
|
||||
return 310;
|
||||
case "DRIZZLE_RAIN":
|
||||
return 311;
|
||||
case "DRIZZLE_RAIN_HEAVY":
|
||||
return 312;
|
||||
case "DRIZZLE_SHOWER":
|
||||
return 321;
|
||||
|
||||
case "RAIN_LIGHT":
|
||||
return 500;
|
||||
case "RAIN":
|
||||
return 501;
|
||||
case "RAIN_HEAVY":
|
||||
return 502;
|
||||
case "RAIN_VERY_HEAVY":
|
||||
return 503;
|
||||
case "RAIN_EXTREME":
|
||||
return 504;
|
||||
case "RAIN_FREEZING":
|
||||
return 511;
|
||||
case "RAIN_SHOWER_LIGHT":
|
||||
return 520;
|
||||
case "RAIN_SHOWER":
|
||||
return 521;
|
||||
case "RAIN_SHOWER_HEAVY":
|
||||
return 522;
|
||||
|
||||
case "SNOW_LIGHT":
|
||||
return 600;
|
||||
case "SNOW":
|
||||
return 601;
|
||||
case "SNOW_HEAVY":
|
||||
return 602;
|
||||
case "SLEET":
|
||||
return 611;
|
||||
case "SNOW_SHOWER":
|
||||
return 621;
|
||||
|
||||
case "MIST":
|
||||
return 701;
|
||||
case "SMOKE":
|
||||
return 711;
|
||||
case "HAZE":
|
||||
return 721;
|
||||
case "SAND_WHIRLS":
|
||||
return 731;
|
||||
case "FOG":
|
||||
return 741;
|
||||
|
||||
case "CLOUDS_CLEAR":
|
||||
return 800;
|
||||
case "CLOUDS_FEW":
|
||||
return 801;
|
||||
case "CLOUDS_SCATTERED":
|
||||
return 802;
|
||||
case "CLOUDS_BROKEN":
|
||||
return 803;
|
||||
case "CLOUDS_OVERCAST":
|
||||
return 804;
|
||||
|
||||
case "TORNADO":
|
||||
return 900;
|
||||
case "TROPICAL_STORM":
|
||||
return 901;
|
||||
case "HURRICANE":
|
||||
return 902;
|
||||
case "COLD":
|
||||
return 903;
|
||||
case "HOT":
|
||||
return 904;
|
||||
case "WINDY":
|
||||
return 905;
|
||||
case "HAIL":
|
||||
return 906;
|
||||
}
|
||||
return 3200;
|
||||
}
|
||||
}
|
|
@ -10,7 +10,5 @@
|
|||
android:descendantFocusability="blocksDescendants"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/alarm_list"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_centerHorizontal="true" />
|
||||
android:id="@+id/alarm_list" />
|
||||
</FrameLayout>
|
||||
|
|
|
@ -21,6 +21,12 @@
|
|||
<item
|
||||
android:id="@+id/appmanager_hrm_deactivate"
|
||||
android:title="@string/appmanager_hrm_deactivate"/>
|
||||
<item
|
||||
android:id="@+id/appmanager_weather_activate"
|
||||
android:title="@string/appmanager_weather_activate" />
|
||||
<item
|
||||
android:id="@+id/appmanager_weather_deactivate"
|
||||
android:title="@string/appmanager_weather_deactivate" />
|
||||
<item
|
||||
android:id="@+id/appmanager_app_configure"
|
||||
android:title="@string/app_configure"/>
|
||||
|
|
|
@ -22,8 +22,11 @@
|
|||
<string name="appmananger_app_delete">Löschen</string>
|
||||
<string name="appmananger_app_delete_cache">Löschen und aus dem Zwischenspeicher entfernen</string>
|
||||
<string name="appmananger_app_reinstall">Erneut installieren</string>
|
||||
<string name="appmanager_app_openinstore">Im Pebble Appstore suchen</string>
|
||||
<string name="appmanager_health_activate">aktivieren</string>
|
||||
<string name="appmanager_health_deactivate">deaktivieren</string>
|
||||
<string name="appmanager_hrm_activate">HRM aktivieren</string>
|
||||
<string name="appmanager_hrm_deactivate">HRM deaktivieren</string>
|
||||
<string name="app_configure">Konfigurieren</string>
|
||||
<string name="app_move_to_top">Nach oben</string>
|
||||
<!--Strings related to AppBlacklist-->
|
||||
|
@ -85,12 +88,20 @@
|
|||
<string name="pref_title_location_aquire">Standort Bestimmen</string>
|
||||
<string name="pref_title_location_latitude">Breitengrad</string>
|
||||
<string name="pref_title_location_longitude">Längengrad</string>
|
||||
<string name="pref_title_location_keep_uptodate">Automatisch Standort aktualisieren</string>
|
||||
<string name="pref_summary_location_keep_uptodate">Versuche den aktuellen Standort zur Laufzeit abzufragen und nutze die gespeicherten Standort falls das fehlschlägt</string>
|
||||
<string name="toast_enable_networklocationprovider">Bitte ungefähre Standortbestimmung einschalten</string>
|
||||
<string name="toast_aqurired_networklocation">Standort wurde bestimmt</string>
|
||||
<string name="pref_title_pebble_forceprotocol">Benachrichtigungsprotokoll erzwingen</string>
|
||||
<string name="pref_summary_pebble_forceprotocol">Diese Option erzwingt das neuste Benachrichtigungsprotokoll abhängig von der Firmwareversion. NUR EINSCHALTEN, WENN DU WEISST WAS DU TUST!</string>
|
||||
<string name="pref_title_pebble_forceuntested">Ungetestete Features freischalten</string>
|
||||
<string name="pref_summary_pebble_forceuntested">Schaltet ungetetestete Features frei. TU DIES NUR, WENN DU WEIßT, WAS DU TUST!</string>
|
||||
<string name="pref_title_pebble_forcele">BLE immer bevorzugen</string>
|
||||
<string name="pref_summary_pebble_forcele">Nutze den experimentellen LE support für alle Pebbles anstelle von BT classic. Setzt voraus, dass die \"Pebble LE\" gepaart wird, nachdem die nicht-LE Pebble einmal verbunden war.</string>
|
||||
<string name="pref_title_pebble_mtu_limit">Pebble 2/LE GATT MTU Limit</string>
|
||||
<string name="pref_summary_pebble_mtu_limit">Wenn deine Pebble 2/Pebble LE nicht so wie erwartet funktioniert, versuche die MTU zu begrenzen (erlaubte Werte zwischen 20–512)</string>
|
||||
<string name="pref_title_pebble_enable_applogs">Watch App Logging einschalten</string>
|
||||
<string name="pref_summary_pebble_enable_applogs">Schreibt logs von Watch Apps in Gadgetbridge logs (Pebble muss nach Ändern der Option erneut verbunden werden)</string>
|
||||
<string name="pref_title_pebble_reconnect_attempts">Neuverbindungsversuche</string>
|
||||
<string name="not_connected">nicht verbunden</string>
|
||||
<string name="connecting">verbinde</string>
|
||||
|
@ -126,7 +137,7 @@
|
|||
<string name="title_activity_android_pairing">Gerät paaren</string>
|
||||
<string name="android_pairing_hint">Verwende den Android Bluetooth Paaren-Dialog um Dein Gerät zu paaren.</string>
|
||||
<string name="title_activity_mi_band_pairing">Paare Dein Mi Band</string>
|
||||
<string name="pairing">Paarung mit %s…</string>
|
||||
<string name="pairing">Pairing mit %s…</string>
|
||||
<string name="message_cannot_pair_no_mac">Kein MAC Adresse bekommen, kann nicht paaren.</string>
|
||||
<string name="preferences_category_device_specific_settings">Gerätespezifische Einstellungen</string>
|
||||
<string name="preferences_miband_settings">Mi Band Einstellungen</string>
|
||||
|
@ -297,4 +308,5 @@ Wenn Du schon deine Daten importiert hast und mit dem Ergebnis zufrieden bist, k
|
|||
<string name="Delete">Löschen</string>
|
||||
<!--Strings related to Vibration Activity-->
|
||||
<string name="title_activity_vibration">Vibration</string>
|
||||
<!--Strings related to Pebble Pairing Activity-->
|
||||
</resources>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<string name="controlcenter_disconnect">Desconectar</string>
|
||||
<string name="controlcenter_delete_device">Borrar Dispositivo</string>
|
||||
<string name="controlcenter_delete_device_name">Borrar %1$s</string>
|
||||
<string name="controlcenter_delete_device_dialogmessage">¡Esta acción borrará el dispositivo y toda la información asociada a él!</string>
|
||||
<string name="controlcenter_delete_device_dialogmessage">¡Esta acción borrará el dispositivo y toda su información asociada!</string>
|
||||
<string name="title_activity_debug">Depuración</string>
|
||||
<!--Strings related to AppManager-->
|
||||
<string name="title_activity_appmanager">Gestor de app</string>
|
||||
|
@ -27,6 +27,8 @@
|
|||
<string name="appmanager_health_deactivate">Desactivar</string>
|
||||
<string name="appmanager_hrm_activate">Activar Monitor de Ritmo Cardíaco</string>
|
||||
<string name="appmanager_hrm_deactivate">Desactivar Monitor de Ritmo Cardíaco</string>
|
||||
<string name="appmanager_weather_activate">Activar la aplicación del tiempo del sistema</string>
|
||||
<string name="appmanager_weather_deactivate">Desactivar la aplicación del tiempo del sistema</string>
|
||||
<string name="app_configure">Configurar</string>
|
||||
<string name="app_move_to_top">Mover a la parte de arriba</string>
|
||||
<!--Strings related to AppBlacklist-->
|
||||
|
@ -36,14 +38,14 @@
|
|||
<string name="fw_upgrade_notice">Estás a punto de instalar el firmware %s en lugar del que está en tu MiBand.</string>
|
||||
<string name="fw_multi_upgrade_notice">Estás a punto de instalar los firmwares %1$s y %2$s en lugar de los que están en tu MiBand.</string>
|
||||
<string name="miband_firmware_known">Este firmware ha sido probado y se sabe que es compatible con Gadgetbridge.</string>
|
||||
<string name="miband_firmware_unknown_warning">Este firmware no ha sido probado y puede que no sea compatible con Gadgetbridge.\n\nNO se recomienda la instalación en tu MiBand!.</string>
|
||||
<string name="miband_firmware_suggest_whitelist">Si aún así quieres seguir y las cosas continúan funcionando correctamente después de esto, por favor indícales a los desarrolladores de Gadgetbridge que la versión del firmware: %s funciona bien.</string>
|
||||
<string name="miband_firmware_unknown_warning">Este firmware no ha sido probado y puede que no sea compatible con Gadgetbridge.\n\n¡NO se recomienda la instalación en tu MiBand!.</string>
|
||||
<string name="miband_firmware_suggest_whitelist">Si aun así quieres seguir y las cosas continúan funcionando correctamente, por favor indícales a los desarrolladores de Gadgetbridge que esta versión del firmware funciona bien: %s .</string>
|
||||
<!--Strings related to Settings-->
|
||||
<string name="title_activity_settings">Ajustes</string>
|
||||
<string name="pref_header_general">Ajustes generales</string>
|
||||
<string name="pref_title_general_autoconnectonbluetooth">Conectarse al dispositivo cuando el Bluetooth esté activado</string>
|
||||
<string name="pref_title_general_autocreonnect">Reconectar automáticamente</string>
|
||||
<string name="pref_title_audo_player">Reproductor de audio preferido</string>
|
||||
<string name="pref_title_audo_player">Reproductor de audio favorito</string>
|
||||
<string name="pref_default">Predeterminado</string>
|
||||
<string name="pref_header_datetime">Fecha y hora</string>
|
||||
<string name="pref_title_datetime_syctimeonconnect">Sincronizar hora</string>
|
||||
|
@ -62,7 +64,7 @@
|
|||
<string name="pref_title_notifications_generic">Soporte para notificaciones genéricas</string>
|
||||
<string name="pref_title_whenscreenon">… también con pantalla encendida</string>
|
||||
<string name="pref_title_notification_filter">No Molestar</string>
|
||||
<string name="pref_summary_notification_filter">Dejar de enviar Notificaciones no deseadas basándose en el modo No Molestar</string>
|
||||
<string name="pref_summary_notification_filter">Dejar de enviar notificaciones no deseadas basándose en el modo No Molestar</string>
|
||||
<string name="always">siempre</string>
|
||||
<string name="when_screen_off">cuando la pantalla está apagada</string>
|
||||
<string name="never">nunca</string>
|
||||
|
@ -98,6 +100,8 @@
|
|||
<string name="pref_summary_pebble_forceuntested">Habilita características que no han sido probadas. ¡HABILÍTALO SOLO SI SABES LO QUE ESTÁS HACIENDO!</string>
|
||||
<string name="pref_title_pebble_forcele">Preferir siempre BLE</string>
|
||||
<string name="pref_summary_pebble_forcele">Usar el soporte experimental de Pebble LE para todos los Pebble en lugar del bluetooth clásico. Requiere vincular \"Pebble LE\" si un Pebble no-LE ha sido vinculado antes.</string>
|
||||
<string name="pref_title_pebble_mtu_limit">Pebble 2/LE límite de GATT MTU</string>
|
||||
<string name="pref_summary_pebble_mtu_limit">Si tu Pebble 2/Pebble LE no funciona correctamente, prueba esta opción para limitar el MTU (rango válido 20–512)</string>
|
||||
<string name="pref_title_pebble_enable_applogs">Activar crear registros de la App del Reloj</string>
|
||||
<string name="pref_summary_pebble_enable_applogs">Producirá registros de las apps del reloj que Gadgetbridge guardará (necesita reconexión)</string>
|
||||
<string name="pref_title_pebble_reconnect_attempts">Intentos de reconexión</string>
|
||||
|
@ -168,7 +172,7 @@
|
|||
<string name="vibration_profile_medium">Medio</string>
|
||||
<string name="vibration_profile_long">Largo</string>
|
||||
<string name="vibration_profile_waterdrop">Muy largo</string>
|
||||
<string name="vibration_profile_ring">Ring</string>
|
||||
<string name="vibration_profile_ring">Timbre</string>
|
||||
<string name="vibration_profile_alarm_clock">Alarma</string>
|
||||
<string name="miband_prefs_vibration">Vibración</string>
|
||||
<string name="vibration_try">Probar</string>
|
||||
|
@ -206,7 +210,7 @@
|
|||
<string name="pbw_install_handler_unable_to_install">No se ha podido instalar el fichero: %1$s</string>
|
||||
<string name="pbw_install_handler_hw_revision_mismatch">No se puede instalar este firmware: no coincide con la revision hardware de tu Pebble.</string>
|
||||
<string name="installer_activity_wait_while_determining_status">Por favor, espera mientras se determina el estado de la instalación...</string>
|
||||
<string name="notif_battery_low_title">Batería baja del Gadget!</string>
|
||||
<string name="notif_battery_low_title">¡Batería baja del Gadget!</string>
|
||||
<string name="notif_battery_low_percent">A %1$s le queda: %2$s%% batería</string>
|
||||
<string name="notif_battery_low_bigtext_last_charge_time">Última carga: %s \n</string>
|
||||
<string name="notif_battery_low_bigtext_number_of_charges">Número de cargas: %s</string>
|
||||
|
@ -217,13 +221,13 @@
|
|||
<string name="fwapp_install_device_not_ready">El archivo no puede ser instalado, el dispositivo no está listo.</string>
|
||||
<string name="miband_installhandler_miband_firmware">Miband firmware %1$s</string>
|
||||
<string name="miband_fwinstaller_compatible_version">Versión compatible</string>
|
||||
<string name="miband_fwinstaller_untested_version">Versión no probada!</string>
|
||||
<string name="miband_fwinstaller_untested_version">¡Versión no probada!</string>
|
||||
<string name="fwappinstaller_connection_state">Conexión al dispositivo: %1$s</string>
|
||||
<string name="pbw_installhandler_pebble_firmware">Pebble firmware %1$s</string>
|
||||
<string name="pbwinstallhandler_correct_hw_revision">Revisión de hardware correcta</string>
|
||||
<string name="pbwinstallhandler_incorrect_hw_revision">La revisión de hardware es incorrecta!</string>
|
||||
<string name="pbwinstallhandler_incorrect_hw_revision">¡La versión de hardware es incorrecta!</string>
|
||||
<string name="pbwinstallhandler_app_item">%1$s (%2$s)</string>
|
||||
<string name="updatefirmwareoperation_updateproblem_do_not_reboot">Hubo un problema con la transferencia de firmware. NO REINICIES tu Mi Band!</string>
|
||||
<string name="updatefirmwareoperation_updateproblem_do_not_reboot">Hubo un problema con la transferencia de firmware. ¡NO REINICIES tu Mi Band!</string>
|
||||
<string name="updatefirmwareoperation_metadata_updateproblem">Hubo un problema con la transferencia de metadatos del firmware</string>
|
||||
<string name="updatefirmwareoperation_update_complete">Instalación del firmware completa</string>
|
||||
<string name="updatefirmwareoperation_update_complete_rebooting">Instalación del firmware completa, reiniciando dispositivo...</string>
|
||||
|
@ -282,7 +286,7 @@
|
|||
<string name="title_activity_onboarding">Importar Base de Datos</string>
|
||||
<string name="import_old_db_buttonlabel">Importar datos de actividad antiguos</string>
|
||||
<string name="import_old_db_information">Desde Gadgetbridge 0.12.0 usamos un nuevo formato de base de datos.
|
||||
Se pueden importar los antiguos datos de actividad y asociarlos con el dispoditivo al que se está conectando (%1$s).\n
|
||||
Se pueden importar los antiguos datos de actividad y asociarlos con el dispositivo al que se está conectando (%1$s).\n
|
||||
\n
|
||||
Si no importas los antiguos datos de actividad ahora, siempre lo podrás hacer después seleccionando \"MERGE OLD ACTIVITY DATA\" en el apartado de gestión de base de datos de actividad.\n
|
||||
\n
|
||||
|
@ -301,17 +305,17 @@ Por favor, ten en cuenta que puedes importar datos desde Mi Band, Pebble Health
|
|||
<string name="dbmanagementactivity_overwrite_database_confirmation">¿Quiere sobreescribir la base de datos actual? Todos sus datos actuales (si los hay) se borrarán.</string>
|
||||
<string name="dbmanagementactivity_import_successful">Importado con éxito.</string>
|
||||
<string name="dbmanagementactivity_error_importing_db">Error importando DB: %1$s</string>
|
||||
<string name="dbmanagementactivity_no_old_activitydatabase_found">No se ha encontrado una Base de Datos con actividad antigua, no se importará nada.</string>
|
||||
<string name="dbmanagementactivity_no_connected_device">No hay ningún dispositivo conectado al que asociar la Base de Datos antigua.</string>
|
||||
<string name="dbmanagementactivity_merging_activity_data_title">Uniendo los datos de actividad</string>
|
||||
<string name="dbmanagementactivity_no_old_activitydatabase_found">No se ha encontrado una base de datos con actividad antigua, no se importará nada.</string>
|
||||
<string name="dbmanagementactivity_no_connected_device">No hay ningún dispositivo conectado al que asociar la base de datos antigua.</string>
|
||||
<string name="dbmanagementactivity_merging_activity_data_title">Fusionando los datos de actividad</string>
|
||||
<string name="dbmanagementactivity_please_wait_while_merging">Por favor, espere mientras se unen las bases de datos.</string>
|
||||
<string name="dbmanagementactivity_error_importing_old_activity_data">Error importando los datos antiguos a la nueva Base de Datos.</string>
|
||||
<string name="dbmanagementactivity_error_importing_old_activity_data">Error importando los datos antiguos a la nueva base de datos.</string>
|
||||
<string name="dbmanagementactivity_associate_old_data_with_device">Asociar los datos antiguos al dispositivo</string>
|
||||
<string name="dbmanagementactivity_delete_activity_data_title">¿Quiere borrar los datos de actividad?</string>
|
||||
<string name="dbmanagementactivity_really_delete_entire_db">¿Quiere borrar la base de datos? Todos sus datos de actividad y la información sobre sus dispositivos se borrarán.</string>
|
||||
<string name="dbmanagementactivity_delete_activity_data_title">¿Quieres borrar los datos de actividad?</string>
|
||||
<string name="dbmanagementactivity_really_delete_entire_db">¿Quieres borrar la base de datos? Todos tus datos de actividad y la información sobre tus dispositivos se borrarán.</string>
|
||||
<string name="dbmanagementactivity_database_successfully_deleted">Datos borrados.</string>
|
||||
<string name="dbmanagementactivity_db_deletion_failed">El borrado de la Base de Datos ha fallado.</string>
|
||||
<string name="dbmanagementactivity_delete_old_activity_db">¿Quieres borrar la antigua Base de Datos de Actividades?</string>
|
||||
<string name="dbmanagementactivity_db_deletion_failed">El borrado de la base de datos ha fallado.</string>
|
||||
<string name="dbmanagementactivity_delete_old_activity_db">¿Quieres borrar la antigua base de datos de actividades?</string>
|
||||
<string name="dbmanagementactivity_delete_old_activitydb_confirmation">¿Quiere borrar la base de datos antigua? Si los datos no se han importado, se perderán.</string>
|
||||
<string name="dbmanagementactivity_old_activity_db_successfully_deleted">Los datos antiguos han sido borrados.</string>
|
||||
<string name="dbmanagementactivity_old_activity_db_deletion_failed">El borrado de la Base de datos antiguos ha fallado.</string>
|
||||
|
@ -322,5 +326,5 @@ Por favor, ten en cuenta que puedes importar datos desde Mi Band, Pebble Health
|
|||
<string name="title_activity_vibration">Vibración</string>
|
||||
<!--Strings related to Pebble Pairing Activity-->
|
||||
<string name="title_activity_pebble_pairing">Emparejando con Pebble</string>
|
||||
<string name="pebble_pairing_hint">En su dispositivo Android va a aparecer un mensaje para emparejarse. Si no apareciera, mire en el cajón de notificaciones y acepte la propuesta de emparejamiento. Después acepte también en su Pebble.</string>
|
||||
<string name="pebble_pairing_hint">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.</string>
|
||||
</resources>
|
||||
|
|
|
@ -6,12 +6,13 @@
|
|||
<string name="action_debug">Déboguer</string>
|
||||
<string name="action_quit">Quitter</string>
|
||||
<string name="controlcenter_fetch_activity_data">Synchroniser</string>
|
||||
<string name="controlcenter_start_sleepmonitor">Moniteur de sommeil (ALPHA)</string>
|
||||
<string name="controlcenter_find_device">Trouver l\'appareil</string>
|
||||
<string name="controlcenter_start_sleepmonitor">Suivi du sommeil (ALPHA)</string>
|
||||
<string name="controlcenter_find_device">Retrouver un appareil perdu...</string>
|
||||
<string name="controlcenter_take_screenshot">Prendre une capture d\'écran</string>
|
||||
<string name="controlcenter_disconnect">Déconnexion</string>
|
||||
<string name="controlcenter_delete_device">Supprimer l\'appareil</string>
|
||||
<string name="controlcenter_delete_device_name">Supprimer %1$s</string>
|
||||
<string name="controlcenter_delete_device">Supprimer l’appareil</string>
|
||||
<string name="controlcenter_delete_device_name">Supprimer %1$s</string>
|
||||
<string name="controlcenter_delete_device_dialogmessage">Ceci va supprimer l’appareil et toutes les données associées !</string>
|
||||
<string name="title_activity_debug">Déboguer</string>
|
||||
<!--Strings related to AppManager-->
|
||||
<string name="title_activity_appmanager">Gestionnaire d\'application</string>
|
||||
|
@ -21,8 +22,11 @@
|
|||
<string name="appmananger_app_delete">Supprimer</string>
|
||||
<string name="appmananger_app_delete_cache">Supprimer et effacer du cache</string>
|
||||
<string name="appmananger_app_reinstall">Réinstaller</string>
|
||||
<string name="appmanager_app_openinstore">Rechercher dans le magasin d’application Pebble</string>
|
||||
<string name="appmanager_health_activate">Activer</string>
|
||||
<string name="appmanager_health_deactivate">Désactiver</string>
|
||||
<string name="appmanager_hrm_activate">Activer la mesure du rythme cardiaque</string>
|
||||
<string name="appmanager_hrm_deactivate">Désactiver la mesure du rythme cardiaque</string>
|
||||
<string name="app_configure">Configurer</string>
|
||||
<string name="app_move_to_top">Haut de page </string>
|
||||
<!--Strings related to AppBlacklist-->
|
||||
|
@ -32,7 +36,7 @@
|
|||
<string name="fw_upgrade_notice">Vous êtes sur le point d\'installer le micrologiciel %s à la place de celui qui est actuellement sur votre Mi Band.</string>
|
||||
<string name="fw_multi_upgrade_notice">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.</string>
|
||||
<string name="miband_firmware_known">Ce micrologiciel a été testé et est connu pour être compatible avec Gadgetbridge.</string>
|
||||
<string name="miband_firmware_unknown_warning">Ce micrologiciel n\'a pas été testé et peut ne pas être compatible avec Gadgetbridge.\n\nIl n\'est pas conseillé de flasher votre Mi Band.</string>
|
||||
<string name="miband_firmware_unknown_warning">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.</string>
|
||||
<string name="miband_firmware_suggest_whitelist">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</string>
|
||||
<!--Strings related to Settings-->
|
||||
<string name="title_activity_settings">Paramètres</string>
|
||||
|
@ -51,47 +55,53 @@
|
|||
<string name="pref_header_notifications">Notifications</string>
|
||||
<string name="pref_title_notifications_repetitions">Répétitions</string>
|
||||
<string name="pref_title_notifications_call">Appels téléphoniques</string>
|
||||
<string name="pref_title_notifications_sms">SMS</string>
|
||||
<string name="pref_title_notifications_sms">Textos</string>
|
||||
<string name="pref_title_notifications_k9mail">K9-Mail</string>
|
||||
<string name="pref_title_notifications_pebblemsg">Messages Pebble</string>
|
||||
<string name="pref_summary_notifications_pebblemsg">Support des applications qui envoient des notification à Pebble par PebbleKit.</string>
|
||||
<string name="pref_title_notifications_generic">Support des notifications génériques</string>
|
||||
<string name="pref_title_whenscreenon">... y compris quand l\'écran est allumé</string>
|
||||
<string name="pref_title_notification_filter">Ne Pas Déranger</string>
|
||||
<string name="pref_summary_notification_filter">Arrêter l’envoie des Notification non-désirée en mode Ne Pas Déranger.</string>
|
||||
<string name="pref_summary_notification_filter">Arrêter l’envoi des notifications non-désirées en mode Ne Pas Déranger.</string>
|
||||
<string name="always">toujours</string>
|
||||
<string name="when_screen_off">quand l\'écran est éteint</string>
|
||||
<string name="never">jamais</string>
|
||||
<string name="pref_blacklist">Applications bloquées</string>
|
||||
<string name="pref_header_cannned_messages">Modèles de messages</string>
|
||||
<string name="pref_title_canned_replies">Réponses</string>
|
||||
<string name="pref_title_canned_reply_suffix">Suffixe commun</string>
|
||||
<string name="pref_title_canned_reply_suffix">Suffixe fréquent</string>
|
||||
<string name="pref_title_canned_messages_dismisscall">Raccrocher</string>
|
||||
<string name="pref_title_canned_messages_set">Mise à jour Pebble</string>
|
||||
<string name="pref_header_development">Options développeur</string>
|
||||
<string name="pref_title_development_miaddr">Adresse Mi Band</string>
|
||||
<string name="pref_title_pebble_settings">Paramètres Pebble</string>
|
||||
<string name="pref_header_activitytrackers">Traqueur d\'activité</string>
|
||||
<string name="pref_header_activitytrackers">Traqueurs d\'activité</string>
|
||||
<string name="pref_title_pebble_activitytracker">Traqueur d\'activité préféré</string>
|
||||
<string name="pref_title_pebble_sync_health">Synchroniser Pebble Health</string>
|
||||
<string name="pref_title_pebble_sync_misfit">Synchroniser Misfit</string>
|
||||
<string name="pref_title_pebble_sync_morpheuz">Synchroniser Morpheuz</string>
|
||||
<string name="pref_title_enable_pebblekit">Permettre l\'accès d\'applications tierces Android</string>
|
||||
<string name="pref_title_enable_pebblekit">Permettre l\'accès aux applications tierces Android</string>
|
||||
<string name="pref_summary_enable_pebblekit">Activer le support expérimental pour les applications Android utilisant PebbleKit</string>
|
||||
<string name="pref_title_sunrise_sunset">Lever et coucher de soleil</string>
|
||||
<string name="pref_summary_sunrise_sunset">Envoyer heures de lever et coucher du soleil dans la timeline Pebble en fonction de l\'emplacement</string>
|
||||
<string name="pref_summary_sunrise_sunset">Envoyer les heures de lever et coucher du soleil dans l’historique Pebble en fonction de l\'emplacement</string>
|
||||
<string name="pref_header_location">Emplacement</string>
|
||||
<string name="pref_title_location_aquire">Obtenir l\'emplacement</string>
|
||||
<string name="pref_title_location_latitude">Latitude</string>
|
||||
<string name="pref_title_location_longitude">Longitude</string>
|
||||
<string name="pref_title_location_keep_uptodate">Garder l\'emplacement à jour</string>
|
||||
<string name="pref_summary_location_keep_uptodate">Tenter d\'obtenir la localisation pendant la course à pied, utiliser la localisation enregistré en cas de problème.</string>
|
||||
<string name="toast_enable_networklocationprovider">Activez la localisation réseau s\'il vous plaît</string>
|
||||
<string name="pref_title_location_keep_uptodate">Garder l’emplacement à jour</string>
|
||||
<string name="pref_summary_location_keep_uptodate">Essayer de garder la localisation à jour pendant le fonctionnement, sinon utiliser l’emplacement enregistré.</string>
|
||||
<string name="toast_enable_networklocationprovider">Veuillez activer la localisation réseau</string>
|
||||
<string name="toast_aqurired_networklocation">Emplacement obtenu</string>
|
||||
<string name="pref_title_pebble_forceprotocol">Protocole des notifications en vigueur</string>
|
||||
<string name="pref_title_pebble_forceprotocol">Forcer le protocole de notification</string>
|
||||
<string name="pref_summary_pebble_forceprotocol">Cette option force l\'utilisation du plus récent protocole de notification qui dépend de la version du micrologiciel. ACTIVEZ-LA UNIQUEMENT SI VOUS SAVEZ CE QUE VOUS FAITES!</string>
|
||||
<string name="pref_title_pebble_forceuntested">Activer les fonctionnalités non-testées</string>
|
||||
<string name="pref_summary_pebble_forceuntested">Activer les fonctionnalités non-testées. ACTIVEZ UNIQUEMENT SI VOUS SAVEZ CE QUE VOUS FAITES!</string>
|
||||
<string name="pref_title_pebble_forcele">Toujours préférer le BLE</string>
|
||||
<string name="pref_summary_pebble_forcele">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</string>
|
||||
<string name="pref_title_pebble_mtu_limit">Limite du GATT MTU de Pebble 2/LE</string>
|
||||
<string name="pref_summary_pebble_mtu_limit">Si votre Pebble 2/LE ne fonctionne pas correctement, essayez d\'activer cette option pour limiter le MTU (plage valide 20-512)</string>
|
||||
<string name="pref_title_pebble_enable_applogs">Activer les logs des Watch App</string>
|
||||
<string name="pref_summary_pebble_enable_applogs">Ceci permettra à Gadgetbridge de conserver les logs des Watch App (requiert une reconnexion)</string>
|
||||
<string name="pref_title_pebble_reconnect_attempts">Tentatives de reconnexion</string>
|
||||
<string name="not_connected">non connecté</string>
|
||||
<string name="connecting">connexion en cours</string>
|
||||
|
@ -106,29 +116,33 @@
|
|||
<string name="bluetooth_is_not_supported_">Le Bluetooth n\'est pas supporté.</string>
|
||||
<string name="bluetooth_is_disabled_">Le Bluetooth est désactivé.</string>
|
||||
<string name="tap_connected_device_for_app_mananger">Cliquez sur l\'appareil pour ouvrir le gestionnaire d\'application</string>
|
||||
<string name="tap_connected_device_for_activity">Cliquez sur l\'appareil pour ouvrir l\'activité</string>
|
||||
<string name="tap_connected_device_for_activity">Cliquez sur l\'appareil pour ouvrir le gestionnaire d’activité</string>
|
||||
<string name="tap_connected_device_for_vibration">Cliquez sur connecter pour envoyer une vibration</string>
|
||||
<string name="tap_a_device_to_connect">Tapotter sur le périphérique pour le connecter.</string>
|
||||
<string name="cannot_connect_bt_address_invalid_">Connexion impossible. L’adresse Bluetooth est-elle invalide? </string>
|
||||
<string name="cannot_connect_bt_address_invalid_">Connexion impossible. L’adresse Bluetooth est-elle valide? </string>
|
||||
<string name="gadgetbridge_running">Gadgetbridge est en fonctionnement</string>
|
||||
<string name="installing_binary_d_d">Installation du binaire %1$d/%2$d</string>
|
||||
<string name="installation_failed_">échec d\'installation!</string>
|
||||
<string name="installation_successful">Installation réalisé</string>
|
||||
<string name="installing_binary_d_d">Installation du fichier %1$d/%2$d</string>
|
||||
<string name="installation_failed_">échec de l\'installation !</string>
|
||||
<string name="installation_successful">Installation réalisée avec succès</string>
|
||||
<string name="firmware_install_warning">VOUS TENTEZ D\'INSTALLER UN MICROLOGICIEL, PROCÉDEZ À VOS PROPRES RISQUES.\n\n\nCe micrologiciel est pour la version de matériel: %s</string>
|
||||
<string name="app_install_info">Vous êtes sur le point d\'installer l\'application suivante:\n\n\n%1$s Version %2$s par %3$s\n</string>
|
||||
<string name="n_a">N.D.</string>
|
||||
<string name="initialized">Initialisé</string>
|
||||
<string name="appversion_by_creator">%1$s par %2$s</string>
|
||||
<string name="title_activity_discovery">Découvrir les appareils</string>
|
||||
<string name="discovery_stop_scanning">Arrêter le balayage</string>
|
||||
<string name="discovery_start_scanning">Démarrer le balayage</string>
|
||||
<string name="title_activity_discovery">Scanner les appareils</string>
|
||||
<string name="discovery_stop_scanning">Arrêter le scan</string>
|
||||
<string name="discovery_start_scanning">Démarrer le scan</string>
|
||||
<string name="action_discover">Connecter un nouvel appareil</string>
|
||||
<string name="device_with_rssi">%1$s (%2$s)</string>
|
||||
<string name="title_activity_android_pairing">Coupler l\'appareil</string>
|
||||
<string name="android_pairing_hint">Utiliser le couplement Bluetooth d\'Android pour coupler l\'appareil</string>
|
||||
<string name="title_activity_mi_band_pairing">Coupler votre Mi Band</string>
|
||||
<string name="pairing">Coupler avec %s...</string>
|
||||
<string name="message_cannot_pair_no_mac">Aucune adresse mac fournie, ne peut être couplé</string>
|
||||
<string name="title_activity_android_pairing">Appairer l\'appareil</string>
|
||||
<string name="android_pairing_hint">Utiliser l’appairage Bluetooth d\'Android pour appairer l\'appareil</string>
|
||||
<string name="title_activity_mi_band_pairing">Appairer votre Mi Band</string>
|
||||
<string name="pairing">Appairage avec %s...</string>
|
||||
<string name="pairing_creating_bond_with">Création d’un lien avec %1$s (%2$s)</string>
|
||||
<string name="pairing_unable_to_pair_with">Impossible se s’appairer avec %1$s (%2$s)</string>
|
||||
<string name="pairing_in_progress">Création du lien en cours : %1$s (%2$s)</string>
|
||||
<string name="pairing_already_bonded">Déjà lié avec %1$s (%2$s), connexion...</string>
|
||||
<string name="message_cannot_pair_no_mac">Aucune adresse MAC fournie, ne peut être appairé</string>
|
||||
<string name="preferences_category_device_specific_settings">Paramètres spécifiques à l\'appareil </string>
|
||||
<string name="preferences_miband_settings">Paramètres Mi Band</string>
|
||||
<string name="male">Homme</string>
|
||||
|
@ -139,7 +153,7 @@
|
|||
<string name="miband_pairing_using_dummy_userdata">Aucune donnée utilisateur valide fournie, utilisation de données fictives pour le moment</string>
|
||||
<string name="miband_pairing_tap_hint">Quand votre Mi Band vibre et clignote, appuyez dessus plusieurs fois d\'affilée.</string>
|
||||
<string name="appinstaller_install">Installer</string>
|
||||
<string name="discovery_connected_devices_hint">Rendre votre montre découvrable. Pour l\'instant les appareils connectés ne seront probablement pas découvert. Si votre montre n’apparaît pas après 2 minutes, essayer à nouveau après avoir redémarré.</string>
|
||||
<string name="discovery_connected_devices_hint">Mettez votre appareil en mode visible. Les appareils déjà connectés ne sont pas visibles. Sur Android 6 ou supérieur, vous devez activer la localisation (ex. GPS). Si votre appareil n\'est pas visible après 2 minutes, réessayez après avoir redémarré votre téléphone.</string>
|
||||
<string name="discovery_note">Note:</string>
|
||||
<string name="candidate_item_device_image">Image de l\'appareil</string>
|
||||
<string name="miband_prefs_alias">Nom/Pseudo</string>
|
||||
|
@ -149,7 +163,7 @@
|
|||
<string name="initializing">Initialisation</string>
|
||||
<string name="busy_task_fetch_activity_data">Récupération des données d\'activité</string>
|
||||
<string name="sleep_activity_date_range">De %1$s à %2$s</string>
|
||||
<string name="miband_prefs_wearside">Côté de port du bracelet</string>
|
||||
<string name="miband_prefs_wearside">Port main gauche ou droite?</string>
|
||||
<string name="pref_screen_vibration_profile">Profil de vibration</string>
|
||||
<string name="vibration_profile_staccato">Saccadé</string>
|
||||
<string name="vibration_profile_short">Court</string>
|
||||
|
@ -159,15 +173,15 @@
|
|||
<string name="vibration_profile_ring">Sonnette</string>
|
||||
<string name="vibration_profile_alarm_clock">Réveil</string>
|
||||
<string name="miband_prefs_vibration">Vibration</string>
|
||||
<string name="pref_screen_notification_profile_sms">Notification SMS</string>
|
||||
<string name="pref_screen_notification_profile_generic_chat">Clavardage (Chat)</string>
|
||||
<string name="pref_screen_notification_profile_generic_navigation">Navigation</string>
|
||||
<string name="pref_screen_notification_profile_generic_social">Réseaux sociaux</string>
|
||||
<string name="vibration_try">Essayer</string>
|
||||
<string name="pref_screen_notification_profile_sms">Notification Texto</string>
|
||||
<string name="pref_header_vibration_settings">Paramètres des vibrations</string>
|
||||
<string name="pref_screen_notification_profile_generic">Notification générique</string>
|
||||
<string name="pref_screen_notification_profile_pebblemsg">Notification Pebble</string>
|
||||
<string name="pref_screen_notification_profile_email">Notification e-mail</string>
|
||||
<string name="pref_screen_notification_profile_email">Notification des Mails</string>
|
||||
<string name="pref_screen_notification_profile_incoming_call">Notification d\'appels entrants</string>
|
||||
<string name="pref_screen_notification_profile_generic_chat">Tchat</string>
|
||||
<string name="pref_screen_notification_profile_generic_navigation">Navigation</string>
|
||||
<string name="pref_screen_notification_profile_generic_social">Réseau social</string>
|
||||
<string name="control_center_find_lost_device">Trouver l\'appareil perdu</string>
|
||||
<string name="control_center_cancel_to_stop_vibration">Annuler pour arrêter les vibrations</string>
|
||||
<string name="title_activity_charts">Votre activité</string>
|
||||
|
@ -193,7 +207,7 @@
|
|||
<string name="installer_activity_unable_to_find_handler">Impossible de trouver un gestionnaire pour installer ce fichier.</string>
|
||||
<string name="pbw_install_handler_unable_to_install">Impossible d\'installer le ficher suivant: %1$s</string>
|
||||
<string name="pbw_install_handler_hw_revision_mismatch">Impossible d\'installer le micrologiciel spécifié: il ne correspond pas à la version du matériel de votre Pebble.</string>
|
||||
<string name="installer_activity_wait_while_determining_status">S\'il vous plait patientez pendant la détermination de l\'état de l\'installation...</string>
|
||||
<string name="installer_activity_wait_while_determining_status">Veuillez patienter pendant la détermination de l\'état de l\'installation...</string>
|
||||
<string name="notif_battery_low_title">Niveau de batterie faible!</string>
|
||||
<string name="notif_battery_low_percent">%1$s batterie restante: %2$s%%</string>
|
||||
<string name="notif_battery_low_bigtext_last_charge_time">Dernière charge: %s \n</string>
|
||||
|
@ -218,7 +232,7 @@
|
|||
<string name="updatefirmwareoperation_write_failed">Échec lors de l\'écriture du micrologiciel</string>
|
||||
<string name="chart_steps">Pas</string>
|
||||
<string name="liveactivity_live_activity">Activité en direct</string>
|
||||
<string name="weeksteps_today_steps_description">Nombre de pas aujourd\'hui, objectif : %1$s</string>
|
||||
<string name="weeksteps_today_steps_description">Nombre de pas aujourd\'hui, objectif: %1$s</string>
|
||||
<string name="pref_title_dont_ack_transfer">Ne pas confirmer le transfert de données d\'activités</string>
|
||||
<string name="pref_summary_dont_ack_transfers">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.</string>
|
||||
<string name="pref_summary_keep_data_on_device">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.</string>
|
||||
|
@ -241,11 +255,11 @@
|
|||
<string name="miband_prefs_reserve_alarm_calendar">Alarmes à réserver pour événements futurs</string>
|
||||
<string name="miband_prefs_hr_sleep_detection">Utiliser le capteur cardiaque pour améliorer la précision du sommeil</string>
|
||||
<string name="miband_prefs_device_time_offset_hours">La compensation de temps en heure (pour détecter le sommeil de travailleurs en rotation, par exemple)</string>
|
||||
<string name="miband2_prefs_dateformat">Mi band 2 : format de l\'heure</string>
|
||||
<string name="dateformat_time">Heure seule</string>
|
||||
<string name="dateformat_date_time"><![CDATA[Heure & date]]></string>
|
||||
<string name="mi2_prefs_activate_display_on_lift">Allumer quand le poignet se lève</string>
|
||||
<string name="FetchActivityOperation_about_to_transfer_since">About to transfer data since %1$s</string>
|
||||
<string name="miband2_prefs_dateformat">Mi2 : Format de la date</string>
|
||||
<string name="dateformat_time">Heure</string>
|
||||
<string name="dateformat_date_time"><![CDATA[Time & Date]]></string>
|
||||
<string name="mi2_prefs_activate_display_on_lift">Allumer l\'écran lors d\'un mouvement</string>
|
||||
<string name="FetchActivityOperation_about_to_transfer_since">Sur le point de transférer des données depuis %1$s</string>
|
||||
<string name="waiting_for_reconnect">en attente de reconnexion</string>
|
||||
<string name="activity_prefs_about_you">A propos de vous</string>
|
||||
<string name="activity_prefs_year_birth">Année de naissance</string>
|
||||
|
@ -256,7 +270,7 @@
|
|||
<string name="authentication_required">authentification requise</string>
|
||||
<string name="appwidget_text">ZzZz</string>
|
||||
<string name="add_widget">Ajouter un widget</string>
|
||||
<string name="activity_prefs_sleep_duration">Durée préférée de sommeil en heures</string>
|
||||
<string name="activity_prefs_sleep_duration">Préférer le mode heure pendant le sommeil</string>
|
||||
<string name="appwidget_alarms_set">Une alarme a été enregistré pour %1$02d:%2$02d</string>
|
||||
<string name="device_hw">Modèle: %1$s</string>
|
||||
<string name="device_fw">Micrologiciel: %1$s</string>
|
||||
|
@ -304,11 +318,14 @@ Si vous avez déjà importé vos données et êtes satisfait du résultat, vous
|
|||
<string name="dbmanagementactivity_db_deletion_failed">Échec de la destruction de la base de donnée.</string>
|
||||
<string name="dbmanagementactivity_delete_old_activity_db">Voulez vous détruire les anciennes activités de la base ?</string>
|
||||
<string name="dbmanagementactivity_delete_old_activitydb_confirmation">Voulez vous vraiment détruire entièrement la base de donnée ? Toutes vos données non importé seront perdu.</string>
|
||||
<string name="dbmanagementactivity_old_activity_db_successfully_deleted">Les ancienne données d\'activité ont été effacés correctement.</string>
|
||||
<string name="dbmanagementactivity_old_activity_db_successfully_deleted">Les anciennes données d\'activité ont été effacées correctement.</string>
|
||||
<string name="dbmanagementactivity_old_activity_db_deletion_failed">Échec de la destruction de l\'ancienne base de donnée.</string>
|
||||
<string name="dbmanagementactivity_overwrite">Écraser</string>
|
||||
<string name="Cancel">Annuler</string>
|
||||
<string name="Delete">Supprimer</string>
|
||||
<!--Strings related to Vibration Activity-->
|
||||
<string name="title_activity_vibration">Vibration</string>
|
||||
<!--Strings related to Pebble Pairing Activity-->
|
||||
<string name="title_activity_pebble_pairing">Appairage avec une Pebble</string>
|
||||
<string name="pebble_pairing_hint">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.</string>
|
||||
</resources>
|
||||
|
|
|
@ -138,7 +138,6 @@
|
|||
<string name="miband_pairing_using_dummy_userdata">Dati dell\'utente non inseriti, vengono usati dati d\'esempio.</string>
|
||||
<string name="miband_pairing_tap_hint">Quando la Mi Band vibra e lampeggia, dalle qualche leggero colpetto.</string>
|
||||
<string name="appinstaller_install">Installa</string>
|
||||
<string name="discovery_connected_devices_hint">Imposta il tuo dispositivo perchè sia rilevabile. I dispositivi attualmente connessi non saranno probabilmente rilevati. Se non vedi il tuo dispositivo entro un paio di minuti, riprova dopo avere riavviato il dispositivo Android.</string>
|
||||
<string name="discovery_note">Nota:</string>
|
||||
<string name="candidate_item_device_image">Immagine dispositivo</string>
|
||||
<string name="miband_prefs_alias">Nome / Soprannome</string>
|
||||
|
@ -299,4 +298,5 @@ Si possono importare i dati da Mi Band, Pebble Health e Morpheuz, NON quelli di
|
|||
<string name="Delete">Cancella</string>
|
||||
<!--Strings related to Vibration Activity-->
|
||||
<string name="title_activity_vibration">Vibrazione</string>
|
||||
<!--Strings related to Pebble Pairing Activity-->
|
||||
</resources>
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
<string name="appmanager_health_deactivate">非アクティベート</string>
|
||||
<string name="appmanager_hrm_activate">HRM をアクティベート</string>
|
||||
<string name="appmanager_hrm_deactivate">HRM を非アクティベート</string>
|
||||
<string name="appmanager_weather_activate">システムの天気アプリを有効にする</string>
|
||||
<string name="appmanager_weather_deactivate">システムの天気アプリを無効にする</string>
|
||||
<string name="app_configure">設定</string>
|
||||
<string name="app_move_to_top">先頭に移動</string>
|
||||
<!--Strings related to AppBlacklist-->
|
||||
|
@ -98,6 +100,8 @@
|
|||
<string name="pref_summary_pebble_forceuntested">テストされていない機能を有効にします。何をしているかわかっている場合のみ有効にしてください!</string>
|
||||
<string name="pref_title_pebble_forcele">常に BLE を好みにする</string>
|
||||
<string name="pref_summary_pebble_forcele">すべてのPebbleに対して、BT クラシックではなく実験的なPebble LEサポートを使用します。非LEで一度接続された後に \"Pebble LE\" をペアリングする必要があります</string>
|
||||
<string name="pref_title_pebble_mtu_limit">Pebble 2/LE GATT MTU 制限</string>
|
||||
<string name="pref_summary_pebble_mtu_limit">Pebble 2/Pebble LE が期待どおりに機能しない場合は、この設定を試して MTU を制限してください (有効範囲 20-512)</string>
|
||||
<string name="pref_title_pebble_enable_applogs">ウォッチアプリのログ記録を有効にする</string>
|
||||
<string name="pref_summary_pebble_enable_applogs">Gadgetbridgeがウォッチアプリからログを記録するようにする (再接続が必要です)</string>
|
||||
<string name="pref_title_pebble_reconnect_attempts">再接続の試行</string>
|
||||
|
|
|
@ -108,7 +108,6 @@
|
|||
<string name="miband_pairing_using_dummy_userdata">올바르지 않은 사용자 정보입니다. 일단 임시 사용자 정보를 사용합니다.</string>
|
||||
<string name="miband_pairing_tap_hint">Mi Band가 진동하고 깜빡일 때, 연달아 몇 번 두드리세요.</string>
|
||||
<string name="appinstaller_install">설치</string>
|
||||
<string name="discovery_connected_devices_hint">기기를 발견 가능하도록 설정하세요. 현재 연결된 기기들은 발견될 수 없습니다. 2분이 지나도 기기가 나타나지 않는다면 재부팅 후 다시 시도해보세요.</string>
|
||||
<string name="discovery_note">알림: </string>
|
||||
<string name="candidate_item_device_image">기기 이미지</string>
|
||||
<string name="miband_prefs_alias">이름/별명</string>
|
||||
|
@ -131,8 +130,6 @@
|
|||
<string name="pref_screen_notification_profile_sms">SMS 알림</string>
|
||||
<string name="pref_header_vibration_settings">진동 설정</string>
|
||||
<string name="pref_screen_notification_profile_generic">일반 알림</string>
|
||||
<string name="pref_screen_notification_profile_pebblemsg">Pebble 알림</string>
|
||||
<string name="pref_screen_notification_profile_email">Mail 알림</string>
|
||||
<string name="pref_screen_notification_profile_incoming_call">걸려오는 전화 알림</string>
|
||||
<string name="control_center_find_lost_device">잃어버린 기기 찾기</string>
|
||||
<string name="control_center_cancel_to_stop_vibration">진동을 멈추려면 취소를 선택하세요.</string>
|
||||
|
@ -226,4 +223,6 @@
|
|||
<string name="live_activity_heart_rate">심박수</string>
|
||||
<!--Strings related to Onboading Activity-->
|
||||
<string name="Delete">삭제</string>
|
||||
<!--Strings related to Vibration Activity-->
|
||||
<!--Strings related to Pebble Pairing Activity-->
|
||||
</resources>
|
||||
|
|
|
@ -3,17 +3,32 @@
|
|||
<string name="app_name">Gadgetbridge</string>
|
||||
<string name="title_activity_controlcenter">Gadgetbridge</string>
|
||||
<string name="action_settings">Ustawienia</string>
|
||||
<string name="action_debug">Usuń błąd</string>
|
||||
<string name="action_debug">Debuguj</string>
|
||||
<string name="action_quit">Zakończ</string>
|
||||
<string name="controlcenter_fetch_activity_data">Synchronizuj</string>
|
||||
<string name="controlcenter_start_sleepmonitor">Monitor snu (ALPHA)</string>
|
||||
<string name="controlcenter_find_device">Odnajdź zagubione urządzenie</string>
|
||||
<string name="controlcenter_take_screenshot">Zrób printscreen</string>
|
||||
<string name="controlcenter_take_screenshot">Zrób screena</string>
|
||||
<string name="controlcenter_disconnect">Rozłącz</string>
|
||||
<string name="controlcenter_delete_device">Usuń urządzenie</string>
|
||||
<string name="controlcenter_delete_device_name">Usuń %1$s</string>
|
||||
<string name="controlcenter_delete_device_dialogmessage">To usunie urządzenie oraz zgromadzone dane</string>
|
||||
<string name="title_activity_debug">Usuń błąd</string>
|
||||
<!--Strings related to AppManager-->
|
||||
<string name="title_activity_appmanager">Zarządzanie aplikacjami</string>
|
||||
<string name="appmanager_cached_watchapps_watchfaces">Aplikacje w pamięci</string>
|
||||
<string name="appmanager_installed_watchapps">Zainstalowane aplikacje</string>
|
||||
<string name="appmanager_installed_watchfaces">Zainstalowane tarcze</string>
|
||||
<string name="appmananger_app_delete">Usuń</string>
|
||||
<string name="appmananger_app_delete_cache">Odinstaluj i usuń z pamięci</string>
|
||||
<string name="appmananger_app_reinstall">Zainstaluj ponownie</string>
|
||||
<string name="appmanager_app_openinstore">Szukaj w Pebble Appstore</string>
|
||||
<string name="appmanager_health_activate">Aktywuj</string>
|
||||
<string name="appmanager_health_deactivate">Deaktywuj</string>
|
||||
<string name="appmanager_hrm_activate">Aktywuj HRM</string>
|
||||
<string name="appmanager_hrm_deactivate">Deaktywuj HRM</string>
|
||||
<string name="app_configure">Konfiguruj</string>
|
||||
<string name="app_move_to_top">Przejdź do góry</string>
|
||||
<!--Strings related to AppBlacklist-->
|
||||
<string name="title_activity_appblacklist">Czarna lista powiadomień</string>
|
||||
<!--Strings related to FwAppInstaller-->
|
||||
|
@ -26,11 +41,16 @@
|
|||
<string name="title_activity_settings">Ustawienia</string>
|
||||
<string name="pref_header_general">Ustawienia ogólne</string>
|
||||
<string name="pref_title_general_autoconnectonbluetooth">Połącz z urządzeniem gdy Bluetooth jest włączone</string>
|
||||
<string name="pref_title_general_autocreonnect">Łącz automatycznie</string>
|
||||
<string name="pref_title_audo_player">Domyślny odtwarzacz muzyki</string>
|
||||
<string name="pref_default">Domyślny</string>
|
||||
<string name="pref_header_datetime">Data i godzina</string>
|
||||
<string name="pref_title_datetime_syctimeonconnect">Synchronizuj czas</string>
|
||||
<string name="pref_summary_datetime_syctimeonconnect">Synchronizuj czas urządzenia podczas połączenia gdy czas lub strefa czasowa zmienia się na Androidzie</string>
|
||||
<string name="pref_title_theme">Motyw</string>
|
||||
<string name="pref_theme_light">Jasny</string>
|
||||
<string name="pref_theme_dark">Ciemny</string>
|
||||
<string name="pref_title_language">Język</string>
|
||||
<string name="pref_header_notifications">Powiadomienia</string>
|
||||
<string name="pref_title_notifications_repetitions">Powtórzenia</string>
|
||||
<string name="pref_title_notifications_call">Połączenia</string>
|
||||
|
@ -39,19 +59,41 @@
|
|||
<string name="pref_title_notifications_pebblemsg">Wiadomości Pebble</string>
|
||||
<string name="pref_title_notifications_generic">Obsługa ogólnych powiadomień</string>
|
||||
<string name="pref_title_whenscreenon">... także gdy ekran jest włączony</string>
|
||||
<string name="pref_title_notification_filter">Nie przeszkadzaj</string>
|
||||
<string name="always">zawsze</string>
|
||||
<string name="when_screen_off">gdy ekran jest wyłączony</string>
|
||||
<string name="never">nigdy</string>
|
||||
<string name="pref_blacklist">Czarna lista aplikacji</string>
|
||||
<string name="pref_header_cannned_messages">Wiadomości zwrotne</string>
|
||||
<string name="pref_title_canned_replies">Odpowiedzi</string>
|
||||
<string name="pref_title_canned_messages_set">Uaktualnij na Pebble</string>
|
||||
<string name="pref_header_development">Ustawienia programisty</string>
|
||||
<string name="pref_title_development_miaddr">Adres Mi Band</string>
|
||||
<string name="pref_title_pebble_settings">Ustawienia Pebble</string>
|
||||
<string name="pref_header_activitytrackers">Monitory aktywności</string>
|
||||
<string name="pref_title_pebble_activitytracker">Preferowany monitor</string>
|
||||
<string name="pref_title_pebble_sync_health">Synchronizuj Pebble Health</string>
|
||||
<string name="pref_title_pebble_sync_misfit">Synchronizuj Misfit</string>
|
||||
<string name="pref_title_pebble_sync_morpheuz">Synchronizuj Morpheuz</string>
|
||||
<string name="pref_title_enable_pebblekit">Zezwól zewnętrznym aplikacjom Android na dostęp</string>
|
||||
<string name="pref_summary_enable_pebblekit">Włącz eksperymentalną obsługę aplikacji android przez PebbleKit</string>
|
||||
<string name="pref_title_sunrise_sunset">Wschód i zachód</string>
|
||||
<string name="pref_summary_sunrise_sunset">Wyślij wschód i zachód do linii czasu Pebble bazując na lokalizacji</string>
|
||||
<string name="pref_header_location">Lokalizacja</string>
|
||||
<string name="pref_title_location_aquire">Otrzymaj lokalizację</string>
|
||||
<string name="pref_title_location_latitude">Szerokość</string>
|
||||
<string name="pref_title_location_longitude">Długość</string>
|
||||
<string name="pref_title_location_keep_uptodate">Utrzymuj aktualną lokalizację</string>
|
||||
<string name="toast_enable_networklocationprovider">Włącz usługę lokalizacji</string>
|
||||
<string name="toast_aqurired_networklocation">Lokalizacja otrzymana</string>
|
||||
<string name="pref_title_pebble_forceprotocol">Wymuś protokół komunikacji</string>
|
||||
<string name="pref_summary_pebble_forceprotocol">Ta opcja wymusza użycie najnowszego protokołu powiadomień w zależności od wersji firmware. WŁĄCZ JEDYNIE JEŚLI WIESZ CO ROBISZ!</string>
|
||||
<string name="pref_title_pebble_forceuntested">Włącz nietestowane funkcje</string>
|
||||
<string name="pref_summary_pebble_forceuntested">Włącz nie testowane funkcje. WŁĄCZ JEDYNIE JEŚLI WIESZ CO ROBISZ!</string>
|
||||
<string name="pref_title_pebble_forcele">Preferuj BLE</string>
|
||||
<string name="pref_title_pebble_mtu_limit">Pebble 2/LE GATT limit MTU</string>
|
||||
<string name="pref_summary_pebble_mtu_limit">Jeśli Twój Pebble 2/ Pebble LE nie działa jak należy spróbuj ustawić ten limit MTU (zakres 20-512)</string>
|
||||
<string name="pref_title_pebble_enable_applogs">Włącz logowanie aplikacji</string>
|
||||
<string name="pref_title_pebble_reconnect_attempts">Próby ponownego połączenia</string>
|
||||
<string name="not_connected">nie połączony</string>
|
||||
<string name="connecting">łącze</string>
|
||||
|
@ -65,6 +107,8 @@
|
|||
<string name="this_is_a_test_notification_from_gadgetbridge">To jest testowe powiadomienie z Gadgetbridge</string>
|
||||
<string name="bluetooth_is_not_supported_">Bluetooth nie jest obsługiwane</string>
|
||||
<string name="bluetooth_is_disabled_">Bluetooth jest wyłączone</string>
|
||||
<string name="tap_connected_device_for_app_mananger">Tapnij urządzenie aby uruchomić menadżer aplikacji</string>
|
||||
<string name="tap_a_device_to_connect">Dotknij urządzenie aby połączyć</string>
|
||||
<string name="cannot_connect_bt_address_invalid_">Nie można połączyć. Adres BT nieprawidłowy?</string>
|
||||
<string name="gadgetbridge_running">Gadgetbridge działa</string>
|
||||
<string name="installing_binary_d_d">Instalowanie binarki %1$d/%2$d</string>
|
||||
|
@ -116,9 +160,10 @@
|
|||
<string name="pref_screen_notification_profile_sms">Powiadomienie SMS</string>
|
||||
<string name="pref_header_vibration_settings">Ustawienia wibracji</string>
|
||||
<string name="pref_screen_notification_profile_generic">Ogólne powiadomienia</string>
|
||||
<string name="pref_screen_notification_profile_pebblemsg">Powiadomienia Pebble</string>
|
||||
<string name="pref_screen_notification_profile_email">Powiadomienia email</string>
|
||||
<string name="pref_screen_notification_profile_incoming_call">Powiadomienia o połaczeniach przychodzących</string>
|
||||
<string name="pref_screen_notification_profile_generic_navigation">Nawigacja</string>
|
||||
<string name="pref_screen_notification_profile_generic_social">Sieć spolecznościowa</string>
|
||||
<string name="control_center_find_lost_device">Odnajdź zagubione urządzenie</string>
|
||||
<string name="control_center_cancel_to_stop_vibration">Anuluj by przerwać wibracje.</string>
|
||||
<string name="title_activity_charts">Twoja aktywność</string>
|
||||
|
@ -173,6 +218,7 @@
|
|||
<string name="pref_title_dont_ack_transfer">Nie wysyłaj danych aktywności</string>
|
||||
<string name="pref_summary_dont_ack_transfers">Gdy dane aktywności nie są przesłane na opaskę, wtedy nie będą usuwane. Przydatne gdy Gadgetbridge jest używany wraz z innymi aplikacjami</string>
|
||||
<string name="pref_summary_keep_data_on_device">Dane aktywności będą zachowane na Mi Band nawet po synchronizacji. Przydatne gdy Gadgetbridge jest używany z innymi aplikacjami.</string>
|
||||
<string name="pref_summary_low_latency_fw_update">To może pomóc na urządzeniach gdzie uaktualnienie kończy się błędem</string>
|
||||
<string name="live_activity_steps_history">Historia kroków</string>
|
||||
<string name="live_activity_current_steps_per_minute">Aktualnie kroków/min</string>
|
||||
<string name="live_activity_total_steps">Kroków łącznie</string>
|
||||
|
@ -188,12 +234,38 @@
|
|||
<string name="miband_fwinstaller_incompatible_version">Niekompatybilny firmware</string>
|
||||
<string name="fwinstaller_firmware_not_compatible_to_device">Ten firmware nie jest kompatybilny z urządzeniem</string>
|
||||
<string name="miband_prefs_reserve_alarm_calendar">Alarmy zarezerwowane dla nadchodzących zdarzeń</string>
|
||||
<string name="miband_prefs_hr_sleep_detection">Użyj czujnika tętna alby poprawić detekcje snu</string>
|
||||
<string name="miband2_prefs_dateformat">Mi2: Format daty</string>
|
||||
<string name="dateformat_time">Czas</string>
|
||||
<string name="waiting_for_reconnect">oczekiwanie na ponowne połaczenie</string>
|
||||
<string name="activity_prefs_about_you">O tobie</string>
|
||||
<string name="activity_prefs_year_birth">Data urodzenia</string>
|
||||
<string name="activity_prefs_gender">Płeć</string>
|
||||
<string name="activity_prefs_height_cm">Wzrost w cm</string>
|
||||
<string name="activity_prefs_weight_kg">Waga w kg</string>
|
||||
<string name="add_widget">Dodaj widget</string>
|
||||
<string name="activity_prefs_sleep_duration">Preferowana długość snu w godzinach</string>
|
||||
<string name="device_hw">Hardware: %1$s</string>
|
||||
<string name="device_fw">Firmware: %1$s</string>
|
||||
<string name="updatefirmwareoperation_update_in_progress">Trwa aktualizacja firmware</string>
|
||||
<string name="charts_legend_heartrate">Puls</string>
|
||||
<string name="live_activity_heart_rate">Puls</string>
|
||||
<!--Strings related to Onboading Activity-->
|
||||
<string name="title_activity_onboarding">Import bazydanych</string>
|
||||
<string name="import_old_db_buttonlabel">Import starszych danych aktywności</string>
|
||||
<string name="action_db_management">Zarządzanie bazą danych</string>
|
||||
<string name="title_activity_db_management">Zarządzanie bazą danych</string>
|
||||
<string name="activity_db_management_merge_old_title">Importuj / Usuń starą bazę danych</string>
|
||||
<string name="dbmanagementactivity_exported_to">Wyeksportowano do: %1$s</string>
|
||||
<string name="dbmanagementactivity_error_exporting_db">Błąd eksportu bazy: %1$s</string>
|
||||
<string name="dbmanagementactivity_import_data_title">Zaimportować?</string>
|
||||
<string name="dbmanagementactivity_overwrite_database_confirmation">Naprawdę chcesz napisać bazę? Wszystkie Twoje dane zostaną zastąpione.</string>
|
||||
<string name="dbmanagementactivity_error_importing_db">Błąd importu bazy: %1$s</string>
|
||||
<string name="dbmanagementactivity_no_old_activitydatabase_found">Nie znaleziono aktywności, nic do importu.</string>
|
||||
<string name="dbmanagementactivity_overwrite">Nadpisz</string>
|
||||
<string name="Cancel">Anuluj</string>
|
||||
<string name="Delete">Usuń</string>
|
||||
<!--Strings related to Vibration Activity-->
|
||||
<string name="title_activity_vibration">Wibracje</string>
|
||||
<!--Strings related to Pebble Pairing Activity-->
|
||||
</resources>
|
||||
|
|
|
@ -99,7 +99,6 @@
|
|||
<string name="title_activity_android_pairing">Сопряжение устройств</string>
|
||||
<string name="android_pairing_hint">Для сопряжения устройств используйте диалог Android.</string>
|
||||
<string name="title_activity_mi_band_pairing">Сопряжение вашего Mi Band</string>
|
||||
<string name="pairing">Сопряжение с %s…</string>
|
||||
<string name="message_cannot_pair_no_mac">MAC-адрес не был передан, сопряжение не удалось.</string>
|
||||
<string name="preferences_category_device_specific_settings">Настройки устройства</string>
|
||||
<string name="preferences_miband_settings">Настройки Mi Band</string>
|
||||
|
@ -133,8 +132,6 @@
|
|||
<string name="pref_screen_notification_profile_sms">SMS-уведомление</string>
|
||||
<string name="pref_header_vibration_settings">Настройки вибро</string>
|
||||
<string name="pref_screen_notification_profile_generic">Общие уведомления</string>
|
||||
<string name="pref_screen_notification_profile_pebblemsg">Уведомления Pebble</string>
|
||||
<string name="pref_screen_notification_profile_email">Уведомления почты</string>
|
||||
<string name="pref_screen_notification_profile_incoming_call">Уведомления о входящем звонке</string>
|
||||
<string name="control_center_find_lost_device">Найти потерянное устройство</string>
|
||||
<string name="control_center_cancel_to_stop_vibration">Отмените, чтобы остановить вибро</string>
|
||||
|
@ -223,4 +220,6 @@
|
|||
<string name="updatefirmwareoperation_update_in_progress">Обновление прошивки в процессе</string>
|
||||
<!--Strings related to Onboading Activity-->
|
||||
<string name="Delete">Удалить</string>
|
||||
<!--Strings related to Vibration Activity-->
|
||||
<!--Strings related to Pebble Pairing Activity-->
|
||||
</resources>
|
||||
|
|
|
@ -105,7 +105,6 @@
|
|||
<string name="title_activity_android_pairing">Створення пари з пристроєм</string>
|
||||
<string name="android_pairing_hint">Для створення пари із пристроєм використовуйте діалог Android.</string>
|
||||
<string name="title_activity_mi_band_pairing">Створення пари із вашим Mi—Band</string>
|
||||
<string name="pairing">Створення пари із %s…</string>
|
||||
<string name="message_cannot_pair_no_mac">MAC-адресу не було передано, не вдалося створити пару.</string>
|
||||
<string name="preferences_category_device_specific_settings">Параметри пристрою</string>
|
||||
<string name="preferences_miband_settings">Параметри Mi—Band</string>
|
||||
|
@ -138,8 +137,6 @@
|
|||
<string name="pref_screen_notification_profile_sms">SMS-сповіщення</string>
|
||||
<string name="pref_header_vibration_settings">Параметри вібро</string>
|
||||
<string name="pref_screen_notification_profile_generic">Загальні сповіщення</string>
|
||||
<string name="pref_screen_notification_profile_pebblemsg">Сповіщення Pebble</string>
|
||||
<string name="pref_screen_notification_profile_email">Сповіщення пошти</string>
|
||||
<string name="pref_screen_notification_profile_incoming_call">Сповіщення під час вхідного дзвінку</string>
|
||||
<string name="control_center_find_lost_device">Знайти загублений пристрій</string>
|
||||
<string name="control_center_cancel_to_stop_vibration">Скасуйте, аби зупинити вібро</string>
|
||||
|
@ -220,4 +217,6 @@
|
|||
<string name="device_fw">ПЗ: %1$s</string>
|
||||
<!--Strings related to Onboading Activity-->
|
||||
<string name="Delete">Вилучити</string>
|
||||
<!--Strings related to Vibration Activity-->
|
||||
<!--Strings related to Pebble Pairing Activity-->
|
||||
</resources>
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
<string name="appmanager_health_deactivate">Deactivate</string>
|
||||
<string name="appmanager_hrm_activate">Activate HRM</string>
|
||||
<string name="appmanager_hrm_deactivate">Deactivate HRM</string>
|
||||
<string name="appmanager_weather_activate">Activate system weather app</string>
|
||||
<string name="appmanager_weather_deactivate">Deactivate system weather app</string>
|
||||
<string name="app_configure">Configure</string>
|
||||
<string name="app_move_to_top">Move to top</string>
|
||||
|
||||
|
@ -63,6 +65,10 @@
|
|||
|
||||
<string name="pref_title_language">Language</string>
|
||||
|
||||
<string name="pref_title_minimize_priority">Hide the gadgetbridge notification</string>
|
||||
<string name="pref_summary_minimize_priority_off">The icon in the status bar and the notification in the lockscreen are shown</string>
|
||||
<string name="pref_summary_minimize_priority_on">The icon in the status bar and the notification in the lockscreen are hidden</string>
|
||||
|
||||
<string name="pref_header_notifications">Notifications</string>
|
||||
<string name="pref_title_notifications_repetitions">Repetitions</string>
|
||||
<string name="pref_title_notifications_call">Phone Calls</string>
|
||||
|
@ -98,6 +104,9 @@
|
|||
<string name="pref_title_pebble_sync_misfit">Sync Misfit</string>
|
||||
<string name="pref_title_pebble_sync_morpheuz">Sync Morpheuz</string>
|
||||
|
||||
<string name="pref_title_enable_outgoing_call">Support outgoing calls</string>
|
||||
<string name="pref_summary_enable_outgoing_call">Disabling this will also stop the Pebble 2/LE to vibrate on outgoing calls</string>
|
||||
|
||||
<string name="pref_title_enable_pebblekit">Allow 3rd Party Android App Access</string>
|
||||
<string name="pref_summary_enable_pebblekit">Enable experimental support for Android Apps using PebbleKit</string>
|
||||
|
||||
|
@ -120,6 +129,8 @@
|
|||
<string name="pref_summary_pebble_forceuntested">Enable features that are untested. ENABLE ONLY IF YOU KNOW WHAT YOU ARE DOING!</string>
|
||||
<string name="pref_title_pebble_forcele">Always prefer BLE</string>
|
||||
<string name="pref_summary_pebble_forcele">Use experimental Pebble LE support for all Pebbles instead of BT classic, requires paring a "Pebble LE" after non LE had been connected once</string>
|
||||
<string name="pref_title_pebble_mtu_limit">Pebble 2/LE GATT MTU limit</string>
|
||||
<string name="pref_summary_pebble_mtu_limit">If your Pebble 2/Pebble LE does not work as expected, try this setting to limit the MTU (valid range 20–512)</string>
|
||||
<string name="pref_title_pebble_enable_applogs">Enable Watch App Logging</string>
|
||||
<string name="pref_summary_pebble_enable_applogs">Will cause logs from watch apps to be logged by Gadgetbridge (requires reconnect)</string>
|
||||
|
||||
|
|
|
@ -1,5 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<changelog>
|
||||
<release version="0.17.0" versioncode="81">
|
||||
<change>Add weather support through "Weather Notification" app</change>
|
||||
<change>Pebble: Support for build-in weather system app (FW 4.x)</change>
|
||||
<change>Pebble: Add weather support for various watchfaces</change>
|
||||
<change>Pebble: Delete notifications that got dismissed on the phone</change>
|
||||
<change>Pebble: Add option to disable call display</change>
|
||||
<change>Pebble 2/LE: Improve reliablitly and transfer speed</change>
|
||||
<change>Various fixes for K9 mail when using the generic notification receiver</change>
|
||||
</release>
|
||||
<release version="0.16.0" versioncode="80">
|
||||
<change>New devices: HPlus (e.g. Zeblaze ZeBand), contributed by João Paulo Barraca</change>
|
||||
<change>ZeBand: Initial support: notifications, heart rate, sleep monitoring, user configuration, date+time</change>
|
||||
<change>Pebble 2: Fix Pebble Classic FW 3.x app variant being prioritized over native Pebble 2 app variant</change>
|
||||
<change>Charts (Live Activity): Fix axis labels color in dark theme</change>
|
||||
<change>Mi Band: Fix ginormous step count when using Live Activity</change>
|
||||
<change>Mi Band: Improved performance during activity sync</change>
|
||||
<change>Mi Band 2: Fix activity data missing after doing manual hr measurements or live activity</change>
|
||||
<change>Support sharing firmwares/watchapps/watchfaces to Gadgetbridge</change>
|
||||
<change>Support for the "Subsonic" music player (#474)</change>
|
||||
</release>
|
||||
<release version="0.15.2" versioncode="79">
|
||||
<change>Mi Band: Fix crash with unknown notification sources</change>
|
||||
</release>
|
||||
<release version="0.15.1" versioncode="78">
|
||||
<change>Improved handling of notifications for some apps</change>
|
||||
<change>Pebble 2/LE: Add setting to limit GATT MTU for debugging broken BLE stacks</change>
|
||||
<change>Mi Band 2: Display battery status</change>
|
||||
</release>
|
||||
<release version="0.15.0" versioncode="77">
|
||||
<change>New device: Liveview</change>
|
||||
<change>Liveview: initial support (set the time and receive notifications)</change>
|
||||
|
|
|
@ -30,6 +30,12 @@
|
|||
android:entryValues="@array/pref_language_values"
|
||||
android:defaultValue="default"
|
||||
android:summary="%s" />
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="false"
|
||||
android:key="minimize_priority"
|
||||
android:summaryOff="@string/pref_summary_minimize_priority_off"
|
||||
android:summaryOn="@string/pref_summary_minimize_priority_on"
|
||||
android:title="@string/pref_title_minimize_priority" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory
|
||||
android:key="pref_key_datetime"
|
||||
|
@ -146,6 +152,11 @@
|
|||
android:title="@string/pref_title_pebble_settings">
|
||||
<PreferenceCategory
|
||||
android:title="@string/pref_header_general">
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="true"
|
||||
android:key="pebble_enable_outgoing_call"
|
||||
android:summary="@string/pref_summary_enable_outgoing_call"
|
||||
android:title="@string/pref_title_enable_outgoing_call" />
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="false"
|
||||
android:key="pebble_enable_pebblekit"
|
||||
|
@ -341,6 +352,13 @@
|
|||
android:key="pebble_force_le"
|
||||
android:summary="@string/pref_summary_pebble_forcele"
|
||||
android:title="@string/pref_title_pebble_forcele" />
|
||||
<EditTextPreference
|
||||
android:inputType="number"
|
||||
android:key="pebble_mtu_limit"
|
||||
android:maxLength="3"
|
||||
android:defaultValue="512"
|
||||
android:title="@string/pref_title_pebble_mtu_limit"
|
||||
android:summary="@string/pref_summary_pebble_mtu_limit" />
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="false"
|
||||
android:key="pebble_enable_applogs"
|
||||
|
|
|
@ -22,7 +22,7 @@ public class DeviceCommunicationServiceTestCase extends TestBase {
|
|||
* Factory that always returns the mockSupport instance
|
||||
*/
|
||||
private class TestDeviceSupportFactory extends DeviceSupportFactory {
|
||||
public TestDeviceSupportFactory(Context context) {
|
||||
TestDeviceSupportFactory(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ public class DeviceCommunicationServiceTestCase extends TestBase {
|
|||
mDeviceService = new TestDeviceService(getContext());
|
||||
}
|
||||
|
||||
protected GBDevice getDevice() {
|
||||
private GBDevice getDevice() {
|
||||
return realSupport.getDevice();
|
||||
}
|
||||
|
||||
|
|
|
@ -13,11 +13,11 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceService;
|
|||
* Extends GBDeviceServer so that communication with the service works
|
||||
* with Robolectric.
|
||||
*/
|
||||
public class TestDeviceService extends GBDeviceService {
|
||||
class TestDeviceService extends GBDeviceService {
|
||||
private final ServiceController<DeviceCommunicationService> serviceController;
|
||||
private final DeviceCommunicationService service;
|
||||
|
||||
public TestDeviceService(Context context) throws Exception {
|
||||
TestDeviceService(Context context) throws Exception {
|
||||
super(context);
|
||||
|
||||
serviceController = Robolectric.buildService(DeviceCommunicationService.class, createIntent());
|
||||
|
|
|
@ -15,10 +15,11 @@ import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
|||
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
|
||||
public class TestDeviceSupport extends AbstractDeviceSupport {
|
||||
class TestDeviceSupport extends AbstractDeviceSupport {
|
||||
|
||||
public TestDeviceSupport() {
|
||||
TestDeviceSupport() {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -53,6 +54,11 @@ public class TestDeviceSupport extends AbstractDeviceSupport {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleteNotification(int id) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetTime() {
|
||||
|
||||
|
@ -177,4 +183,9 @@ public class TestDeviceSupport extends AbstractDeviceSupport {
|
|||
public void onTestNewFunction() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package nodomain.freeyourgadget.gadgetbridge.test;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic;
|
||||
|
||||
public class MiscTest extends TestBase {
|
||||
@Test
|
||||
public void testGattCharacteristic() {
|
||||
String desc = GattCharacteristic.lookup(GattCharacteristic.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT, "xxx");
|
||||
Assert.assertEquals("heart rate control point", desc);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue