From d17e8fcbfb87fce71440dd4930c5da86b8f347de Mon Sep 17 00:00:00 2001 From: Alinson Xavier Date: Sat, 10 Jun 2017 15:28:12 -0400 Subject: [PATCH 1/4] Bump version to 1.7.5 --- app/src/main/AndroidManifest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 40d1e8a7c..9e7185d46 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -21,8 +21,8 @@ + android:versionCode="32" + android:versionName="1.7.5"> From d727dabb2bf4dd43844d3a9582f159e6efb104c5 Mon Sep 17 00:00:00 2001 From: Alinson Xavier Date: Sat, 10 Jun 2017 15:30:51 -0400 Subject: [PATCH 2/4] Fix snooze button on notifications --- .../java/org/isoron/uhabits/receivers/ReminderController.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/isoron/uhabits/receivers/ReminderController.java b/app/src/main/java/org/isoron/uhabits/receivers/ReminderController.java index 22fd4bcd0..8e6429696 100644 --- a/app/src/main/java/org/isoron/uhabits/receivers/ReminderController.java +++ b/app/src/main/java/org/isoron/uhabits/receivers/ReminderController.java @@ -28,6 +28,8 @@ import org.isoron.uhabits.utils.*; import javax.inject.*; +import static org.isoron.uhabits.utils.DateUtils.*; + @ReceiverScope public class ReminderController { @@ -66,7 +68,7 @@ public class ReminderController { long snoozeInterval = preferences.getSnoozeInterval(); - long now = DateUtils.getLocalTime(); + long now = applyTimezone(getLocalTime()); long reminderTime = now + snoozeInterval * 60 * 1000; reminderScheduler.schedule(habit, reminderTime); From e06ace9ea868d13cf32a58ddbd60645c57ce4c3b Mon Sep 17 00:00:00 2001 From: Alinson Xavier Date: Sat, 10 Jun 2017 15:38:21 -0400 Subject: [PATCH 3/4] Fix ArrayIndexOutOfBoundsException on FrequencyChart --- .../isoron/uhabits/activities/common/views/FrequencyChart.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/isoron/uhabits/activities/common/views/FrequencyChart.java b/app/src/main/java/org/isoron/uhabits/activities/common/views/FrequencyChart.java index fa1d38214..7c0527702 100644 --- a/app/src/main/java/org/isoron/uhabits/activities/common/views/FrequencyChart.java +++ b/app/src/main/java/org/isoron/uhabits/activities/common/views/FrequencyChart.java @@ -256,7 +256,7 @@ public class FrequencyChart extends ScrollableChart float scale = 1.0f/maxFreq * value; float radius = maxRadius * scale; - int colorIndex = Math.round((colors.length-1) * scale); + int colorIndex = Math.min(colors.length - 1, Math.round((colors.length - 1) * scale)); pGraph.setColor(colors[colorIndex]); canvas.drawCircle(rect.centerX(), rect.centerY(), radius, pGraph); } From fe1513bb644810f1b3368b53fa2c7703c625a035 Mon Sep 17 00:00:00 2001 From: Alinson Xavier Date: Sat, 10 Jun 2017 16:48:53 -0400 Subject: [PATCH 4/4] Fix race conditions on SQLiteScoreList --- .../org/isoron/uhabits/BaseAndroidTest.java | 21 ++++++ .../models/sqlite/SQLiteScoreListTest.java | 66 ++++++++++++------- .../org/isoron/uhabits/models/ScoreList.java | 2 +- .../models/sqlite/SQLiteScoreList.java | 7 +- 4 files changed, 69 insertions(+), 27 deletions(-) diff --git a/app/src/androidTest/java/org/isoron/uhabits/BaseAndroidTest.java b/app/src/androidTest/java/org/isoron/uhabits/BaseAndroidTest.java index 36f4df5d3..f82959eb2 100644 --- a/app/src/androidTest/java/org/isoron/uhabits/BaseAndroidTest.java +++ b/app/src/androidTest/java/org/isoron/uhabits/BaseAndroidTest.java @@ -67,6 +67,8 @@ public class BaseAndroidTest protected ModelFactory modelFactory; + private boolean isDone = false; + @Before public void setUp() { @@ -117,6 +119,25 @@ public class BaseAndroidTest assertTrue(latch.await(60, TimeUnit.SECONDS)); } + protected void runConcurrently(Runnable... runnableList) throws Exception + { + isDone = false; + ExecutorService executor = Executors.newFixedThreadPool(100); + List futures = new LinkedList<>(); + for (Runnable r : runnableList) + futures.add(executor.submit(() -> + { + while (!isDone) r.run(); + return null; + })); + + Thread.sleep(3000); + isDone = true; + executor.shutdown(); + for(Future f : futures) f.get(); + while (!executor.isTerminated()) Thread.sleep(50); + } + protected void setTheme(@StyleRes int themeId) { targetContext.setTheme(themeId); diff --git a/app/src/androidTest/java/org/isoron/uhabits/models/sqlite/SQLiteScoreListTest.java b/app/src/androidTest/java/org/isoron/uhabits/models/sqlite/SQLiteScoreListTest.java index db3f1aaa8..a11b7908b 100644 --- a/app/src/androidTest/java/org/isoron/uhabits/models/sqlite/SQLiteScoreListTest.java +++ b/app/src/androidTest/java/org/isoron/uhabits/models/sqlite/SQLiteScoreListTest.java @@ -61,29 +61,6 @@ public class SQLiteScoreListTest extends BaseAndroidTest day = DateUtils.millisecondsInOneDay; } - @Test - public void testGetAll() - { - List list = scores.toList(); - assertThat(list.size(), equalTo(121)); - assertThat(list.get(0).getTimestamp(), equalTo(today)); - assertThat(list.get(10).getTimestamp(), equalTo(today - 10 * day)); - } - - @Test - public void testInvalidateNewerThan() - { - scores.getTodayValue(); // force recompute - List records = getAllRecords(); - assertThat(records.size(), equalTo(121)); - - scores.invalidateNewerThan(today - 10 * day); - - records = getAllRecords(); - assertThat(records.size(), equalTo(110)); - assertThat(records.get(0).timestamp, equalTo(today - 11 * day)); - } - @Test public void testAdd() { @@ -101,6 +78,15 @@ public class SQLiteScoreListTest extends BaseAndroidTest assertThat(records.get(0).timestamp, equalTo(today)); } + @Test + public void testGetAll() + { + List list = scores.toList(); + assertThat(list.size(), equalTo(121)); + assertThat(list.get(0).getTimestamp(), equalTo(today)); + assertThat(list.get(10).getTimestamp(), equalTo(today - 10 * day)); + } + @Test public void testGetByInterval() { @@ -115,6 +101,16 @@ public class SQLiteScoreListTest extends BaseAndroidTest assertThat(list.get(7).getTimestamp(), equalTo(today - 10 * day)); } + @Test + public void testGetByInterval_concurrent() throws Exception + { + Runnable block1 = () -> scores.invalidateNewerThan(0); + Runnable block2 = + () -> assertThat(scores.getByInterval(today, today).size(), + equalTo(1)); + runConcurrently(block1, block2); + } + @Test public void testGetByInterval_withLongInterval() { @@ -125,6 +121,30 @@ public class SQLiteScoreListTest extends BaseAndroidTest assertThat(list.size(), equalTo(201)); } + @Test + public void testGetTodayValue_concurrent() throws Exception + { + Runnable block1 = () -> scores.invalidateNewerThan(0); + Runnable block2 = + () -> assertThat(scores.getTodayValue(), equalTo(18407827)); + + runConcurrently(block1, block2); + } + + @Test + public void testInvalidateNewerThan() + { + scores.getTodayValue(); // force recompute + List records = getAllRecords(); + assertThat(records.size(), equalTo(121)); + + scores.invalidateNewerThan(today - 10 * day); + + records = getAllRecords(); + assertThat(records.size(), equalTo(110)); + assertThat(records.get(0).timestamp, equalTo(today - 11 * day)); + } + private List getAllRecords() { return new Select() diff --git a/app/src/main/java/org/isoron/uhabits/models/ScoreList.java b/app/src/main/java/org/isoron/uhabits/models/ScoreList.java index fa87e3b74..a77bfa666 100644 --- a/app/src/main/java/org/isoron/uhabits/models/ScoreList.java +++ b/app/src/main/java/org/isoron/uhabits/models/ScoreList.java @@ -81,7 +81,7 @@ public abstract class ScoreList implements Iterable * @param timestamp the timestamp of a day * @return score value for that day */ - public final synchronized int getValue(long timestamp) + public synchronized final int getValue(long timestamp) { compute(timestamp, timestamp); Score s = getComputedByTimestamp(timestamp); diff --git a/app/src/main/java/org/isoron/uhabits/models/sqlite/SQLiteScoreList.java b/app/src/main/java/org/isoron/uhabits/models/sqlite/SQLiteScoreList.java index 7589400a3..7bf739cd2 100644 --- a/app/src/main/java/org/isoron/uhabits/models/sqlite/SQLiteScoreList.java +++ b/app/src/main/java/org/isoron/uhabits/models/sqlite/SQLiteScoreList.java @@ -100,7 +100,8 @@ public class SQLiteScoreList extends ScoreList @NonNull @Override - public List getByInterval(long fromTimestamp, long toTimestamp) + public synchronized List getByInterval(long fromTimestamp, + long toTimestamp) { check(habit.getId()); compute(fromTimestamp, toTimestamp); @@ -137,7 +138,7 @@ public class SQLiteScoreList extends ScoreList } @Override - public int getTodayValue() + public synchronized int getTodayValue() { if (cache == null || cache.expired()) cache = new CachedData(super.getTodayValue()); @@ -146,7 +147,7 @@ public class SQLiteScoreList extends ScoreList } @Override - public void invalidateNewerThan(long timestamp) + public synchronized void invalidateNewerThan(long timestamp) { cache = null; invalidateStatement.bindLong(1, habit.getId());