diff --git a/android_app/app/schemas/com.health.openscale.core.database.AppDatabase/3.json b/android_app/app/schemas/com.health.openscale.core.database.AppDatabase/3.json index f3858d57..2b7e3e0d 100644 --- a/android_app/app/schemas/com.health.openscale.core.database.AppDatabase/3.json +++ b/android_app/app/schemas/com.health.openscale.core.database.AppDatabase/3.json @@ -2,11 +2,11 @@ "formatVersion": 1, "database": { "version": 3, - "identityHash": "2db259b9e244ebad0c664f2c9fb36068", + "identityHash": "974ad0a810bf389300cf67b40862bb75", "entities": [ { "tableName": "scaleMeasurements", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userId` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `datetime` INTEGER, `weight` REAL NOT NULL, `fat` REAL NOT NULL, `water` REAL NOT NULL, `muscle` REAL NOT NULL, `visceralFat` REAL NOT NULL, `lbm` REAL NOT NULL, `waist` REAL NOT NULL, `hip` REAL NOT NULL, `bone` REAL NOT NULL, `chest` REAL NOT NULL, `thigh` REAL NOT NULL, `biceps` REAL NOT NULL, `neck` REAL NOT NULL, `caliper1` REAL NOT NULL, `caliper2` REAL NOT NULL, `caliper3` REAL NOT NULL, `calories` REAL NOT NULL, `comment` TEXT, FOREIGN KEY(`userId`) REFERENCES `scaleUsers`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userId` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `datetime` INTEGER, `weight` REAL NOT NULL, `fat` REAL NOT NULL, `water` REAL NOT NULL, `muscle` REAL NOT NULL, `visceralFat` REAL NOT NULL, `lbm` REAL NOT NULL, `waist` REAL NOT NULL, `hip` REAL NOT NULL, `bone` REAL NOT NULL, `chest` REAL NOT NULL, `thigh` REAL NOT NULL, `biceps` REAL NOT NULL, `neck` REAL NOT NULL, `caliper1` REAL NOT NULL, `caliper2` REAL NOT NULL, `caliper3` REAL NOT NULL, `comment` TEXT, FOREIGN KEY(`userId`) REFERENCES `scaleUsers`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", "fields": [ { "fieldPath": "id", @@ -128,12 +128,6 @@ "affinity": "REAL", "notNull": true }, - { - "fieldPath": "calories", - "columnName": "calories", - "affinity": "REAL", - "notNull": true - }, { "fieldPath": "comment", "columnName": "comment", @@ -253,10 +247,9 @@ "foreignKeys": [] } ], - "views": [], "setupQueries": [ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"2db259b9e244ebad0c664f2c9fb36068\")" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"974ad0a810bf389300cf67b40862bb75\")" ] } } \ No newline at end of file diff --git a/android_app/app/src/androidTest/java/com/health/openscale/DatabaseMigrationTest.java b/android_app/app/src/androidTest/java/com/health/openscale/DatabaseMigrationTest.java index 5d7f052a..7eb177a6 100644 --- a/android_app/app/src/androidTest/java/com/health/openscale/DatabaseMigrationTest.java +++ b/android_app/app/src/androidTest/java/com/health/openscale/DatabaseMigrationTest.java @@ -16,14 +16,9 @@ package com.health.openscale; -import androidx.sqlite.db.SupportSQLiteDatabase; -import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory; -import androidx.room.testing.MigrationTestHelper; import android.content.ContentValues; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; -import androidx.test.InstrumentationRegistry; -import androidx.test.ext.junit.runners.AndroidJUnit4; import com.health.openscale.core.database.AppDatabase; @@ -31,6 +26,12 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import androidx.room.testing.MigrationTestHelper; +import androidx.sqlite.db.SupportSQLiteDatabase; +import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotSame; import static junit.framework.Assert.assertTrue; diff --git a/android_app/app/src/androidTest/java/com/health/openscale/DatabaseTest.java b/android_app/app/src/androidTest/java/com/health/openscale/DatabaseTest.java index 4019274b..14b63873 100644 --- a/android_app/app/src/androidTest/java/com/health/openscale/DatabaseTest.java +++ b/android_app/app/src/androidTest/java/com/health/openscale/DatabaseTest.java @@ -15,10 +15,7 @@ */ package com.health.openscale; -import androidx.room.Room; import android.content.Context; -import androidx.test.InstrumentationRegistry; -import androidx.test.ext.junit.runners.AndroidJUnit4; import com.health.openscale.core.database.AppDatabase; import com.health.openscale.core.database.ScaleMeasurementDAO; @@ -36,6 +33,10 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; +import androidx.room.Room; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -51,7 +52,7 @@ public class DatabaseTest { @Before public void initDatabase() { - Context context = InstrumentationRegistry.getTargetContext(); + Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); appDB = Room.inMemoryDatabaseBuilder(context, AppDatabase.class).build(); userDao = appDB.userDAO(); measurementDAO = appDB.measurementDAO(); diff --git a/android_app/app/src/test/java/com/health/openscale/TrisaBodyAnalyzeLibTest.java b/android_app/app/src/androidTest/java/com/health/openscale/TrisaBodyAnalyzeLibTest.java similarity index 66% rename from android_app/app/src/test/java/com/health/openscale/TrisaBodyAnalyzeLibTest.java rename to android_app/app/src/androidTest/java/com/health/openscale/TrisaBodyAnalyzeLibTest.java index ad9cfe96..e64bc87c 100644 --- a/android_app/app/src/test/java/com/health/openscale/TrisaBodyAnalyzeLibTest.java +++ b/android_app/app/src/androidTest/java/com/health/openscale/TrisaBodyAnalyzeLibTest.java @@ -1,39 +1,65 @@ package com.health.openscale; +import com.health.openscale.core.bluetooth.BluetoothTrisaBodyAnalyze; import com.health.openscale.core.datatypes.ScaleMeasurement; import com.health.openscale.core.datatypes.ScaleUser; import com.health.openscale.core.utils.Converters; +import com.health.openscale.gui.MainActivity; import junit.framework.Assert; +import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; -import static com.health.openscale.core.bluetooth.lib.TrisaBodyAnalyzeLib.convertDeviceTimestampToJava; -import static com.health.openscale.core.bluetooth.lib.TrisaBodyAnalyzeLib.convertJavaTimestampToDevice; -import static com.health.openscale.core.bluetooth.lib.TrisaBodyAnalyzeLib.getBase10Float; -import static com.health.openscale.core.bluetooth.lib.TrisaBodyAnalyzeLib.parseScaleMeasurementData; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.rule.ActivityTestRule; + import static junit.framework.Assert.assertEquals; /** Unit tests for {@link com.health.openscale.core.bluetooth.lib.TrisaBodyAnalyzeLib}.*/ +@RunWith(AndroidJUnit4.class) public class TrisaBodyAnalyzeLibTest { + @Rule + public ActivityTestRule mActivityTestRule = new ActivityTestRule<>(MainActivity.class, false, false); + + + public BluetoothTrisaBodyAnalyze trisaBodyAnalyze; + + @Before + public void initTest() { + try { + mActivityTestRule.runOnUiThread(new Runnable() { + public void run() { + trisaBodyAnalyze =new BluetoothTrisaBodyAnalyze(InstrumentationRegistry.getInstrumentation().getTargetContext()); + } + }); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } + @Test public void getBase10FloatTests() { double eps = 1e-9; // margin of error for inexact floating point comparisons - assertEquals(0.0, getBase10Float(new byte[]{0, 0, 0, 0}, 0)); - assertEquals(0.0, getBase10Float(new byte[]{0, 0, 0, -1}, 0)); - assertEquals(76.1, getBase10Float(new byte[]{-70, 29, 0, -2}, 0), eps); - assertEquals(1234.5678, getBase10Float(new byte[]{78, 97, -68, -4}, 0), eps); - assertEquals(12345678e127, getBase10Float(new byte[]{78, 97, -68, 127}, 0)); - assertEquals(12345678e-128, getBase10Float(new byte[]{78, 97, -68, -128}, 0), eps); + + assertEquals(0.0f, trisaBodyAnalyze.getBase10Float(new byte[]{0, 0, 0, 0}, 0)); + assertEquals(0.0f, trisaBodyAnalyze.getBase10Float(new byte[]{0, 0, 0, -1}, 0)); + assertEquals(76.1f, trisaBodyAnalyze.getBase10Float(new byte[]{-70, 29, 0, -2}, 0), eps); + assertEquals(1234.5678f, trisaBodyAnalyze.getBase10Float(new byte[]{78, 97, -68, -4}, 0), eps); + assertEquals(12345678e20f, trisaBodyAnalyze.getBase10Float(new byte[]{78, 97, -68, 20}, 0)); + assertEquals(12345678e-20f, trisaBodyAnalyze.getBase10Float(new byte[]{78, 97, -68, -20}, 0), eps); byte[] data = new byte[]{1,2,3,4,5}; - assertEquals(0x030201*1e4, getBase10Float(data, 0)); - assertEquals(0x040302*1e5, getBase10Float(data, 1)); + assertEquals(0x030201*1e4f, trisaBodyAnalyze.getBase10Float(data, 0)); + assertEquals(0x040302*1e5f, trisaBodyAnalyze.getBase10Float(data, 1)); assertThrows(IndexOutOfBoundsException.class, getBase10FloatRunnable(data, -1)); assertThrows(IndexOutOfBoundsException.class, getBase10FloatRunnable(data, 5)); @@ -42,18 +68,18 @@ public class TrisaBodyAnalyzeLibTest { @Test public void convertJavaTimestampToDeviceTests() { - assertEquals(275852082, convertJavaTimestampToDevice(1538156082000L)); + assertEquals(275852082, trisaBodyAnalyze.convertJavaTimestampToDevice(1538156082000L)); // Rounds down. - assertEquals(275852082, convertJavaTimestampToDevice(1538156082499L)); + assertEquals(275852082, trisaBodyAnalyze.convertJavaTimestampToDevice(1538156082499L)); // Rounds up. - assertEquals(275852083, convertJavaTimestampToDevice(1538156082500L)); + assertEquals(275852083, trisaBodyAnalyze.convertJavaTimestampToDevice(1538156082500L)); } @Test public void convertDeviceTimestampToJavaTests() { - assertEquals(1538156082000L, convertDeviceTimestampToJava(275852082)); + assertEquals(1538156082000L, trisaBodyAnalyze.convertDeviceTimestampToJava(275852082)); } @Test @@ -67,7 +93,7 @@ public class TrisaBodyAnalyzeLibTest { user.setBodyHeight(186); user.setMeasureUnit(Converters.MeasureUnit.CM); - ScaleMeasurement measurement = parseScaleMeasurementData(bytes, user); + ScaleMeasurement measurement = trisaBodyAnalyze.parseScaleMeasurementData(bytes, user); float eps = 1e-3f; assertEquals(76.0f, measurement.getWeight(), eps); @@ -83,7 +109,7 @@ public class TrisaBodyAnalyzeLibTest { long expected_timestamp_seconds = 1538156082L; // Fri Sep 28 17:34:42 UTC 2018 byte[] bytes = hexToBytes("9f:ba:1d:00:fe:32:2b:71:10:00:00:00:ff:8d:14:00:ff:00:09:00"); - ScaleMeasurement measurement = parseScaleMeasurementData(bytes, null); + ScaleMeasurement measurement = trisaBodyAnalyze.parseScaleMeasurementData(bytes, null); assertEquals(76.1f, measurement.getWeight(), 1e-3f); assertEquals(new Date(expected_timestamp_seconds * 1000), measurement.getDateTime()); @@ -95,7 +121,7 @@ public class TrisaBodyAnalyzeLibTest { long expected_timestamp_seconds = 1538156082L; // Fri Sep 28 17:34:42 UTC 2018 byte[] bytes = hexToBytes("9f:ba:1d:00:fe:32:2b:71:10:00:00:00:ff:8d:14:00:ff:00:09:00"); - ScaleMeasurement measurement = parseScaleMeasurementData(bytes, new ScaleUser()); + ScaleMeasurement measurement = trisaBodyAnalyze.parseScaleMeasurementData(bytes, new ScaleUser()); assertEquals(76.1f, measurement.getWeight(), 1e-3f); assertEquals(new Date(expected_timestamp_seconds * 1000), measurement.getDateTime()); @@ -106,11 +132,11 @@ public class TrisaBodyAnalyzeLibTest { * Creates a {@link Runnable} that will call getBase10Float(). In Java 8, this can be done more * easily with a lambda expression at the call site, but we are using Java 7. */ - private static Runnable getBase10FloatRunnable(final byte[] data, final int offset) { + private Runnable getBase10FloatRunnable(final byte[] data, final int offset) { return new Runnable() { @Override public void run() { - getBase10Float(data, offset); + trisaBodyAnalyze.getBase10Float(data, offset); } }; } diff --git a/android_app/app/src/androidTest/java/com/health/openscale/gui/AddMeasurementTest.java b/android_app/app/src/androidTest/java/com/health/openscale/gui/AddMeasurementTest.java index 8d2f2110..7b240af8 100644 --- a/android_app/app/src/androidTest/java/com/health/openscale/gui/AddMeasurementTest.java +++ b/android_app/app/src/androidTest/java/com/health/openscale/gui/AddMeasurementTest.java @@ -18,11 +18,6 @@ package com.health.openscale.gui; import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; -import androidx.test.InstrumentationRegistry; -import androidx.test.espresso.contrib.PickerActions; -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.rule.ActivityTestRule; -import androidx.test.filters.LargeTest; import android.widget.DatePicker; import android.widget.EditText; import android.widget.TimePicker; @@ -63,6 +58,12 @@ import org.junit.runner.RunWith; import java.util.Calendar; import java.util.List; +import androidx.test.espresso.contrib.PickerActions; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.LargeTest; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.rule.ActivityTestRule; + import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; import static androidx.test.espresso.action.ViewActions.replaceText; @@ -85,7 +86,7 @@ public class AddMeasurementTest { @BeforeClass public static void initTest() { - context = InstrumentationRegistry.getTargetContext(); + context = InstrumentationRegistry.getInstrumentation().getTargetContext(); openScale = OpenScale.getInstance(); diff --git a/android_app/app/src/androidTest/java/com/health/openscale/gui/AddUserTest.java b/android_app/app/src/androidTest/java/com/health/openscale/gui/AddUserTest.java index e3342d49..57167bfb 100644 --- a/android_app/app/src/androidTest/java/com/health/openscale/gui/AddUserTest.java +++ b/android_app/app/src/androidTest/java/com/health/openscale/gui/AddUserTest.java @@ -18,12 +18,6 @@ package com.health.openscale.gui; import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; -import androidx.test.InstrumentationRegistry; -import androidx.test.espresso.ViewInteraction; -import androidx.test.espresso.contrib.PickerActions; -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.rule.ActivityTestRule; -import androidx.test.filters.LargeTest; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; @@ -46,6 +40,13 @@ import org.junit.runner.RunWith; import java.util.Calendar; +import androidx.test.espresso.ViewInteraction; +import androidx.test.espresso.contrib.PickerActions; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.LargeTest; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.rule.ActivityTestRule; + import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard; @@ -68,7 +69,7 @@ public class AddUserTest { @Before public void initTest() { - context = InstrumentationRegistry.getTargetContext(); + context = InstrumentationRegistry.getInstrumentation().getTargetContext(); // Set first start to true to get the user add dialog SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); diff --git a/android_app/app/src/androidTest/java/com/health/openscale/gui/ScreenshotRecorder.java b/android_app/app/src/androidTest/java/com/health/openscale/gui/ScreenshotRecorder.java index b3167096..44f9909a 100644 --- a/android_app/app/src/androidTest/java/com/health/openscale/gui/ScreenshotRecorder.java +++ b/android_app/app/src/androidTest/java/com/health/openscale/gui/ScreenshotRecorder.java @@ -20,14 +20,6 @@ import android.content.Context; import android.content.SharedPreferences; import android.graphics.Bitmap; import android.preference.PreferenceManager; -import androidx.test.InstrumentationRegistry; -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.rule.ActivityTestRule; -import androidx.test.rule.GrantPermissionRule; -import androidx.test.runner.screenshot.BasicScreenCaptureProcessor; -import androidx.test.runner.screenshot.ScreenCapture; -import androidx.test.runner.screenshot.Screenshot; -import androidx.test.filters.LargeTest; import android.view.Gravity; import com.health.openscale.R; @@ -52,6 +44,14 @@ import java.util.Calendar; import java.util.List; import java.util.Locale; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.LargeTest; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.rule.ActivityTestRule; +import androidx.test.rule.GrantPermissionRule; +import androidx.test.runner.screenshot.BasicScreenCaptureProcessor; +import androidx.test.runner.screenshot.ScreenCapture; +import androidx.test.runner.screenshot.Screenshot; import timber.log.Timber; import static android.os.Environment.DIRECTORY_PICTURES; @@ -81,7 +81,7 @@ public class ScreenshotRecorder { @Before public void initRecorder() { - context = InstrumentationRegistry.getTargetContext(); + context = InstrumentationRegistry.getInstrumentation().getTargetContext(); openScale = OpenScale.getInstance(); // Set first start to true to get the user add dialog diff --git a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothTrisaBodyAnalyze.java b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothTrisaBodyAnalyze.java index 10ceaf83..f7b63531 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothTrisaBodyAnalyze.java +++ b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothTrisaBodyAnalyze.java @@ -255,7 +255,17 @@ public class BluetoothTrisaBodyAnalyze extends BluetoothCommunication { private void onScaleMeasurumentReceived(byte[] data) { ScaleUser user = OpenScale.getInstance().getSelectedScaleUser(); + ScaleMeasurement measurement = parseScaleMeasurementData(data, user); + if (measurement == null) { + Timber.e("Failed to parse scale measure measurement data: %s", byteInHex(data)); + return; + } + + addScaleData(measurement); + } + + public ScaleMeasurement parseScaleMeasurementData(byte[] data, ScaleUser user) { // data contains: // // 1 byte: info about presence of other fields: @@ -272,15 +282,14 @@ public class BluetoothTrisaBodyAnalyze extends BluetoothCommunication { // Check that we have at least weight & timestamp, which is the minimum information that // ScaleMeasurement needs. if (data.length < 9) { - return; // data is too short + return null; // data is too short } byte infoByte = data[0]; boolean hasTimestamp = (infoByte & 1) == 1; boolean hasResistance1 = (infoByte & 2) == 2; boolean hasResistance2 = (infoByte & 4) == 4; if (!hasTimestamp) { - Timber.e("Failed to parse scale measure measurement data: %s", byteInHex(data)); - return; + return null; } float weightKg = getBase10Float(data, 1); int deviceTimestamp = Converters.fromSignedInt32Le(data, 5); @@ -307,7 +316,7 @@ public class BluetoothTrisaBodyAnalyze extends BluetoothCommunication { measurement.setBone(trisaBodyAnalyzeLib.getBone(weightKg, impedance)); } - addScaleData(measurement); + return measurement; } /** Write a single command byte, without any arguments. */ @@ -363,17 +372,17 @@ public class BluetoothTrisaBodyAnalyze extends BluetoothCommunication { * * @throws IndexOutOfBoundsException if {@code offset < 0} or {@code offset + 4> data.length} */ - private float getBase10Float(byte[] data, int offset) { + public float getBase10Float(byte[] data, int offset) { int mantissa = Converters.fromUnsignedInt24Le(data, offset); int exponent = data[offset + 3]; // note: byte is signed. - return mantissa * (float)Math.pow(10, exponent); + return (float)(mantissa * Math.pow(10, exponent)); } - private int convertJavaTimestampToDevice(long javaTimestampMillis) { + public int convertJavaTimestampToDevice(long javaTimestampMillis) { return (int)((javaTimestampMillis + 500)/1000 - TIMESTAMP_OFFSET_SECONDS); } - private long convertDeviceTimestampToJava(int deviceTimestampSeconds) { + public long convertDeviceTimestampToJava(int deviceTimestampSeconds) { return 1000 * (TIMESTAMP_OFFSET_SECONDS + (long)deviceTimestampSeconds); }