Table shows measurements from different user, allows to dupliate measurement, and crashes
Describe the bug
Currently, with my Sanitas SBF70, measurements of 2 users get falsely imported into one user (will open separate ticket). This makes me re-assign the wrong-user-measurements quite often. To make this easier, I go to the "Table" view, click on each wrongly-assigned measurement, edit, change user, save, go back to "Table", and find the next wrong one. However, it seems the table is not updated to reflect the underlying database state (assumption without looking into the code, sorry). This leads to a state where the user can open⇒edit⇒change user⇒save the measurement a 2nd time. This raises a unexpected UNIQUE constraint failed: scaleMeasurements.userId on save, crashing the app.
The best fix would be to make the table update and reflect the state of the underlying data as soon as the user comes back from the "measurement detail-view" to the table, so that it will be a) more clear, and b) impossible to trigger this.
To Reproduce Steps to reproduce the behavior:
- Have some need to re-assign a measurement to a different user
- Switch to table-view
- Find measurement you want to re-assign
- Make sure the measurement to re-assign is not the top-of-the-list item
- Open measurement, assign different user, save
- Go "back" to table view
- Find that re-assigned measurement is still shown (although it should not be part of the current user anymore)
- Repeat the edit, change user, save process
- :boom: crash with below stacktrace
Reproduced with latest dev version: No, only openScale v2.3.5 (54), SDK 29, Xiaomi MI 8 from F-Droid. Will attempt and report back (however, commits show nothing that sounds like it could fix this)
Expected behavior The table should get and reflect that the measurement is moved to the other user. That way, it would not be possible to trigger this duplicate-move-duplicates-data bug.
Debug log No debug-log, but stacktrace:
Build version: 2.3.5
Build date: 1981-01-01 01:01:02
Current date: 2021-01-26 09:05:42
Device: Xiaomi MI 8
OS version: Android 10 (SDK 29)
Stack trace:
android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: scaleMeasurements.userId, scaleMeasurements.datetime (code 2067 SQLITE_CONSTRAINT_UNIQUE)
at android.database.sqlite.SQLiteConnection.nativeExecuteForChangedRowCount(Native Method)
at android.database.sqlite.SQLiteConnection.executeForChangedRowCount(SQLiteConnection.java:831)
at android.database.sqlite.SQLiteSession.executeForChangedRowCount(SQLiteSession.java:756)
at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:66)
at androidx.sqlite.db.framework.FrameworkSQLiteStatement.executeUpdateDelete(FrameworkSQLiteStatement.java:46)
at androidx.room.EntityDeletionOrUpdateAdapter.handle(EntityDeletionOrUpdateAdapter.java:70)
at com.health.openscale.core.database.ScaleMeasurementDAO_Impl.update(ScaleMeasurementDAO_Impl.java:174)
at com.health.openscale.core.OpenScale.updateScaleMeasurement(OpenScale.java:405)
at com.health.openscale.gui.measurement.MeasurementEntryFragment.saveScaleData(MeasurementEntryFragment.java:346)
at com.health.openscale.gui.measurement.MeasurementEntryFragment.onOptionsItemSelected(MeasurementEntryFragment.java:200)
at androidx.fragment.app.Fragment.performOptionsItemSelected(Fragment.java:2830)
at androidx.fragment.app.FragmentManager.dispatchOptionsItemSelected(FragmentManager.java:2717)
at androidx.fragment.app.Fragment.performOptionsItemSelected(Fragment.java:2834)
at androidx.fragment.app.FragmentManager.dispatchOptionsItemSelected(FragmentManager.java:2717)
at androidx.fragment.app.FragmentController.dispatchOptionsItemSelected(FragmentController.java:412)
at androidx.fragment.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:389)
at androidx.appcompat.app.AppCompatActivity.onMenuItemSelected(AppCompatActivity.java:228)
at androidx.appcompat.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:109)
at androidx.appcompat.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:109)
at androidx.appcompat.app.ToolbarActionBar$2.onMenuItemClick(ToolbarActionBar.java:65)
at androidx.appcompat.widget.Toolbar$1.onMenuItemClick(Toolbar.java:207)
at androidx.appcompat.widget.ActionMenuView$MenuBuilderCallback.onMenuItemSelected(ActionMenuView.java:779)
at androidx.appcompat.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:834)
at androidx.appcompat.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:158)
at androidx.appcompat.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:985)
at androidx.appcompat.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:975)
at androidx.appcompat.widget.ActionMenuView.invokeItem(ActionMenuView.java:623)
at androidx.appcompat.view.menu.ActionMenuItemView.onClick(ActionMenuItemView.java:151)
at android.view.View.performClick(View.java:7259)
at android.view.View.performClickInternal(View.java:7236)
at android.view.View.access$3600(View.java:801)
at android.view.View$PerformClick.run(View.java:27892)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:491)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:940)
Find that re-assigned measurement is still shown (although it should not be part of the current user anymore)
I can't reproduce this crash. I can't find the re-assigned measurement anymore if I go back to the table view?
Thanks for your reply! Would it maybe helpful if i can dump the database in the state before this occurs? Otherwise I could also attempt to additionally capture a debug log when this happens next.
Finally, maybe this is also just a follow-up-error of the "wrong-user-assignment" I mentioned, for which I haven’t been able capture a nice enough log yet to open a good issue. Maybe we can (if the above 2 options don’t sound good to you) leave this open until I can open that other issue, and then see if this is a followup-error?
Hi,
today, I was able to reproduce the bug. The attached log captures the sync process. Here is a screencapture of the crash: https://tmp.kanojo.de/openscale%20crash.mp4
Furthermore, I was able to copy out the sqlite database from before the crash: https://tmp.kanojo.de/openScale.db
Finally, here is the debug log saved while sync'ing: openScale_2021-02-14_10-38.txt
The traceback from the crash:
Build version: 2.3.5
Build date: 1981-01-01 01:01:02
Current date: 2021-02-14 11:42:07
Device: Xiaomi MI 8
OS version: Android 10 (SDK 29)
Stack trace:
android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: scaleMeasurements.userId, scaleMeasurements.datetime (code 2067 SQLITE_CONSTRAINT_UNIQUE)
at android.database.sqlite.SQLiteConnection.nativeExecuteForChangedRowCount(Native Method)
at android.database.sqlite.SQLiteConnection.executeForChangedRowCount(SQLiteConnection.java:831)
at android.database.sqlite.SQLiteSession.executeForChangedRowCount(SQLiteSession.java:756)
at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:66)
at androidx.sqlite.db.framework.FrameworkSQLiteStatement.executeUpdateDelete(FrameworkSQLiteStatement.java:46)
at androidx.room.EntityDeletionOrUpdateAdapter.handle(EntityDeletionOrUpdateAdapter.java:70)
at com.health.openscale.core.database.ScaleMeasurementDAO_Impl.update(ScaleMeasurementDAO_Impl.java:174)
at com.health.openscale.core.OpenScale.updateScaleMeasurement(OpenScale.java:405)
at com.health.openscale.gui.measurement.MeasurementEntryFragment.saveScaleData(MeasurementEntryFragment.java:346)
at com.health.openscale.gui.measurement.MeasurementEntryFragment.onOptionsItemSelected(MeasurementEntryFragment.java:200)
at androidx.fragment.app.Fragment.performOptionsItemSelected(Fragment.java:2830)
at androidx.fragment.app.FragmentManager.dispatchOptionsItemSelected(FragmentManager.java:2717)
at androidx.fragment.app.Fragment.performOptionsItemSelected(Fragment.java:2834)
at androidx.fragment.app.FragmentManager.dispatchOptionsItemSelected(FragmentManager.java:2717)
at androidx.fragment.app.FragmentController.dispatchOptionsItemSelected(FragmentController.java:412)
at androidx.fragment.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:389)
at androidx.appcompat.app.AppCompatActivity.onMenuItemSelected(AppCompatActivity.java:228)
at androidx.appcompat.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:109)
at androidx.appcompat.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:109)
at androidx.appcompat.app.ToolbarActionBar$2.onMenuItemClick(ToolbarActionBar.java:65)
at androidx.appcompat.widget.Toolbar$1.onMenuItemClick(Toolbar.java:207)
at androidx.appcompat.widget.ActionMenuView$MenuBuilderCallback.onMenuItemSelected(ActionMenuView.java:779)
at androidx.appcompat.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:834)
at androidx.appcompat.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:158)
at androidx.appcompat.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:985)
at androidx.appcompat.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:975)
at androidx.appcompat.widget.ActionMenuView.invokeItem(ActionMenuView.java:623)
at androidx.appcompat.view.menu.ActionMenuItemView.onClick(ActionMenuItemView.java:151)
at android.view.View.performClick(View.java:7259)
at android.view.View.performClickInternal(View.java:7236)
at android.view.View.access$3600(View.java:801)
at android.view.View$PerformClick.run(View.java:27892)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:491)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:940)
What was happening to me was:
- Import data from scale
- Some new measurements from user 2 (
tig) get imported onto user 1 (bar) - Some measurements which already exist for user 2 (
tig) get imported onto user 1 (bar) - Fix new measurements that are visibly wrong-user in user 1 by assigning to user 2
- Fix already-existing-in-user-2 measurement that were re-imported onto user 1 by assigning to user 2
- ⇒ :boom:
So, I’m not sure how this all plays together, but there seem to be a few problems:
- Old (already-imported) measurements seem to persist on scale, and can get re-imported
- Measurements get imported onto the wrong user
- When manually "fixing" one kind of errornously imported measurements (already-imported + wrong-user), the "target" measurement for the correct user already exists, thus throwing the
UNIQUE Constrainterror …
Hope this information helps by reproducing and tracking down the error …
Hello @oliexdev , I have been using the openscale pro app on my Android phone. I face the same issue reported here with every sync. Data points from another user(>20kg difference) randomly gets synced/assigned to my user table. Sometime setting the users works and many times the app crashes. With the new trend feature, having others users weights in my list also spoils the trend and makes it unreliable to use so had to manually check and delete or correct all wrong entries. Would be good to have this fixed. Please let me know if there is any thing I can share to help investigate and fix.