From 9d6ac2b985032309e274b8e940e914c6b93f0e54 Mon Sep 17 00:00:00 2001 From: JF Date: Wed, 21 Oct 2020 17:57:33 +0200 Subject: [PATCH 1/4] Improve notification support for InfiniTime (PineTime) : - InfiniTime 0.9 now supports messages up to 100 chars (instead of max 18 previously) - Remove the hack that was implemented as a workaround to a bug in InfiniTime that would ignore the last character of the notification message (https://github.com/JF002/Pinetime/issues/109). These 2 features are enabled only if the firmware version is >= 0.9. --- .../devices/pinetime/PineTimeJFSupport.java | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pinetime/PineTimeJFSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pinetime/PineTimeJFSupport.java index 8c8ce2b52..2be3e5e06 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pinetime/PineTimeJFSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pinetime/PineTimeJFSupport.java @@ -24,6 +24,7 @@ import android.widget.Toast; import androidx.localbroadcastmanager.content.LocalBroadcastManager; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -72,6 +73,10 @@ public class PineTimeJFSupport extends AbstractBTLEDeviceSupport implements DfuL private static final Logger LOG = LoggerFactory.getLogger(PineTimeJFSupport.class); private final GBDeviceEventVersionInfo versionCmd = new GBDeviceEventVersionInfo(); private final DeviceInfoProfile deviceInfoProfile; + private final int MaxNotificationLength = 100; + private int firmwareVersionMajor = 0; + private int firmwareVersionMinor = 0; + private int firmwareVersionPatch = 0; /** * These are used to keep track when long strings haven't changed, * thus avoiding unnecessary transfers that are (potentially) very slow. @@ -227,8 +232,19 @@ public class PineTimeJFSupport extends AbstractBTLEDeviceSupport implements DfuL @Override public void onNotification(NotificationSpec notificationSpec) { TransactionBuilder builder = new TransactionBuilder("notification"); - NewAlert alert = new NewAlert(AlertCategory.CustomHuami, 1, notificationSpec.body + " "); // HACK: no idea why the last byte is swallowed + String message = notificationSpec.body; + if(!IsFirmwareAtLeastVersion0_9()) { + // Firmware versions prior to 0.9 ignore the last characters of the notification message + // Add an space character so that the whole message will be displayed + message += " "; + } + NewAlert alert = new NewAlert(AlertCategory.CustomHuami, 1, message); AlertNotificationProfile profile = new AlertNotificationProfile<>(this); + if(IsFirmwareAtLeastVersion0_9()) { + // InfiniTime 0.9+ support notification message of up to 100 characters + // Instead of 18 by default + profile.setMaxLength(MaxNotificationLength); + } profile.newAlert(builder, alert, OverflowStrategy.TRUNCATE); builder.queue(getQueue()); } @@ -573,9 +589,24 @@ public class PineTimeJFSupport extends AbstractBTLEDeviceSupport implements DfuL LOG.warn("Device info: " + info); versionCmd.hwVersion = info.getHardwareRevision(); versionCmd.fwVersion = info.getFirmwareRevision(); + + if(versionCmd.fwVersion != null && !versionCmd.fwVersion.isEmpty()) { + // FW version format : "major.minor.patch". Ex : "0.8.2" + String[] tokens = StringUtils.split(versionCmd.fwVersion, "."); + if(tokens.length == 3) { + firmwareVersionMajor = Integer.parseInt(tokens[0]); + firmwareVersionMinor = Integer.parseInt(tokens[1]); + firmwareVersionPatch = Integer.parseInt(tokens[2]); + } + } + handleGBDeviceEvent(versionCmd); } + private boolean IsFirmwareAtLeastVersion0_9() { + return firmwareVersionMajor > 0 || firmwareVersionMinor >= 9; + } + /** * Nordic DFU needs this function to log DFU-related messages */ From 4d42e169b99598d7b67a33a781b17944aad4fadf Mon Sep 17 00:00:00 2001 From: vanous Date: Thu, 22 Oct 2020 06:32:21 +0200 Subject: [PATCH 2/4] Add GPS fragment to Sport Activity detail add GPX parser fix possible swiping issue after device rotation use window background color for screenshots --- .../gadgetbridge/GBApplication.java | 7 + .../ActivitySummariesGpsFragment.java | 142 ++++++++++++++++++ .../activities/ActivitySummaryDetail.java | 61 +++++++- .../gadgetbridge/model/GPSCoordinate.java | 23 +++ .../gadgetbridge/util/GpxParser.java | 78 ++++++++++ .../gadgetbridge/util/SwipeEvents.java | 3 + .../res/layout/activity_summary_details.xml | 19 ++- app/src/main/res/layout/fragment_gps.xml | 28 ++++ app/src/main/res/values/strings.xml | 1 + 9 files changed, 345 insertions(+), 17 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ActivitySummariesGpsFragment.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GpxParser.java create mode 100644 app/src/main/res/layout/fragment_gps.xml diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java index d3c2830c7..627f513c2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java @@ -1003,6 +1003,13 @@ public class GBApplication extends Application { return typedValue.data; } + public static int getWindowBackgroundColor(Context context) { + TypedValue typedValue = new TypedValue(); + Resources.Theme theme = context.getTheme(); + theme.resolveAttribute(android.R.attr.windowBackground, typedValue, true); + return typedValue.data; + } + public static Prefs getPrefs() { return prefs; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ActivitySummariesGpsFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ActivitySummariesGpsFragment.java new file mode 100644 index 000000000..4b89200a0 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ActivitySummariesGpsFragment.java @@ -0,0 +1,142 @@ +/* Copyright (C) 2015-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele + Gobbetti, Dikay900, Pavel Elagin + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.activities; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import androidx.annotation.Nullable; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.util.Collections; +import java.util.List; + +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.model.GPSCoordinate; +import nodomain.freeyourgadget.gadgetbridge.util.GpxParser; + +import static android.graphics.Bitmap.createBitmap; + + +public class ActivitySummariesGpsFragment extends AbstractGBFragment { + private static final Logger LOG = LoggerFactory.getLogger(ActivitySummariesGpsFragment.class); + private ImageView gpsView; + private int CANVAS_SIZE = 360; + private File inputFile; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View rootView = inflater.inflate(R.layout.fragment_gps, container, false); + gpsView = rootView.findViewById(R.id.activitygpsview); + if (inputFile != null) { + processInBackgroundThread(); + } + return rootView; + } + + public void set_data(File inputFile) { + this.inputFile = inputFile; + if (gpsView != null) { //first fragment inflate is AFTER this is called + processInBackgroundThread(); + } + } + + private void processInBackgroundThread() { + final Canvas canvas = createCanvas(gpsView); + new Thread(new Runnable() { + @Override + public void run() { + GpxParser gpxParser = null; + FileInputStream inputStream = null; + + try { + inputStream = new FileInputStream(inputFile); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + + if (inputStream != null) { + gpxParser = new GpxParser(inputStream); + } + + if (gpxParser != null) { + drawTrack(canvas, gpxParser.getPoints()); + } + } + }).start(); + } + private void drawTrack(Canvas canvas, List trackPoints) { + double maxLat = (Collections.max(trackPoints, new GPSCoordinate.compareLatitude())).getLatitude(); + double minLat = (Collections.min(trackPoints, new GPSCoordinate.compareLatitude())).getLatitude(); + double maxLon = (Collections.max(trackPoints, new GPSCoordinate.compareLongitude())).getLongitude(); + double minLon = (Collections.min(trackPoints, new GPSCoordinate.compareLongitude())).getLongitude(); + double maxAlt = (Collections.max(trackPoints, new GPSCoordinate.compareElevation())).getAltitude(); + double minAlt = (Collections.min(trackPoints, new GPSCoordinate.compareElevation())).getAltitude(); + + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + paint.setStrokeWidth(1); + paint.setColor(getResources().getColor(R.color.chart_activity_light)); + + for (GPSCoordinate p : trackPoints) { + float lat = (float) ((p.getLatitude() - minLat) / (maxLat - minLat)); + float lon = (float) ((p.getLongitude() - minLon) / (maxLon - minLon)); + float alt = (float) ((p.getAltitude() - minAlt) / (maxAlt - minAlt)); + paint.setStrokeWidth(1 + alt); //make thicker with higher altitude, we could do more here + canvas.drawPoint(CANVAS_SIZE * lat, CANVAS_SIZE * lon, paint); + } + } + + + private Canvas createCanvas(ImageView imageView) { + Bitmap bitmap = createBitmap(CANVAS_SIZE, CANVAS_SIZE, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + canvas.drawColor(GBApplication.getWindowBackgroundColor(getActivity())); + //frame around, but it doesn't look so nice + /* + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + paint.setStrokeWidth(0); + paint.setStyle(Paint.Style.STROKE); + paint.setColor(getResources().getColor(R.color.chart_activity_light)); + canvas.drawRect(0,0,360,360,paint); + */ + imageView.setImageBitmap(bitmap); + + return canvas; + } + + @Nullable + @Override + protected CharSequence getTitle() { + return null; + } + +} + diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ActivitySummaryDetail.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ActivitySummaryDetail.java index b3609f3c4..10940249a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ActivitySummaryDetail.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ActivitySummaryDetail.java @@ -26,7 +26,6 @@ import android.content.Intent; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Typeface; import android.net.Uri; import android.os.Bundle; @@ -97,11 +96,7 @@ public class ActivitySummaryDetail extends AbstractGBActivity { public static Bitmap getScreenShot(View view, int height, int width, Context context) { Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); - if (GBApplication.isDarkThemeEnabled()) { - canvas.drawColor(GBApplication.getBackgroundColor(context)); - } else { - canvas.drawColor(Color.WHITE); - } + canvas.drawColor(GBApplication.getWindowBackgroundColor(context)); view.draw(canvas); return bitmap; } @@ -153,10 +148,12 @@ public class ActivitySummaryDetail extends AbstractGBActivity { R.anim.bounceright); final ActivitySummariesChartFragment activitySummariesChartFragment = new ActivitySummariesChartFragment(); + final ActivitySummariesGpsFragment activitySummariesGpsFragment = new ActivitySummariesGpsFragment(); getSupportFragmentManager() .beginTransaction() - .replace(R.id.fragmentHolder, activitySummariesChartFragment) + .replace(R.id.chartsFragmentHolder, activitySummariesChartFragment) + .replace(R.id.gpsFragmentHolder, activitySummariesGpsFragment) .commit(); layout.setOnTouchListener(new SwipeEvents(this) { @@ -168,6 +165,13 @@ public class ActivitySummaryDetail extends AbstractGBActivity { makeSummaryHeader(newItem); makeSummaryContent(newItem); activitySummariesChartFragment.setDateAndGetData(gbDevice, currentItem.getStartTime().getTime() / 1000, currentItem.getEndTime().getTime() / 1000); + if (get_gpx_file() != null) { + showCanvas(); + activitySummariesGpsFragment.set_data(get_gpx_file()); + } else { + hideCanvas(); + } + layout.startAnimation(animFadeRight); show_hide_gpx_menu(); } else { @@ -183,6 +187,14 @@ public class ActivitySummaryDetail extends AbstractGBActivity { makeSummaryHeader(newItem); makeSummaryContent(newItem); activitySummariesChartFragment.setDateAndGetData(gbDevice, currentItem.getStartTime().getTime() / 1000, currentItem.getEndTime().getTime() / 1000); + if (get_gpx_file() != null) { + showCanvas(); + activitySummariesGpsFragment.set_data(get_gpx_file()); + } else { + hideCanvas(); + } + + layout.startAnimation(animFadeLeft); show_hide_gpx_menu(); } else { @@ -196,6 +208,13 @@ public class ActivitySummaryDetail extends AbstractGBActivity { makeSummaryHeader(currentItem); makeSummaryContent(currentItem); activitySummariesChartFragment.setDateAndGetData(gbDevice, currentItem.getStartTime().getTime() / 1000, currentItem.getEndTime().getTime() / 1000); + if (get_gpx_file() != null) { + showCanvas(); + activitySummariesGpsFragment.set_data(get_gpx_file()); + } else { + hideCanvas(); + } + } @@ -464,6 +483,34 @@ public class ActivitySummaryDetail extends AbstractGBActivity { } } + private void showCanvas() { + View gpsView = findViewById(R.id.gpsFragmentHolder); + ViewGroup.LayoutParams params = gpsView.getLayoutParams(); + params.height = (int) (300 * getApplicationContext().getResources().getDisplayMetrics().density); + gpsView.setLayoutParams(params); + } + + private void hideCanvas() { + View gpsView = findViewById(R.id.gpsFragmentHolder); + ViewGroup.LayoutParams params = gpsView.getLayoutParams(); + params.height = 0; + gpsView.setLayoutParams(params); + } + + private File get_gpx_file() { + final String gpxTrack = currentItem.getGpxTrack(); + if (gpxTrack != null) { + File file = new File(gpxTrack); + if (file.exists()) { + return file; + } else { + return null; + } + } + return null; + } + + @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/GPSCoordinate.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/GPSCoordinate.java index 993ee1f18..b1ee09296 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/GPSCoordinate.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/GPSCoordinate.java @@ -18,6 +18,7 @@ package nodomain.freeyourgadget.gadgetbridge.model; import java.math.BigDecimal; import java.math.RoundingMode; +import java.util.Comparator; public final class GPSCoordinate { private final double latitude; @@ -78,4 +79,26 @@ public final class GPSCoordinate { public String toString() { return "lon: " + formatLocation(longitude) + ", lat: " + formatLocation(latitude) + ", alt: " + formatLocation(altitude) + "m"; } + + public static class compareLatitude implements Comparator { + @Override + public int compare(GPSCoordinate trkPt1, GPSCoordinate trkPt2) { + return Double.compare(trkPt1.getLatitude(), trkPt2.getLatitude()); + } + } + + public static class compareLongitude implements Comparator { + @Override + public int compare(GPSCoordinate trkPt1, GPSCoordinate trkPt2) { + return Double.compare(trkPt1.getLongitude(), trkPt2.getLongitude()); + } + } + + public static class compareElevation implements Comparator { + @Override + public int compare(GPSCoordinate trkPt1, GPSCoordinate trkPt2) { + return Double.compare(trkPt1.getAltitude(), trkPt2.getAltitude()); + } + } + } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GpxParser.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GpxParser.java new file mode 100644 index 000000000..e5af6c84b --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GpxParser.java @@ -0,0 +1,78 @@ +package nodomain.freeyourgadget.gadgetbridge.util; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlPullParserFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import nodomain.freeyourgadget.gadgetbridge.model.GPSCoordinate; + +public class GpxParser { + private XmlPullParser parser; + private List points; + private int eventType; + + public GpxParser(InputStream stream) { + points = new ArrayList<>(); + try { + parser = createXmlParser(stream); + parseGpx(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static XmlPullParser createXmlParser(InputStream stream) throws XmlPullParserException { + XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); + factory.setNamespaceAware(true); + XmlPullParser parser = factory.newPullParser(); + parser.setInput(stream, null); + return parser; + } + + private void parseGpx() throws XmlPullParserException, IOException { + eventType = parser.getEventType(); + while (eventType != XmlPullParser.END_DOCUMENT) { + if (eventType == XmlPullParser.START_TAG && parser.getName().equals("trkpt")) + points.add(parsePoint(parser)); + else + eventType = parser.next(); + } + } + + private double parseElevation(XmlPullParser parser) throws XmlPullParserException, IOException { + String eleString = ""; + while (eventType != XmlPullParser.END_TAG) { + if (eventType == XmlPullParser.TEXT) { + eleString = parser.getText(); + } + eventType = parser.next(); + } + return Double.parseDouble(eleString); + } + + private GPSCoordinate parsePoint(XmlPullParser parser) throws XmlPullParserException, IOException { + double lat; + double lon; + double ele = 0; + String latString = parser.getAttributeValue(null, "lat"); + String lonString = parser.getAttributeValue(null, "lon"); + lat = latString != null ? Double.parseDouble(latString) : 0; + lon = lonString != null ? Double.parseDouble(lonString) : 0; + while (eventType != XmlPullParser.END_TAG) { + if (parser.getEventType() == XmlPullParser.START_TAG && parser.getName().equals("ele")) { + ele = parseElevation(parser); + } + eventType = parser.next(); + } + return new GPSCoordinate(lat, lon, ele); + } + + public List getPoints() { + return points; + } +} \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/SwipeEvents.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/SwipeEvents.java index 940ea1205..8bba4b665 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/SwipeEvents.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/SwipeEvents.java @@ -40,6 +40,9 @@ public class SwipeEvents implements View.OnTouchListener { @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + if (e1 == null || e2 == null){ + return false; + } float distanceX = e2.getX() - e1.getX(); float distanceY = e2.getY() - e1.getY(); if (Math.abs(distanceX) > Math.abs(distanceY) && Math.abs(distanceX) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) { diff --git a/app/src/main/res/layout/activity_summary_details.xml b/app/src/main/res/layout/activity_summary_details.xml index 005681a5d..110d9c3fb 100644 --- a/app/src/main/res/layout/activity_summary_details.xml +++ b/app/src/main/res/layout/activity_summary_details.xml @@ -2,7 +2,8 @@ - - - @@ -166,13 +164,14 @@ android:layout_height="wrap_content" /> - - + android:layout_height="300dp"> + - - \ No newline at end of file + diff --git a/app/src/main/res/layout/fragment_gps.xml b/app/src/main/res/layout/fragment_gps.xml new file mode 100644 index 000000000..6f195efb8 --- /dev/null +++ b/app/src/main/res/layout/fragment_gps.xml @@ -0,0 +1,28 @@ + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 303942cca..3488a54d5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1022,6 +1022,7 @@ End Duration Show GPS Track + GPS track Use device events to trigger actions and Android broadcasts Device actions From 95c35deb905e0d49eeec640bc1ef5e687d24d8f3 Mon Sep 17 00:00:00 2001 From: vanous Date: Sat, 24 Oct 2020 21:55:48 +0200 Subject: [PATCH 3/4] Add version to About screen --- .../gadgetbridge/activities/AboutActivity.java | 5 +++++ app/src/main/res/layout/activity_about.xml | 7 ++++++- app/src/main/res/values/strings.xml | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AboutActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AboutActivity.java index 590fb23d9..fcd0290d5 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AboutActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AboutActivity.java @@ -20,6 +20,7 @@ package nodomain.freeyourgadget.gadgetbridge.activities; import android.os.Bundle; import android.text.method.LinkMovementMethod; import android.widget.TextView; +import nodomain.freeyourgadget.gadgetbridge.BuildConfig; import nodomain.freeyourgadget.gadgetbridge.R; @@ -29,6 +30,10 @@ public class AboutActivity extends AbstractGBActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_about); + TextView about_version = findViewById(R.id.about_version); + String versionName = BuildConfig.VERSION_NAME; + about_version.setText(String.format(getString(R.string.about_version), versionName)); + TextView link1 = findViewById(R.id.links1); link1.setMovementMethod(LinkMovementMethod.getInstance()); TextView link2 = findViewById(R.id.links2); diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml index c735b7202..fc442e051 100644 --- a/app/src/main/res/layout/activity_about.xml +++ b/app/src/main/res/layout/activity_about.xml @@ -12,7 +12,7 @@ android:layout_centerInParent="true" android:alpha="0.1" android:contentDescription="@string/icon_placeholder" - android:tint="?attr/textColorPrimary" + app:tint="?attr/textColorPrimary" app:srcCompat="@drawable/gadgetbridge_img" /> + + Code: https://codeberg.org/Freeyourgadget/Gadgetbridge F-Droid: https://f-droid.org/packages/nodomain.freeyourgadget.gadgetbridge/ About + Version %s About Gadgetbridge Cloudless copylefted libre replacement for closed source Android gadget apps from vendors. Core Team (in order of first code contribution) From a38203202125c23440d62323375fee3495fb7d56 Mon Sep 17 00:00:00 2001 From: vanous Date: Sun, 25 Oct 2020 14:48:06 +0100 Subject: [PATCH 4/4] Add GPX Import test --- .../gadgetbridge/test/GPXParserTest.java | 33 +++++++++ .../gpx-exporter-test-SampleTrack.gpx | 70 +++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/GPXParserTest.java create mode 100644 app/src/test/resources/gpx-exporter-test-SampleTrack.gpx diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/GPXParserTest.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/GPXParserTest.java new file mode 100644 index 000000000..0b3c21848 --- /dev/null +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/GPXParserTest.java @@ -0,0 +1,33 @@ +package nodomain.freeyourgadget.gadgetbridge.test; + +import org.junit.Assert; +import org.junit.Test; + +import java.io.IOException; +import java.io.InputStream; +import java.text.DecimalFormat; +import java.util.List; + +import nodomain.freeyourgadget.gadgetbridge.model.GPSCoordinate; +import nodomain.freeyourgadget.gadgetbridge.util.GpxParser; + +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.is; + +public class GPXParserTest extends TestBase { + + @Test + public void shouldReadGPXCorrectly() throws IOException { + try (final InputStream inputStream = getClass().getResourceAsStream("/gpx-exporter-test-SampleTrack.gpx")) { + GpxParser gpxParser = new GpxParser(inputStream); + List trackPoints = gpxParser.getPoints(); + Assert.assertEquals(trackPoints.size(), 14); + DecimalFormat df = new DecimalFormat("###.##"); + for (GPSCoordinate tp : trackPoints) { + Assert.assertEquals(df.format(tp.getLongitude()), "44.15"); + Assert.assertEquals(df.format(tp.getLatitude()), "-68.2"); + Assert.assertThat(df.format(tp.getAltitude()), anyOf(is("40"), is("46"))); + } + } + } +} diff --git a/app/src/test/resources/gpx-exporter-test-SampleTrack.gpx b/app/src/test/resources/gpx-exporter-test-SampleTrack.gpx new file mode 100644 index 000000000..24141feb1 --- /dev/null +++ b/app/src/test/resources/gpx-exporter-test-SampleTrack.gpx @@ -0,0 +1,70 @@ + + + + Test Track + + Test User + + + + + + + 40.000000 + + + + 40.000000 + + + + 40.000000 + + + + 40.000000 + + + + 40.000000 + + + + 40.000000 + + + + 40.000000 + + + + 40.000000 + + + + 46.000000 + + + + 46.000000 + + + + 46.000000 + + + + 46.000000 + + + + 46.000000 + + + + 46.000000 + + + + +