Apply google-java-format 1.5.1

pull/699/head
Alex Baker 8 years ago
parent d983167976
commit 02a112e3b3

@ -5,9 +5,7 @@ import javax.inject.Inject;
public class FlavorSetup { public class FlavorSetup {
@Inject @Inject
public FlavorSetup() { public FlavorSetup() {}
}
public void setup() { public void setup() {}
}
} }

@ -28,24 +28,23 @@ public class Tracker {
analytics = GoogleAnalytics.getInstance(context); analytics = GoogleAnalytics.getInstance(context);
tracker = analytics.newTracker(R.xml.google_analytics); tracker = analytics.newTracker(R.xml.google_analytics);
tracker.setAppVersion(Integer.toString(BuildConfig.VERSION_CODE)); tracker.setAppVersion(Integer.toString(BuildConfig.VERSION_CODE));
final StandardExceptionParser standardExceptionParser = new StandardExceptionParser(context, final StandardExceptionParser standardExceptionParser =
null); new StandardExceptionParser(context, null);
exceptionParser = (thread, throwable) -> { exceptionParser =
StringBuilder stack = new StringBuilder() (thread, throwable) -> {
StringBuilder stack =
new StringBuilder()
.append(standardExceptionParser.getDescription(thread, throwable)) .append(standardExceptionParser.getDescription(thread, throwable))
.append("\n") .append("\n")
.append(throwable.getClass().getName()) .append(throwable.getClass().getName())
.append("\n"); .append("\n");
for (StackTraceElement element : throwable.getStackTrace()) { for (StackTraceElement element : throwable.getStackTrace()) {
stack.append(element.toString()) stack.append(element.toString()).append("\n");
.append("\n");
} }
return stack.toString(); return stack.toString();
}; };
ExceptionReporter reporter = new ExceptionReporter( ExceptionReporter reporter =
tracker, new ExceptionReporter(tracker, Thread.getDefaultUncaughtExceptionHandler(), context);
Thread.getDefaultUncaughtExceptionHandler(),
context);
reporter.setExceptionParser(exceptionParser); reporter.setExceptionParser(exceptionParser);
Thread.setDefaultUncaughtExceptionHandler(reporter); Thread.setDefaultUncaughtExceptionHandler(reporter);
} }
@ -60,7 +59,8 @@ public class Tracker {
public void reportException(Thread thread, Throwable t) { public void reportException(Thread thread, Throwable t) {
Timber.e(t, t.getMessage()); Timber.e(t, t.getMessage());
tracker.send(new HitBuilders.ExceptionBuilder() tracker.send(
new HitBuilders.ExceptionBuilder()
.setDescription(exceptionParser.getDescription(thread.getName(), t)) .setDescription(exceptionParser.getDescription(thread.getName(), t))
.setFatal(false) .setFatal(false)
.build()); .build());
@ -83,9 +83,8 @@ public class Tracker {
} }
private void reportEvent(int category, String action, String label) { private void reportEvent(int category, String action, String label) {
HitBuilders.EventBuilder eventBuilder = new HitBuilders.EventBuilder() HitBuilders.EventBuilder eventBuilder =
.setCategory(context.getString(category)) new HitBuilders.EventBuilder().setCategory(context.getString(category)).setAction(action);
.setAction(action);
if (!Strings.isNullOrEmpty(label)) { if (!Strings.isNullOrEmpty(label)) {
eventBuilder.setLabel(label); eventBuilder.setLabel(label);
} }

@ -7,26 +7,22 @@ import javax.inject.Inject;
public class PurchaseHelper { public class PurchaseHelper {
@Inject @Inject
public PurchaseHelper() { public PurchaseHelper() {}
}
public boolean purchase(
public boolean purchase(final Activity activity, final Activity activity,
final String sku, final String pref, final String sku,
final int requestCode, final PurchaseHelperCallback callback) { final String pref,
final int requestCode,
final PurchaseHelperCallback callback) {
callback.purchaseCompleted(false, sku); callback.purchaseCompleted(false, sku);
return false; return false;
} }
public void handleActivityResult(PurchaseHelperCallback callback, int requestCode, int resultCode, public void handleActivityResult(
Intent data) { PurchaseHelperCallback callback, int requestCode, int resultCode, Intent data) {}
}
public void disposeIabHelper() {
}
public void consumePurchases() { public void disposeIabHelper() {}
} public void consumePurchases() {}
} }

@ -8,9 +8,7 @@ import javax.inject.Inject;
public class PlayServices { public class PlayServices {
@Inject @Inject
public PlayServices() { public PlayServices() {}
}
public boolean isPlayServicesAvailable() { public boolean isPlayServicesAvailable() {
return false; return false;
@ -20,9 +18,7 @@ public class PlayServices {
return false; return false;
} }
public void resolve(Activity activity) { public void resolve(Activity activity) {}
}
public String getStatus() { public String getStatus() {
return null; return null;
@ -32,8 +28,8 @@ public class PlayServices {
return false; return false;
} }
public void getAuthToken(GtasksLoginActivity gtasksLoginActivity, String a, public void getAuthToken(
GtasksLoginActivity.AuthResultHandler authResultHandler) { GtasksLoginActivity gtasksLoginActivity,
String a,
} GtasksLoginActivity.AuthResultHandler authResultHandler) {}
} }

@ -8,19 +8,11 @@ import org.tasks.data.Location;
public class GeofenceApi { public class GeofenceApi {
@Inject @Inject
public GeofenceApi() { public GeofenceApi() {}
} public void register(List<Location> activeGeofences) {}
public void register(List<Location> activeGeofences) { public void cancel(Location geofence) {}
} public void cancel(List<Location> geofences) {}
public void cancel(Location geofence) {
}
public void cancel(List<Location> geofences) {
}
} }

@ -1,5 +1,3 @@
package org.tasks.location; package org.tasks.location;
public class GeofenceTransitionsIntentService { public class GeofenceTransitionsIntentService {}
}

@ -1,12 +1,10 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.test; package com.todoroo.andlib.test;
import static android.support.test.InstrumentationRegistry.getTargetContext; import static android.support.test.InstrumentationRegistry.getTargetContext;
import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertFalse;
@ -24,18 +22,15 @@ import org.junit.runner.RunWith;
import org.tasks.R; import org.tasks.R;
/** /**
* Tests translations for consistency with the default values. You must * Tests translations for consistency with the default values. You must extend this class and create
* extend this class and create it with your own values for strings * it with your own values for strings and arrays.
* and arrays.
* *
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
*/ */
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class TranslationTests { public class TranslationTests {
/** /** Loop through each locale and call runnable */
* Loop through each locale and call runnable
*/
private void forEachLocale(Callback<Resources> callback) { private void forEachLocale(Callback<Resources> callback) {
Locale[] locales = Locale.getAvailableLocales(); Locale[] locales = Locale.getAvailableLocales();
for (Locale locale : locales) { for (Locale locale : locales) {
@ -50,9 +45,7 @@ public class TranslationTests {
return new Resources(resources.getAssets(), resources.getDisplayMetrics(), configuration); return new Resources(resources.getAssets(), resources.getDisplayMetrics(), configuration);
} }
/** /** Internal test of format string parser */
* Internal test of format string parser
*/
@Test @Test
public void testFormatStringParser() { public void testFormatStringParser() {
String s = "abc"; String s = "abc";
@ -84,8 +77,8 @@ public class TranslationTests {
} }
/** /**
* Test that the format specifiers in translations match exactly the * Test that the format specifiers in translations match exactly the translations in the default
* translations in the default text * text
*/ */
@Test @Test
public void testFormatStringsMatch() { public void testFormatStringsMatch() {
@ -101,12 +94,12 @@ public class TranslationTests {
formatStrings[i] = new FormatStringData(string); formatStrings[i] = new FormatStringData(string);
} catch (Exception e) { } catch (Exception e) {
String name = resources.getResourceName(strings[i]); String name = resources.getResourceName(strings[i]);
failures.append(String.format("error opening %s: %s\n", failures.append(String.format("error opening %s: %s\n", name, e.getMessage()));
name, e.getMessage()));
} }
} }
forEachLocale(r -> { forEachLocale(
r -> {
Locale locale = r.getConfiguration().locale; Locale locale = r.getConfiguration().locale;
for (int i = 0; i < strings.length; i++) { for (int i = 0; i < strings.length; i++) {
try { try {
@ -118,13 +111,15 @@ public class TranslationTests {
FormatStringData newFS = new FormatStringData(string); FormatStringData newFS = new FormatStringData(string);
if (!newFS.matches(formatStrings[i])) { if (!newFS.matches(formatStrings[i])) {
String name = r.getResourceName(strings[i]); String name = r.getResourceName(strings[i]);
failures.append(String.format("%s (%s): %s != %s\n", failures.append(
name, locale.toString(), newFS, formatStrings[i])); String.format(
"%s (%s): %s != %s\n", name, locale.toString(), newFS, formatStrings[i]));
} }
} catch (Exception e) { } catch (Exception e) {
String name = r.getResourceName(strings[i]); String name = r.getResourceName(strings[i]);
failures.append(String.format("%s: error opening %s: %s\n", failures.append(
locale.toString(), name, e.getMessage())); String.format(
"%s: error opening %s: %s\n", locale.toString(), name, e.getMessage()));
} }
} }
}); });
@ -132,27 +127,24 @@ public class TranslationTests {
assertTrue(failures.toString(), errorCount(failures) == 0); assertTrue(failures.toString(), errorCount(failures) == 0);
} }
/** /** check if string contains contains substrings */
* check if string contains contains substrings
*/
private void contains(Resources r, int resource, StringBuilder failures, String expected) { private void contains(Resources r, int resource, StringBuilder failures, String expected) {
String translation = r.getString(resource); String translation = r.getString(resource);
if (!translation.contains(expected)) { if (!translation.contains(expected)) {
Locale locale = r.getConfiguration().locale; Locale locale = r.getConfiguration().locale;
String name = r.getResourceName(resource); String name = r.getResourceName(resource);
failures.append(String.format("%s: %s did not contain: %s\n", failures.append(
locale.toString(), name, expected)); String.format("%s: %s did not contain: %s\n", locale.toString(), name, expected));
} }
} }
/** /** Test dollar sign resources */
* Test dollar sign resources
*/
@Test @Test
public void testSpecialStringsMatch() { public void testSpecialStringsMatch() {
final StringBuilder failures = new StringBuilder(); final StringBuilder failures = new StringBuilder();
forEachLocale(r -> { forEachLocale(
r -> {
contains(r, R.string.CFC_tag_text, failures, "?"); contains(r, R.string.CFC_tag_text, failures, "?");
contains(r, R.string.CFC_title_contains_text, failures, "?"); contains(r, R.string.CFC_title_contains_text, failures, "?");
contains(r, R.string.CFC_dueBefore_text, failures, "?"); contains(r, R.string.CFC_dueBefore_text, failures, "?");
@ -160,13 +152,10 @@ public class TranslationTests {
contains(r, R.string.CFC_gtasks_list_text, failures, "?"); contains(r, R.string.CFC_gtasks_list_text, failures, "?");
}); });
assertEquals(failures.toString(), 0, assertEquals(failures.toString(), 0, failures.toString().replaceAll("[^\n]", "").length());
failures.toString().replaceAll("[^\n]", "").length());
} }
/** /** Count newlines */
* Count newlines
*/
private int errorCount(StringBuilder failures) { private int errorCount(StringBuilder failures) {
int count = 0; int count = 0;
int pos = -1; int pos = -1;
@ -179,9 +168,7 @@ public class TranslationTests {
} }
} }
/** /** @return an array of all string resource id's */
* @return an array of all string resource id's
*/
private int[] getResourceIds(Class<?> resources) { private int[] getResourceIds(Class<?> resources) {
Field[] fields = resources.getDeclaredFields(); Field[] fields = resources.getDeclaredFields();
List<Integer> ids = new ArrayList<>(fields.length); List<Integer> ids = new ArrayList<>(fields.length);
@ -208,14 +195,10 @@ public class TranslationTests {
private static final char[] scratch = new char[10]; private static final char[] scratch = new char[10];
/** /** format characters */
* format characters
*/
final char[] characters; final char[] characters;
/** /** the original string */
* the original string
*/
final String string; final String string;
public FormatStringData(String string) { public FormatStringData(String string) {
@ -240,9 +223,7 @@ public class TranslationTests {
} }
} }
/** /** test that the characters match */
* test that the characters match
*/
boolean matches(FormatStringData other) { boolean matches(FormatStringData other) {
if (characters.length != other.characters.length) { if (characters.length != other.characters.length) {
return false; return false;
@ -259,7 +240,6 @@ public class TranslationTests {
} else if (characters[i] != other.characters[i]) { } else if (characters[i] != other.characters[i]) {
return false; return false;
} }
} }
return true; return true;
} }

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.utility; package com.todoroo.andlib.utility;
import static android.support.test.InstrumentationRegistry.getTargetContext; import static android.support.test.InstrumentationRegistry.getTargetContext;
@ -66,7 +65,8 @@ public class DateUtilitiesTest {
@Test @Test
public void testTimeString() { public void testTimeString() {
forEachLocale(() -> { forEachLocale(
() -> {
DateTime d = newDateTime(); DateTime d = newDateTime();
DateUtilities.is24HourOverride = false; DateUtilities.is24HourOverride = false;
@ -85,7 +85,8 @@ public class DateUtilitiesTest {
@Test @Test
public void testDateString() { public void testDateString() {
forEachLocale(() -> { forEachLocale(
() -> {
DateTime d = newDateTime(); DateTime d = newDateTime();
for (int i = 0; i < 12; i++) { for (int i = 0; i < 12; i++) {
@ -122,16 +123,24 @@ public class DateUtilitiesTest {
@Test @Test
public void testGetDateStringHidingYear() { public void testGetDateStringHidingYear() {
freezeAt(newDate(2014, 1, 1)).thawAfter(new Snippet() {{ freezeAt(newDate(2014, 1, 1))
.thawAfter(
new Snippet() {
{
assertEquals("Jan 1", getDateString(newDateTime())); assertEquals("Jan 1", getDateString(newDateTime()));
}}); }
});
} }
@Test @Test
public void testGetDateStringWithDifferentYear() { public void testGetDateStringWithDifferentYear() {
freezeAt(newDate(2013, 12, 31)).thawAfter(new Snippet() {{ freezeAt(newDate(2013, 12, 31))
.thawAfter(
new Snippet() {
{
assertEquals("Jan 1 '14", getDateString(new DateTime(2014, 1, 1, 0, 0, 0))); assertEquals("Jan 1 '14", getDateString(new DateTime(2014, 1, 1, 0, 0, 0)));
}}); }
});
} }
@Test @Test
@ -139,9 +148,13 @@ public class DateUtilitiesTest {
DateTime now = new DateTime(2013, 12, 1, 12, 19, 45, 192); DateTime now = new DateTime(2013, 12, 1, 12, 19, 45, 192);
final long expected = new DateTime(2014, 1, 1, 12, 19, 45, 192).getMillis(); final long expected = new DateTime(2014, 1, 1, 12, 19, 45, 192).getMillis();
freezeAt(now).thawAfter(new Snippet() {{ freezeAt(now)
.thawAfter(
new Snippet() {
{
assertEquals(expected, oneMonthFromNow()); assertEquals(expected, oneMonthFromNow());
}}); }
});
} }
@Test @Test
@ -149,9 +162,13 @@ public class DateUtilitiesTest {
DateTime now = new DateTime(2013, 12, 31, 16, 31, 20, 597); DateTime now = new DateTime(2013, 12, 31, 16, 31, 20, 597);
final long expected = new DateTime(2014, 1, 31, 16, 31, 20, 597).getMillis(); final long expected = new DateTime(2014, 1, 31, 16, 31, 20, 597).getMillis();
freezeAt(now).thawAfter(new Snippet() {{ freezeAt(now)
.thawAfter(
new Snippet() {
{
assertEquals(expected, oneMonthFromNow()); assertEquals(expected, oneMonthFromNow());
}}); }
});
} }
@Test @Test
@ -159,9 +176,13 @@ public class DateUtilitiesTest {
final DateTime now = new DateTime(2013, 12, 31, 17, 17, 32, 900); final DateTime now = new DateTime(2013, 12, 31, 17, 17, 32, 900);
final long expected = new DateTime(2014, 7, 1, 17, 17, 32, 900).getMillis(); final long expected = new DateTime(2014, 7, 1, 17, 17, 32, 900).getMillis();
freezeAt(now).thawAfter(new Snippet() {{ freezeAt(now)
.thawAfter(
new Snippet() {
{
assertEquals(expected, addCalendarMonthsToUnixtime(now.getMillis(), 6)); assertEquals(expected, addCalendarMonthsToUnixtime(now.getMillis(), 6));
}}); }
});
} }
@Test @Test
@ -169,9 +190,13 @@ public class DateUtilitiesTest {
DateTime now = new DateTime(2014, 1, 31, 12, 54, 33, 175); DateTime now = new DateTime(2014, 1, 31, 12, 54, 33, 175);
final long expected = new DateTime(2014, 3, 3, 12, 54, 33, 175).getMillis(); final long expected = new DateTime(2014, 3, 3, 12, 54, 33, 175).getMillis();
freezeAt(now).thawAfter(new Snippet() {{ freezeAt(now)
.thawAfter(
new Snippet() {
{
assertEquals(expected, oneMonthFromNow()); assertEquals(expected, oneMonthFromNow());
}}); }
});
} }
@Test @Test
@ -179,17 +204,19 @@ public class DateUtilitiesTest {
DateTime now = new DateTime(2014, 2, 28, 9, 19, 7, 990); DateTime now = new DateTime(2014, 2, 28, 9, 19, 7, 990);
final long expected = new DateTime(2014, 3, 28, 9, 19, 7, 990).getMillis(); final long expected = new DateTime(2014, 3, 28, 9, 19, 7, 990).getMillis();
freezeAt(now).thawAfter(new Snippet() {{ freezeAt(now)
.thawAfter(
new Snippet() {
{
assertEquals(expected, oneMonthFromNow()); assertEquals(expected, oneMonthFromNow());
}}); }
});
} }
@Test @Test
public void testShouldGetStartOfDay() { public void testShouldGetStartOfDay() {
DateTime now = new DateTime(2014, 1, 3, 10, 41, 41, 520); DateTime now = new DateTime(2014, 1, 3, 10, 41, 41, 520);
assertEquals( assertEquals(now.startOfDay().getMillis(), getStartOfDay(now.getMillis()));
now.startOfDay().getMillis(),
getStartOfDay(now.getMillis()));
} }
@Test @Test
@ -216,101 +243,145 @@ public class DateUtilitiesTest {
@Test @Test
public void testAddMonthsToTimestamp() { public void testAddMonthsToTimestamp() {
assertEquals(newDate(2014, 1, 1).getMillis(), assertEquals(
newDate(2014, 1, 1).getMillis(),
addCalendarMonthsToUnixtime(newDate(2013, 12, 1).getMillis(), 1)); addCalendarMonthsToUnixtime(newDate(2013, 12, 1).getMillis(), 1));
assertEquals(newDate(2014, 12, 31).getMillis(), assertEquals(
newDate(2014, 12, 31).getMillis(),
addCalendarMonthsToUnixtime(newDate(2013, 12, 31).getMillis(), 12)); addCalendarMonthsToUnixtime(newDate(2013, 12, 31).getMillis(), 12));
} }
@Test @Test
public void testAddMonthsWithLessDays() { public void testAddMonthsWithLessDays() {
assertEquals(newDate(2014, 3, 3).getMillis(), assertEquals(
newDate(2014, 3, 3).getMillis(),
addCalendarMonthsToUnixtime(newDate(2013, 12, 31).getMillis(), 2)); addCalendarMonthsToUnixtime(newDate(2013, 12, 31).getMillis(), 2));
} }
@Test @Test
public void testAddMonthsWithMoreDays() { public void testAddMonthsWithMoreDays() {
assertEquals(newDate(2014, 1, 30).getMillis(), assertEquals(
newDate(2014, 1, 30).getMillis(),
addCalendarMonthsToUnixtime(newDate(2013, 11, 30).getMillis(), 2)); addCalendarMonthsToUnixtime(newDate(2013, 11, 30).getMillis(), 2));
} }
@Test @Test
public void usDateNoYear() { public void usDateNoYear() {
setLocale(Locale.US); setLocale(Locale.US);
freezeAt(new DateTime(2018, 1, 1)).thawAfter(() -> freezeAt(new DateTime(2018, 1, 1))
assertEquals("Jan 14", DateUtilities.getRelativeDateStringWithTime(getTargetContext(), .thawAfter(
new DateTime(2018, 1, 14).getMillis()))); () ->
assertEquals(
"Jan 14",
DateUtilities.getRelativeDateStringWithTime(
getTargetContext(), new DateTime(2018, 1, 14).getMillis())));
} }
@Test @Test
public void usDateWithYear() { public void usDateWithYear() {
setLocale(Locale.US); setLocale(Locale.US);
freezeAt(new DateTime(2017, 12, 12)).thawAfter(() -> freezeAt(new DateTime(2017, 12, 12))
assertEquals("Jan 14 '18", DateUtilities.getRelativeDateStringWithTime(getTargetContext(), .thawAfter(
new DateTime(2018, 1, 14).getMillis()))); () ->
assertEquals(
"Jan 14 '18",
DateUtilities.getRelativeDateStringWithTime(
getTargetContext(), new DateTime(2018, 1, 14).getMillis())));
} }
@Test @Test
public void germanDateNoYear() { public void germanDateNoYear() {
setLocale(Locale.GERMAN); setLocale(Locale.GERMAN);
freezeAt(new DateTime(2018, 1, 1)).thawAfter(() -> freezeAt(new DateTime(2018, 1, 1))
assertEquals("14 Jan.", DateUtilities.getRelativeDateStringWithTime(getTargetContext(), .thawAfter(
new DateTime(2018, 1, 14).getMillis()))); () ->
assertEquals(
"14 Jan.",
DateUtilities.getRelativeDateStringWithTime(
getTargetContext(), new DateTime(2018, 1, 14).getMillis())));
} }
@Test @Test
public void germanDateWithYear() { public void germanDateWithYear() {
setLocale(Locale.GERMAN); setLocale(Locale.GERMAN);
freezeAt(new DateTime(2017, 12, 12)).thawAfter(() -> freezeAt(new DateTime(2017, 12, 12))
assertEquals("14 Jan. '18", DateUtilities.getRelativeDateStringWithTime(getTargetContext(), .thawAfter(
new DateTime(2018, 1, 14).getMillis()))); () ->
assertEquals(
"14 Jan. '18",
DateUtilities.getRelativeDateStringWithTime(
getTargetContext(), new DateTime(2018, 1, 14).getMillis())));
} }
@Test @Test
public void koreanDateNoYear() { public void koreanDateNoYear() {
setLocale(Locale.KOREAN); setLocale(Locale.KOREAN);
freezeAt(new DateTime(2018, 1, 1)).thawAfter(() -> freezeAt(new DateTime(2018, 1, 1))
assertEquals("1월 14일", DateUtilities.getRelativeDateStringWithTime(getTargetContext(), .thawAfter(
new DateTime(2018, 1, 14).getMillis()))); () ->
assertEquals(
"1월 14일",
DateUtilities.getRelativeDateStringWithTime(
getTargetContext(), new DateTime(2018, 1, 14).getMillis())));
} }
@Test @Test
public void koreanDateWithYear() { public void koreanDateWithYear() {
setLocale(Locale.KOREAN); setLocale(Locale.KOREAN);
freezeAt(new DateTime(2017, 12, 12)).thawAfter(() -> freezeAt(new DateTime(2017, 12, 12))
assertEquals("18년 1월 14일", DateUtilities.getRelativeDateStringWithTime(getTargetContext(), .thawAfter(
new DateTime(2018, 1, 14).getMillis()))); () ->
assertEquals(
"18년 1월 14일",
DateUtilities.getRelativeDateStringWithTime(
getTargetContext(), new DateTime(2018, 1, 14).getMillis())));
} }
@Test @Test
public void japaneseDateNoYear() { public void japaneseDateNoYear() {
setLocale(Locale.JAPANESE); setLocale(Locale.JAPANESE);
freezeAt(new DateTime(2018, 1, 1)).thawAfter(() -> freezeAt(new DateTime(2018, 1, 1))
assertEquals("1月 14日", DateUtilities.getRelativeDateStringWithTime(getTargetContext(), .thawAfter(
new DateTime(2018, 1, 14).getMillis()))); () ->
assertEquals(
"1月 14日",
DateUtilities.getRelativeDateStringWithTime(
getTargetContext(), new DateTime(2018, 1, 14).getMillis())));
} }
@Test @Test
public void japaneseDateWithYear() { public void japaneseDateWithYear() {
setLocale(Locale.JAPANESE); setLocale(Locale.JAPANESE);
freezeAt(new DateTime(2017, 12, 12)).thawAfter(() -> freezeAt(new DateTime(2017, 12, 12))
assertEquals("18年 1月 14日", DateUtilities.getRelativeDateStringWithTime(getTargetContext(), .thawAfter(
new DateTime(2018, 1, 14).getMillis()))); () ->
assertEquals(
"18年 1月 14日",
DateUtilities.getRelativeDateStringWithTime(
getTargetContext(), new DateTime(2018, 1, 14).getMillis())));
} }
@Test @Test
public void chineseDateNoYear() { public void chineseDateNoYear() {
setLocale(Locale.CHINESE); setLocale(Locale.CHINESE);
freezeAt(new DateTime(2018, 1, 1)).thawAfter(() -> freezeAt(new DateTime(2018, 1, 1))
assertEquals("1月 14日", DateUtilities.getRelativeDateStringWithTime(getTargetContext(), .thawAfter(
new DateTime(2018, 1, 14).getMillis()))); () ->
assertEquals(
"1月 14日",
DateUtilities.getRelativeDateStringWithTime(
getTargetContext(), new DateTime(2018, 1, 14).getMillis())));
} }
@Test @Test
public void chineseDateWithYear() { public void chineseDateWithYear() {
setLocale(Locale.CHINESE); setLocale(Locale.CHINESE);
freezeAt(new DateTime(2017, 12, 12)).thawAfter(() -> freezeAt(new DateTime(2017, 12, 12))
assertEquals("18年 1月 14日", DateUtilities.getRelativeDateStringWithTime(getTargetContext(), .thawAfter(
new DateTime(2018, 1, 14).getMillis()))); () ->
assertEquals(
"18年 1月 14日",
DateUtilities.getRelativeDateStringWithTime(
getTargetContext(), new DateTime(2018, 1, 14).getMillis())));
} }
} }

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.dao; package com.todoroo.astrid.dao;
import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertEquals;
@ -24,9 +23,7 @@ public class TaskDaoTests extends InjectingTestCase {
@Inject TaskDao taskDao; @Inject TaskDao taskDao;
/** /** Test basic task creation, fetch, and save */
* Test basic task creation, fetch, and save
*/
@Test @Test
public void testTaskCreation() { public void testTaskCreation() {
assertEquals(0, taskDao.getAll().size()); assertEquals(0, taskDao.getAll().size());
@ -61,9 +58,7 @@ public class TaskDaoTests extends InjectingTestCase {
assertEquals("melancholy", task.getTitle()); assertEquals("melancholy", task.getTitle());
} }
/** /** Test various task fetch conditions */
* Test various task fetch conditions
*/
@Test @Test
public void testTaskConditions() { public void testTaskConditions() {
// create normal task // create normal task
@ -106,9 +101,7 @@ public class TaskDaoTests extends InjectingTestCase {
assertEquals(5, taskDao.getVisibleTasks().size()); assertEquals(5, taskDao.getVisibleTasks().size());
} }
/** /** Test task deletion */
* Test task deletion
*/
@Test @Test
public void testTDeletion() { public void testTDeletion() {
assertEquals(0, taskDao.getAll().size()); assertEquals(0, taskDao.getAll().size());
@ -125,9 +118,7 @@ public class TaskDaoTests extends InjectingTestCase {
assertEquals(0, taskDao.getAll().size()); assertEquals(0, taskDao.getAll().size());
} }
/** /** Test save without prior create doesn't work */
* Test save without prior create doesn't work
*/
@Test @Test
public void testSaveWithoutCreate() { public void testSaveWithoutCreate() {
// try to save task "happy" // try to save task "happy"
@ -140,9 +131,7 @@ public class TaskDaoTests extends InjectingTestCase {
assertEquals(0, taskDao.getAll().size()); assertEquals(0, taskDao.getAll().size());
} }
/** /** Test passing invalid task indices to various things */
* Test passing invalid task indices to various things
*/
@Test @Test
public void testInvalidIndex() { public void testInvalidIndex() {
assertEquals(0, taskDao.getAll().size()); assertEquals(0, taskDao.getAll().size());
@ -162,4 +151,3 @@ public class TaskDaoTests extends InjectingTestCase {
// TODO check eventing // TODO check eventing
} }

@ -88,7 +88,8 @@ public class TaskTest {
@Test @Test
public void testRemoveTimeForSpecificDay() { public void testRemoveTimeForSpecificDay() {
long expected = specificDueDate long expected =
specificDueDate
.withHourOfDay(12) .withHourOfDay(12)
.withMinuteOfHour(0) .withMinuteOfHour(0)
.withSecondOfMinute(0) .withSecondOfMinute(0)
@ -99,10 +100,7 @@ public class TaskTest {
@Test @Test
public void testRemoveSecondsForSpecificTime() { public void testRemoveSecondsForSpecificTime() {
long expected = specificDueDate long expected = specificDueDate.withSecondOfMinute(1).withMillisOfSecond(0).getMillis();
.withSecondOfMinute(1)
.withMillisOfSecond(0)
.getMillis();
assertEquals(expected, createDueDate(URGENCY_SPECIFIC_DAY_TIME, specificDueDate.getMillis())); assertEquals(expected, createDueDate(URGENCY_SPECIFIC_DAY_TIME, specificDueDate.getMillis()));
} }
@ -176,21 +174,29 @@ public class TaskTest {
@Test @Test
public void testTaskIsNotHiddenAtHideUntilTime() { public void testTaskIsNotHiddenAtHideUntilTime() {
final long now = currentTimeMillis(); final long now = currentTimeMillis();
freezeAt(now).thawAfter(new Snippet() {{ freezeAt(now)
.thawAfter(
new Snippet() {
{
Task task = new Task(); Task task = new Task();
task.setHideUntil(now); task.setHideUntil(now);
assertFalse(task.isHidden()); assertFalse(task.isHidden());
}}); }
});
} }
@Test @Test
public void testTaskIsHiddenBeforeHideUntilTime() { public void testTaskIsHiddenBeforeHideUntilTime() {
final long now = currentTimeMillis(); final long now = currentTimeMillis();
freezeAt(now).thawAfter(new Snippet() {{ freezeAt(now)
.thawAfter(
new Snippet() {
{
Task task = new Task(); Task task = new Task();
task.setHideUntil(now + 1); task.setHideUntil(now + 1);
assertTrue(task.isHidden()); assertTrue(task.isHidden());
}}); }
});
} }
@Test @Test
@ -208,54 +214,74 @@ public class TaskTest {
@Test @Test
public void testTaskNotOverdueAtDueTime() { public void testTaskNotOverdueAtDueTime() {
final long now = currentTimeMillis(); final long now = currentTimeMillis();
freezeAt(now).thawAfter(new Snippet() {{ freezeAt(now)
.thawAfter(
new Snippet() {
{
Task task = new Task(); Task task = new Task();
task.setDueDate(now); task.setDueDate(now);
assertFalse(task.isOverdue()); assertFalse(task.isOverdue());
}}); }
});
} }
@Test @Test
public void testTaskIsOverduePastDueTime() { public void testTaskIsOverduePastDueTime() {
final long dueDate = currentTimeMillis(); final long dueDate = currentTimeMillis();
freezeAt(dueDate + 1).thawAfter(new Snippet() {{ freezeAt(dueDate + 1)
.thawAfter(
new Snippet() {
{
Task task = new Task(); Task task = new Task();
task.setDueDate(dueDate); task.setDueDate(dueDate);
assertTrue(task.isOverdue()); assertTrue(task.isOverdue());
}}); }
});
} }
@Test @Test
public void testTaskNotOverdueBeforeNoonOnDueDate() { public void testTaskNotOverdueBeforeNoonOnDueDate() {
final DateTime dueDate = new DateTime().startOfDay(); final DateTime dueDate = new DateTime().startOfDay();
freezeAt(dueDate.plusHours(12).minusMillis(1)).thawAfter(new Snippet() {{ freezeAt(dueDate.plusHours(12).minusMillis(1))
.thawAfter(
new Snippet() {
{
Task task = new Task(); Task task = new Task();
task.setDueDate(dueDate.getMillis()); task.setDueDate(dueDate.getMillis());
assertFalse(task.hasDueTime()); assertFalse(task.hasDueTime());
assertFalse(task.isOverdue()); assertFalse(task.isOverdue());
}}); }
});
} }
@Test @Test
public void testTaskOverdueAtNoonOnDueDate() { public void testTaskOverdueAtNoonOnDueDate() {
final DateTime dueDate = new DateTime().startOfDay(); final DateTime dueDate = new DateTime().startOfDay();
freezeAt(dueDate.plusHours(12)).thawAfter(new Snippet() {{ freezeAt(dueDate.plusHours(12))
.thawAfter(
new Snippet() {
{
Task task = new Task(); Task task = new Task();
task.setDueDate(dueDate.getMillis()); task.setDueDate(dueDate.getMillis());
assertFalse(task.hasDueTime()); assertFalse(task.hasDueTime());
assertFalse(task.isOverdue()); assertFalse(task.isOverdue());
}}); }
});
} }
@Test @Test
public void testTaskWithNoDueTimeIsOverdue() { public void testTaskWithNoDueTimeIsOverdue() {
final DateTime dueDate = new DateTime().startOfDay(); final DateTime dueDate = new DateTime().startOfDay();
freezeAt(dueDate.plusDays(1)).thawAfter(new Snippet() {{ freezeAt(dueDate.plusDays(1))
.thawAfter(
new Snippet() {
{
Task task = new Task(); Task task = new Task();
task.setDueDate(dueDate.getMillis()); task.setDueDate(dueDate.getMillis());
assertFalse(task.hasDueTime()); assertFalse(task.hasDueTime());
assertTrue(task.isOverdue()); assertTrue(task.isOverdue());
}}); }
});
} }
@Test @Test

@ -21,11 +21,15 @@ public class TaskTest extends InjectingTestCase {
@Test @Test
public void testSavedTaskHasCreationDate() { public void testSavedTaskHasCreationDate() {
freezeClock().thawAfter(new Snippet() {{ freezeClock()
.thawAfter(
new Snippet() {
{
Task task = new Task(); Task task = new Task();
taskDao.createNew(task); taskDao.createNew(task);
assertEquals(currentTimeMillis(), (long) task.getCreationDate()); assertEquals(currentTimeMillis(), (long) task.getCreationDate());
}}); }
});
} }
@Test @Test

@ -89,7 +89,8 @@ public class ReminderServiceTest extends InjectingTestCase {
@Test @Test
public void schedulePastDueDate() { public void schedulePastDueDate() {
Task task = newTask( Task task =
newTask(
with(ID, 1L), with(ID, 1L),
with(DUE_TIME, newDateTime().minusDays(1)), with(DUE_TIME, newDateTime().minusDays(1)),
with(REMINDERS, NOTIFY_AT_DEADLINE)); with(REMINDERS, NOTIFY_AT_DEADLINE));
@ -102,7 +103,8 @@ public class ReminderServiceTest extends InjectingTestCase {
@Test @Test
public void scheduleFutureDueDate() { public void scheduleFutureDueDate() {
Task task = newTask( Task task =
newTask(
with(ID, 1L), with(ID, 1L),
with(DUE_TIME, newDateTime().plusDays(1)), with(DUE_TIME, newDateTime().plusDays(1)),
with(REMINDERS, NOTIFY_AT_DEADLINE)); with(REMINDERS, NOTIFY_AT_DEADLINE));
@ -116,22 +118,23 @@ public class ReminderServiceTest extends InjectingTestCase {
@Test @Test
public void scheduleReminderAtDefaultDueTime() { public void scheduleReminderAtDefaultDueTime() {
DateTime now = newDateTime(); DateTime now = newDateTime();
Task task = newTask( Task task = newTask(with(ID, 1L), with(DUE_DATE, now), with(REMINDERS, NOTIFY_AT_DEADLINE));
with(ID, 1L),
with(DUE_DATE, now),
with(REMINDERS, NOTIFY_AT_DEADLINE));
service.scheduleAlarm(task); service.scheduleAlarm(task);
InOrder order = inOrder(jobs); InOrder order = inOrder(jobs);
order.verify(jobs).cancelReminder(1); order.verify(jobs).cancelReminder(1);
order.verify(jobs).add( order
new ReminderEntry(1, now.startOfDay().withHourOfDay(18).getMillis(), ReminderService.TYPE_DUE)); .verify(jobs)
.add(
new ReminderEntry(
1, now.startOfDay().withHourOfDay(18).getMillis(), ReminderService.TYPE_DUE));
} }
@Test @Test
public void dontScheduleReminderForCompletedTask() { public void dontScheduleReminderForCompletedTask() {
Task task = newTask( Task task =
newTask(
with(ID, 1L), with(ID, 1L),
with(DUE_TIME, newDateTime().plusDays(1)), with(DUE_TIME, newDateTime().plusDays(1)),
with(COMPLETION_TIME, newDateTime()), with(COMPLETION_TIME, newDateTime()),
@ -144,7 +147,8 @@ public class ReminderServiceTest extends InjectingTestCase {
@Test @Test
public void dontScheduleReminderForDeletedTask() { public void dontScheduleReminderForDeletedTask() {
Task task = newTask( Task task =
newTask(
with(ID, 1L), with(ID, 1L),
with(DUE_TIME, newDateTime().plusDays(1)), with(DUE_TIME, newDateTime().plusDays(1)),
with(DELETION_TIME, newDateTime()), with(DELETION_TIME, newDateTime()),
@ -158,7 +162,8 @@ public class ReminderServiceTest extends InjectingTestCase {
@Test @Test
public void dontScheduleDueDateReminderWhenAlreadyReminded() { public void dontScheduleDueDateReminderWhenAlreadyReminded() {
DateTime now = newDateTime(); DateTime now = newDateTime();
Task task = newTask( Task task =
newTask(
with(ID, 1L), with(ID, 1L),
with(DUE_TIME, now), with(DUE_TIME, now),
with(REMINDER_LAST, now.plusSeconds(1)), with(REMINDER_LAST, now.plusSeconds(1)),
@ -171,7 +176,8 @@ public class ReminderServiceTest extends InjectingTestCase {
@Test @Test
public void ignoreStaleSnoozeTime() { public void ignoreStaleSnoozeTime() {
Task task = newTask( Task task =
newTask(
with(ID, 1L), with(ID, 1L),
with(DUE_TIME, newDateTime()), with(DUE_TIME, newDateTime()),
with(SNOOZE_TIME, newDateTime().minusMinutes(5)), with(SNOOZE_TIME, newDateTime().minusMinutes(5)),
@ -187,7 +193,8 @@ public class ReminderServiceTest extends InjectingTestCase {
@Test @Test
public void dontIgnoreMissedSnoozeTime() { public void dontIgnoreMissedSnoozeTime() {
DateTime dueDate = newDateTime(); DateTime dueDate = newDateTime();
Task task = newTask( Task task =
newTask(
with(ID, 1L), with(ID, 1L),
with(DUE_TIME, dueDate), with(DUE_TIME, dueDate),
with(SNOOZE_TIME, dueDate.minusMinutes(4)), with(SNOOZE_TIME, dueDate.minusMinutes(4)),
@ -197,15 +204,21 @@ public class ReminderServiceTest extends InjectingTestCase {
InOrder order = inOrder(jobs); InOrder order = inOrder(jobs);
order.verify(jobs).cancelReminder(1); order.verify(jobs).cancelReminder(1);
order.verify(jobs).add(new ReminderEntry(1, task.getReminderSnooze(), ReminderService.TYPE_SNOOZE)); order
.verify(jobs)
.add(new ReminderEntry(1, task.getReminderSnooze(), ReminderService.TYPE_SNOOZE));
} }
@Test @Test
public void scheduleInitialRandomReminder() { public void scheduleInitialRandomReminder() {
freezeClock().thawAfter(new Snippet() {{ freezeClock()
.thawAfter(
new Snippet() {
{
DateTime now = newDateTime(); DateTime now = newDateTime();
when(random.nextFloat()).thenReturn(0.3865f); when(random.nextFloat()).thenReturn(0.3865f);
Task task = newTask( Task task =
newTask(
with(ID, 1L), with(ID, 1L),
with(REMINDER_LAST, (DateTime) null), with(REMINDER_LAST, (DateTime) null),
with(CREATION_TIME, now.minusDays(1)), with(CREATION_TIME, now.minusDays(1)),
@ -215,17 +228,27 @@ public class ReminderServiceTest extends InjectingTestCase {
InOrder order = inOrder(jobs); InOrder order = inOrder(jobs);
order.verify(jobs).cancelReminder(1); order.verify(jobs).cancelReminder(1);
order.verify(jobs).add( order
new ReminderEntry(1L, now.minusDays(1).getMillis() + 584206592, ReminderService.TYPE_RANDOM)); .verify(jobs)
}}); .add(
new ReminderEntry(
1L,
now.minusDays(1).getMillis() + 584206592,
ReminderService.TYPE_RANDOM));
}
});
} }
@Test @Test
public void scheduleNextRandomReminder() { public void scheduleNextRandomReminder() {
freezeClock().thawAfter(new Snippet() {{ freezeClock()
.thawAfter(
new Snippet() {
{
DateTime now = newDateTime(); DateTime now = newDateTime();
when(random.nextFloat()).thenReturn(0.3865f); when(random.nextFloat()).thenReturn(0.3865f);
Task task = newTask( Task task =
newTask(
with(ID, 1L), with(ID, 1L),
with(REMINDER_LAST, now.minusDays(1)), with(REMINDER_LAST, now.minusDays(1)),
with(CREATION_TIME, now.minusDays(30)), with(CREATION_TIME, now.minusDays(30)),
@ -235,17 +258,27 @@ public class ReminderServiceTest extends InjectingTestCase {
InOrder order = inOrder(jobs); InOrder order = inOrder(jobs);
order.verify(jobs).cancelReminder(1); order.verify(jobs).cancelReminder(1);
order.verify(jobs).add( order
new ReminderEntry(1L, now.minusDays(1).getMillis() + 584206592, ReminderService.TYPE_RANDOM)); .verify(jobs)
}}); .add(
new ReminderEntry(
1L,
now.minusDays(1).getMillis() + 584206592,
ReminderService.TYPE_RANDOM));
}
});
} }
@Test @Test
public void scheduleOverdueRandomReminder() { public void scheduleOverdueRandomReminder() {
freezeClock().thawAfter(new Snippet() {{ freezeClock()
.thawAfter(
new Snippet() {
{
DateTime now = newDateTime(); DateTime now = newDateTime();
when(random.nextFloat()).thenReturn(0.3865f); when(random.nextFloat()).thenReturn(0.3865f);
Task task = newTask( Task task =
newTask(
with(ID, 1L), with(ID, 1L),
with(REMINDER_LAST, now.minusDays(14)), with(REMINDER_LAST, now.minusDays(14)),
with(CREATION_TIME, now.minusDays(30)), with(CREATION_TIME, now.minusDays(30)),
@ -255,14 +288,19 @@ public class ReminderServiceTest extends InjectingTestCase {
InOrder order = inOrder(jobs); InOrder order = inOrder(jobs);
order.verify(jobs).cancelReminder(1); order.verify(jobs).cancelReminder(1);
order.verify(jobs) order
.add(new ReminderEntry(1L, now.getMillis() + 10148400, ReminderService.TYPE_RANDOM)); .verify(jobs)
}}); .add(
new ReminderEntry(
1L, now.getMillis() + 10148400, ReminderService.TYPE_RANDOM));
}
});
} }
@Test @Test
public void scheduleOverdueNoLastReminder() { public void scheduleOverdueNoLastReminder() {
Task task = newTask( Task task =
newTask(
with(ID, 1L), with(ID, 1L),
with(DUE_TIME, new DateTime(2017, 9, 22, 15, 30)), with(DUE_TIME, new DateTime(2017, 9, 22, 15, 30)),
with(REMINDER_LAST, (DateTime) null), with(REMINDER_LAST, (DateTime) null),
@ -272,13 +310,19 @@ public class ReminderServiceTest extends InjectingTestCase {
InOrder order = inOrder(jobs); InOrder order = inOrder(jobs);
order.verify(jobs).cancelReminder(1); order.verify(jobs).cancelReminder(1);
order.verify(jobs).add(new ReminderEntry(1L, new DateTime(2017, 9, 23, 15, 30, 1, 0).getMillis(), order
.verify(jobs)
.add(
new ReminderEntry(
1L,
new DateTime(2017, 9, 23, 15, 30, 1, 0).getMillis(),
ReminderService.TYPE_OVERDUE)); ReminderService.TYPE_OVERDUE));
} }
@Test @Test
public void scheduleOverduePastLastReminder() { public void scheduleOverduePastLastReminder() {
Task task = newTask( Task task =
newTask(
with(ID, 1L), with(ID, 1L),
with(DUE_TIME, new DateTime(2017, 9, 22, 15, 30)), with(DUE_TIME, new DateTime(2017, 9, 22, 15, 30)),
with(REMINDER_LAST, new DateTime(2017, 9, 24, 12, 0)), with(REMINDER_LAST, new DateTime(2017, 9, 24, 12, 0)),
@ -288,13 +332,19 @@ public class ReminderServiceTest extends InjectingTestCase {
InOrder order = inOrder(jobs); InOrder order = inOrder(jobs);
order.verify(jobs).cancelReminder(1); order.verify(jobs).cancelReminder(1);
order.verify(jobs).add(new ReminderEntry(1L, new DateTime(2017, 9, 24, 15, 30, 1, 0).getMillis(), order
.verify(jobs)
.add(
new ReminderEntry(
1L,
new DateTime(2017, 9, 24, 15, 30, 1, 0).getMillis(),
ReminderService.TYPE_OVERDUE)); ReminderService.TYPE_OVERDUE));
} }
@Test @Test
public void scheduleOverdueBeforeLastReminder() { public void scheduleOverdueBeforeLastReminder() {
Task task = newTask( Task task =
newTask(
with(ID, 1L), with(ID, 1L),
with(DUE_TIME, new DateTime(2017, 9, 22, 12, 30)), with(DUE_TIME, new DateTime(2017, 9, 22, 12, 30)),
with(REMINDER_LAST, new DateTime(2017, 9, 24, 15, 0)), with(REMINDER_LAST, new DateTime(2017, 9, 24, 15, 0)),
@ -304,14 +354,20 @@ public class ReminderServiceTest extends InjectingTestCase {
InOrder order = inOrder(jobs); InOrder order = inOrder(jobs);
order.verify(jobs).cancelReminder(1); order.verify(jobs).cancelReminder(1);
order.verify(jobs).add(new ReminderEntry(1L, new DateTime(2017, 9, 25, 12, 30, 1, 0).getMillis(), order
.verify(jobs)
.add(
new ReminderEntry(
1L,
new DateTime(2017, 9, 25, 12, 30, 1, 0).getMillis(),
ReminderService.TYPE_OVERDUE)); ReminderService.TYPE_OVERDUE));
} }
@Test @Test
public void scheduleOverdueWithNoDueTime() { public void scheduleOverdueWithNoDueTime() {
preferences.setInt(R.string.p_rmd_time, (int) TimeUnit.HOURS.toMillis(15)); preferences.setInt(R.string.p_rmd_time, (int) TimeUnit.HOURS.toMillis(15));
Task task = newTask( Task task =
newTask(
with(ID, 1L), with(ID, 1L),
with(DUE_DATE, new DateTime(2017, 9, 22)), with(DUE_DATE, new DateTime(2017, 9, 22)),
with(REMINDER_LAST, new DateTime(2017, 9, 23, 12, 17, 59, 999)), with(REMINDER_LAST, new DateTime(2017, 9, 23, 12, 17, 59, 999)),
@ -321,13 +377,19 @@ public class ReminderServiceTest extends InjectingTestCase {
InOrder order = inOrder(jobs); InOrder order = inOrder(jobs);
order.verify(jobs).cancelReminder(1); order.verify(jobs).cancelReminder(1);
order.verify(jobs).add(new ReminderEntry(1L, new DateTime(2017, 9, 23, 15, 0, 0, 0).getMillis(), order
.verify(jobs)
.add(
new ReminderEntry(
1L,
new DateTime(2017, 9, 23, 15, 0, 0, 0).getMillis(),
ReminderService.TYPE_OVERDUE)); ReminderService.TYPE_OVERDUE));
} }
@Test @Test
public void scheduleSubsequentOverdueReminder() { public void scheduleSubsequentOverdueReminder() {
Task task = newTask( Task task =
newTask(
with(ID, 1L), with(ID, 1L),
with(DUE_TIME, new DateTime(2017, 9, 22, 15, 30)), with(DUE_TIME, new DateTime(2017, 9, 22, 15, 30)),
with(REMINDER_LAST, new DateTime(2017, 9, 23, 15, 30, 59, 999)), with(REMINDER_LAST, new DateTime(2017, 9, 23, 15, 30, 59, 999)),
@ -337,13 +399,19 @@ public class ReminderServiceTest extends InjectingTestCase {
InOrder order = inOrder(jobs); InOrder order = inOrder(jobs);
order.verify(jobs).cancelReminder(1); order.verify(jobs).cancelReminder(1);
order.verify(jobs).add(new ReminderEntry(1L, new DateTime(2017, 9, 24, 15, 30, 1, 0).getMillis(), order
.verify(jobs)
.add(
new ReminderEntry(
1L,
new DateTime(2017, 9, 24, 15, 30, 1, 0).getMillis(),
ReminderService.TYPE_OVERDUE)); ReminderService.TYPE_OVERDUE));
} }
@Test @Test
public void scheduleOverdueAfterLastReminder() { public void scheduleOverdueAfterLastReminder() {
Task task = newTask( Task task =
newTask(
with(ID, 1L), with(ID, 1L),
with(DUE_TIME, new DateTime(2017, 9, 22, 15, 30)), with(DUE_TIME, new DateTime(2017, 9, 22, 15, 30)),
with(REMINDER_LAST, new DateTime(2017, 9, 23, 12, 17, 59, 999)), with(REMINDER_LAST, new DateTime(2017, 9, 23, 12, 17, 59, 999)),
@ -353,14 +421,20 @@ public class ReminderServiceTest extends InjectingTestCase {
InOrder order = inOrder(jobs); InOrder order = inOrder(jobs);
order.verify(jobs).cancelReminder(1); order.verify(jobs).cancelReminder(1);
order.verify(jobs).add(new ReminderEntry(1L, new DateTime(2017, 9, 23, 15, 30, 1, 0).getMillis(), order
.verify(jobs)
.add(
new ReminderEntry(
1L,
new DateTime(2017, 9, 23, 15, 30, 1, 0).getMillis(),
ReminderService.TYPE_OVERDUE)); ReminderService.TYPE_OVERDUE));
} }
@Test @Test
public void snoozeOverridesAll() { public void snoozeOverridesAll() {
DateTime now = newDateTime(); DateTime now = newDateTime();
Task task = newTask( Task task =
newTask(
with(ID, 1L), with(ID, 1L),
with(DUE_TIME, now), with(DUE_TIME, now),
with(SNOOZE_TIME, now.plusMonths(12)), with(SNOOZE_TIME, now.plusMonths(12)),
@ -371,7 +445,8 @@ public class ReminderServiceTest extends InjectingTestCase {
InOrder order = inOrder(jobs); InOrder order = inOrder(jobs);
order.verify(jobs).cancelReminder(1); order.verify(jobs).cancelReminder(1);
order.verify(jobs) order
.verify(jobs)
.add(new ReminderEntry(1, now.plusMonths(12).getMillis(), ReminderService.TYPE_SNOOZE)); .add(new ReminderEntry(1, now.plusMonths(12).getMillis(), ReminderService.TYPE_SNOOZE));
} }
} }

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.repeats; package com.todoroo.astrid.repeats;
import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertEquals;
@ -37,8 +36,7 @@ public class AdvancedRepeatTest {
private RRule rrule; private RRule rrule;
public static void assertDateTimeEquals(long date, long other) { public static void assertDateTimeEquals(long date, long other) {
assertEquals("Expected: " + newDateTime(date) + ", Actual: " + newDateTime(other), assertEquals("Expected: " + newDateTime(date) + ", Actual: " + newDateTime(other), date, other);
date, other);
} }
// --- date with time tests // --- date with time tests
@ -55,8 +53,9 @@ public class AdvancedRepeatTest {
buildRRule(1, Frequency.DAILY); buildRRule(1, Frequency.DAILY);
// test specific day & time // test specific day & time
long dayWithTime = Task.createDueDate(Task.URGENCY_SPECIFIC_DAY_TIME, long dayWithTime =
new DateTime(2010, 8, 1, 10, 4, 0).getMillis()); Task.createDueDate(
Task.URGENCY_SPECIFIC_DAY_TIME, new DateTime(2010, 8, 1, 10, 4, 0).getMillis());
task.setDueDate(dayWithTime); task.setDueDate(dayWithTime);
long nextDayWithTime = dayWithTime + DateUtilities.ONE_DAY; long nextDayWithTime = dayWithTime + DateUtilities.ONE_DAY;
@ -71,14 +70,13 @@ public class AdvancedRepeatTest {
buildRRule(1, Frequency.DAILY); buildRRule(1, Frequency.DAILY);
// test specific day & time // test specific day & time
long dayWithTime = Task.createDueDate(Task.URGENCY_SPECIFIC_DAY_TIME, long dayWithTime =
new DateTime(2010, 8, 1, 10, 4, 0).getMillis()); Task.createDueDate(
Task.URGENCY_SPECIFIC_DAY_TIME, new DateTime(2010, 8, 1, 10, 4, 0).getMillis());
task.setDueDate(dayWithTime); task.setDueDate(dayWithTime);
DateTime todayWithTime = newDateTime() DateTime todayWithTime =
.withHourOfDay(10) newDateTime().withHourOfDay(10).withMinuteOfHour(4).withSecondOfMinute(1);
.withMinuteOfHour(4)
.withSecondOfMinute(1);
long nextDayWithTimeLong = todayWithTime.getMillis(); long nextDayWithTimeLong = todayWithTime.getMillis();
nextDayWithTimeLong += DateUtilities.ONE_DAY; nextDayWithTimeLong += DateUtilities.ONE_DAY;
nextDayWithTimeLong = nextDayWithTimeLong / 1000L * 1000; nextDayWithTimeLong = nextDayWithTimeLong / 1000L * 1000;
@ -87,9 +85,7 @@ public class AdvancedRepeatTest {
assertDateTimeEquals(nextDayWithTimeLong, nextDueDate); assertDateTimeEquals(nextDayWithTimeLong, nextDueDate);
} }
/** /** test multiple days per week - DUE DATE */
* test multiple days per week - DUE DATE
*/
@Test @Test
public void testDueDateInPastSingleWeekMultiDay() throws Exception { public void testDueDateInPastSingleWeekMultiDay() throws Exception {
buildRRule(1, Frequency.WEEKLY, Weekday.MO, Weekday.WE, Weekday.FR); buildRRule(1, Frequency.WEEKLY, Weekday.MO, Weekday.WE, Weekday.FR);
@ -107,9 +103,7 @@ public class AdvancedRepeatTest {
assertDueDate(nextDueDate, THIS, Calendar.MONDAY); assertDueDate(nextDueDate, THIS, Calendar.MONDAY);
} }
/** /** test single day repeats - DUE DATE */
* test single day repeats - DUE DATE
*/
@Test @Test
public void testDueDateSingleDay() throws Exception { public void testDueDateSingleDay() throws Exception {
buildRRule(1, Frequency.WEEKLY, Weekday.MO); buildRRule(1, Frequency.WEEKLY, Weekday.MO);
@ -139,9 +133,7 @@ public class AdvancedRepeatTest {
assertDueDate(nextDueDate, NEXT, Calendar.MONDAY); assertDueDate(nextDueDate, NEXT, Calendar.MONDAY);
} }
/** /** test multiple days per week - DUE DATE */
* test multiple days per week - DUE DATE
*/
@Test @Test
public void testDueDateSingleWeekMultiDay() throws Exception { public void testDueDateSingleWeekMultiDay() throws Exception {
@ -162,9 +154,7 @@ public class AdvancedRepeatTest {
// --- completion tests // --- completion tests
/** /** test multiple days per week, multiple intervals - DUE DATE */
* test multiple days per week, multiple intervals - DUE DATE
*/
@Test @Test
public void testDueDateMultiWeekMultiDay() throws Exception { public void testDueDateMultiWeekMultiDay() throws Exception {
buildRRule(2, Frequency.WEEKLY, Weekday.MO, Weekday.WE, Weekday.FR); buildRRule(2, Frequency.WEEKLY, Weekday.MO, Weekday.WE, Weekday.FR);
@ -182,9 +172,7 @@ public class AdvancedRepeatTest {
assertDueDate(nextDueDate, NEXT, Calendar.MONDAY); assertDueDate(nextDueDate, NEXT, Calendar.MONDAY);
} }
/** /** test multiple days per week - COMPLETE DATE */
* test multiple days per week - COMPLETE DATE
*/
@Test @Test
public void testCompleteDateSingleWeek() throws Exception { public void testCompleteDateSingleWeek() throws Exception {
for (Weekday wday : Weekday.values()) { for (Weekday wday : Weekday.values()) {
@ -213,9 +201,7 @@ public class AdvancedRepeatTest {
// --- helpers // --- helpers
/** /** test multiple days per week, multiple intervals - COMPLETE DATE */
* test multiple days per week, multiple intervals - COMPLETE DATE
*/
@Test @Test
public void testCompleteDateMultiWeek() throws Exception { public void testCompleteDateMultiWeek() throws Exception {
for (Weekday wday : Weekday.values()) { for (Weekday wday : Weekday.values()) {

@ -66,10 +66,7 @@ public class NewRepeatTests {
assertEquals(newDayTime(2017, 8, 28, 1, 44), calculateNextDueDate(task)); assertEquals(newDayTime(2017, 8, 28, 1, 44), calculateNextDueDate(task));
} }
/** /** Tests for repeating from completionDate */
* Tests for repeating from completionDate
*/
@Test @Test
public void testRepeatMinutelyFromCompleteDateCompleteBefore() throws ParseException { public void testRepeatMinutelyFromCompleteDateCompleteBefore() throws ParseException {
DateTime dueDateTime = newDayTime(2016, 8, 30, 0, 25); DateTime dueDateTime = newDayTime(2016, 8, 30, 0, 25);
@ -181,8 +178,9 @@ public class NewRepeatTests {
@Test @Test
public void testAdvancedRepeatWeeklyFromDueDate() throws ParseException { public void testAdvancedRepeatWeeklyFromDueDate() throws ParseException {
DateTime dueDateTime = newDayTime(2016, 8, 29, 0, 25); DateTime dueDateTime = newDayTime(2016, 8, 29, 0, 25);
Task task = newWeeklyFromDue(1, dueDateTime, new WeekdayNum(0, Weekday.MO), Task task =
new WeekdayNum(0, Weekday.WE)); newWeeklyFromDue(
1, dueDateTime, new WeekdayNum(0, Weekday.MO), new WeekdayNum(0, Weekday.WE));
assertEquals(newDayTime(2016, 8, 31, 0, 25), calculateNextDueDate(task)); assertEquals(newDayTime(2016, 8, 31, 0, 25), calculateNextDueDate(task));
} }
@ -191,8 +189,13 @@ public class NewRepeatTests {
public void testAdvancedRepeatWeeklyFromCompleteDateCompleteBefore() throws ParseException { public void testAdvancedRepeatWeeklyFromCompleteDateCompleteBefore() throws ParseException {
DateTime dueDateTime = newDayTime(2016, 8, 29, 0, 25); DateTime dueDateTime = newDayTime(2016, 8, 29, 0, 25);
DateTime completionDateTime = newDayTime(2016, 8, 28, 1, 9); DateTime completionDateTime = newDayTime(2016, 8, 28, 1, 9);
Task task = newWeeklyFromCompleted(1, dueDateTime, completionDateTime, Task task =
new WeekdayNum(0, Weekday.MO), new WeekdayNum(0, Weekday.WE)); newWeeklyFromCompleted(
1,
dueDateTime,
completionDateTime,
new WeekdayNum(0, Weekday.MO),
new WeekdayNum(0, Weekday.WE));
assertEquals(newDayTime(2016, 8, 29, 0, 25), calculateNextDueDate(task)); assertEquals(newDayTime(2016, 8, 29, 0, 25), calculateNextDueDate(task));
} }
@ -201,14 +204,21 @@ public class NewRepeatTests {
public void testAdvancedRepeatWeeklyFromCompleteDateCompleteAfter() throws ParseException { public void testAdvancedRepeatWeeklyFromCompleteDateCompleteAfter() throws ParseException {
DateTime dueDateTime = newDayTime(2016, 8, 29, 0, 25); DateTime dueDateTime = newDayTime(2016, 8, 29, 0, 25);
DateTime completionDateTime = newDayTime(2016, 9, 1, 1, 9); DateTime completionDateTime = newDayTime(2016, 9, 1, 1, 9);
Task task = newWeeklyFromCompleted(1, dueDateTime, completionDateTime, Task task =
new WeekdayNum(0, Weekday.MO), new WeekdayNum(0, Weekday.WE)); newWeeklyFromCompleted(
1,
dueDateTime,
completionDateTime,
new WeekdayNum(0, Weekday.MO),
new WeekdayNum(0, Weekday.WE));
assertEquals(newDayTime(2016, 9, 5, 0, 25), calculateNextDueDate(task)); assertEquals(newDayTime(2016, 9, 5, 0, 25), calculateNextDueDate(task));
} }
private DateTime newDayTime(int year, int month, int day, int hour, int minute) { private DateTime newDayTime(int year, int month, int day, int hour, int minute) {
return new DateTime(Task.createDueDate(Task.URGENCY_SPECIFIC_DAY_TIME, return new DateTime(
Task.createDueDate(
Task.URGENCY_SPECIFIC_DAY_TIME,
new DateTime(year, month, day, hour, minute).getMillis())); new DateTime(year, month, day, hour, minute).getMillis()));
} }
@ -218,39 +228,47 @@ public class NewRepeatTests {
} }
private Task newFromDue(Frequency frequency, int interval, DateTime dueDateTime) { private Task newFromDue(Frequency frequency, int interval, DateTime dueDateTime) {
return new Task() {{ return new Task() {
{
setRecurrence(getRecurrenceRule(frequency, interval, false)); setRecurrence(getRecurrenceRule(frequency, interval, false));
setDueDate(dueDateTime.getMillis()); setDueDate(dueDateTime.getMillis());
}}; }
};
} }
private Task newWeeklyFromDue(int interval, DateTime dueDateTime, WeekdayNum... weekdays) { private Task newWeeklyFromDue(int interval, DateTime dueDateTime, WeekdayNum... weekdays) {
return new Task() {{ return new Task() {
{
setRecurrence(getRecurrenceRule(Frequency.WEEKLY, interval, false, weekdays)); setRecurrence(getRecurrenceRule(Frequency.WEEKLY, interval, false, weekdays));
setDueDate(dueDateTime.getMillis()); setDueDate(dueDateTime.getMillis());
}}; }
};
} }
private Task newFromCompleted(Frequency frequency, int interval, DateTime dueDateTime, private Task newFromCompleted(
DateTime completionDate) { Frequency frequency, int interval, DateTime dueDateTime, DateTime completionDate) {
return new Task() {{ return new Task() {
{
setRecurrence(getRecurrenceRule(frequency, interval, true)); setRecurrence(getRecurrenceRule(frequency, interval, true));
setDueDate(dueDateTime.getMillis()); setDueDate(dueDateTime.getMillis());
setCompletionDate(completionDate.getMillis()); setCompletionDate(completionDate.getMillis());
}}; }
};
} }
private Task newWeeklyFromCompleted(int interval, DateTime dueDateTime, DateTime completionDate, private Task newWeeklyFromCompleted(
WeekdayNum... weekdays) { int interval, DateTime dueDateTime, DateTime completionDate, WeekdayNum... weekdays) {
return new Task() {{ return new Task() {
{
setRecurrence(getRecurrenceRule(Frequency.WEEKLY, interval, true, weekdays)); setRecurrence(getRecurrenceRule(Frequency.WEEKLY, interval, true, weekdays));
setDueDate(dueDateTime.getMillis()); setDueDate(dueDateTime.getMillis());
setCompletionDate(completionDate.getMillis()); setCompletionDate(completionDate.getMillis());
}}; }
};
} }
private String getRecurrenceRule(Frequency frequency, int interval, boolean fromCompletion, private String getRecurrenceRule(
WeekdayNum... weekdays) { Frequency frequency, int interval, boolean fromCompletion, WeekdayNum... weekdays) {
RRule rrule = new RRule(); RRule rrule = new RRule();
rrule.setFreq(frequency); rrule.setFreq(frequency);
rrule.setInterval(interval); rrule.setInterval(interval);

@ -64,44 +64,49 @@ public class RepeatTaskHelperTest extends InjectingTestCase {
@Test @Test
public void testMinutelyRepeat() throws ParseException { public void testMinutelyRepeat() throws ParseException {
Task task = newTask(with(ID, 1L), Task task =
newTask(
with(ID, 1L),
with(DUE_TIME, new DateTime(2017, 10, 4, 13, 30)), with(DUE_TIME, new DateTime(2017, 10, 4, 13, 30)),
with(RRULE, new RRule("RRULE:FREQ=MINUTELY;INTERVAL=30"))); with(RRULE, new RRule("RRULE:FREQ=MINUTELY;INTERVAL=30")));
repeatAndVerify(task, repeatAndVerify(
new DateTime(2017, 10, 4, 13, 30, 1), task, new DateTime(2017, 10, 4, 13, 30, 1), new DateTime(2017, 10, 4, 14, 0, 1));
new DateTime(2017, 10, 4, 14, 0, 1));
} }
@Test @Test
public void testMinutelyRepeatAfterCompletion() throws ParseException { public void testMinutelyRepeatAfterCompletion() throws ParseException {
Task task = newTask(with(ID, 1L), Task task =
newTask(
with(ID, 1L),
with(DUE_TIME, new DateTime(2017, 10, 4, 13, 30)), with(DUE_TIME, new DateTime(2017, 10, 4, 13, 30)),
with(COMPLETION_TIME, new DateTime(2017, 10, 4, 13, 17, 45, 340)), with(COMPLETION_TIME, new DateTime(2017, 10, 4, 13, 17, 45, 340)),
with(RRULE, new RRule("RRULE:FREQ=MINUTELY;INTERVAL=30")), with(RRULE, new RRule("RRULE:FREQ=MINUTELY;INTERVAL=30")),
with(AFTER_COMPLETE, true)); with(AFTER_COMPLETE, true));
repeatAndVerify(task, repeatAndVerify(
new DateTime(2017, 10, 4, 13, 30, 1), task, new DateTime(2017, 10, 4, 13, 30, 1), new DateTime(2017, 10, 4, 13, 47, 1));
new DateTime(2017, 10, 4, 13, 47, 1));
} }
@Test @Test
public void testMinutelyDecrementCount() throws ParseException { public void testMinutelyDecrementCount() throws ParseException {
Task task = newTask(with(ID, 1L), Task task =
newTask(
with(ID, 1L),
with(DUE_TIME, new DateTime(2017, 10, 4, 13, 30)), with(DUE_TIME, new DateTime(2017, 10, 4, 13, 30)),
with(RRULE, new RRule("RRULE:FREQ=MINUTELY;COUNT=2;INTERVAL=30"))); with(RRULE, new RRule("RRULE:FREQ=MINUTELY;COUNT=2;INTERVAL=30")));
repeatAndVerify(task, repeatAndVerify(
new DateTime(2017, 10, 4, 13, 30, 1), task, new DateTime(2017, 10, 4, 13, 30, 1), new DateTime(2017, 10, 4, 14, 0, 1));
new DateTime(2017, 10, 4, 14, 0, 1));
assertEquals(1, new RRule(task.getRecurrenceWithoutFrom()).getCount()); assertEquals(1, new RRule(task.getRecurrenceWithoutFrom()).getCount());
} }
@Test @Test
public void testMinutelyLastOccurrence() throws ParseException { public void testMinutelyLastOccurrence() throws ParseException {
Task task = newTask(with(ID, 1L), Task task =
newTask(
with(ID, 1L),
with(DUE_TIME, new DateTime(2017, 10, 4, 13, 30)), with(DUE_TIME, new DateTime(2017, 10, 4, 13, 30)),
with(RRULE, new RRule("RRULE:FREQ=MINUTELY;COUNT=1;INTERVAL=30"))); with(RRULE, new RRule("RRULE:FREQ=MINUTELY;COUNT=1;INTERVAL=30")));
@ -110,81 +115,88 @@ public class RepeatTaskHelperTest extends InjectingTestCase {
@Test @Test
public void testHourlyRepeat() throws ParseException { public void testHourlyRepeat() throws ParseException {
Task task = newTask(with(ID, 1L), Task task =
newTask(
with(ID, 1L),
with(DUE_TIME, new DateTime(2017, 10, 4, 13, 30)), with(DUE_TIME, new DateTime(2017, 10, 4, 13, 30)),
with(RRULE, new RRule("RRULE:FREQ=HOURLY;INTERVAL=6"))); with(RRULE, new RRule("RRULE:FREQ=HOURLY;INTERVAL=6")));
repeatAndVerify(task, repeatAndVerify(
new DateTime(2017, 10, 4, 13, 30, 1), task, new DateTime(2017, 10, 4, 13, 30, 1), new DateTime(2017, 10, 4, 19, 30, 1));
new DateTime(2017, 10, 4, 19, 30, 1));
} }
@Test @Test
public void testHourlyRepeatAfterCompletion() throws ParseException { public void testHourlyRepeatAfterCompletion() throws ParseException {
Task task = newTask(with(ID, 1L), Task task =
newTask(
with(ID, 1L),
with(DUE_TIME, new DateTime(2017, 10, 4, 13, 30)), with(DUE_TIME, new DateTime(2017, 10, 4, 13, 30)),
with(COMPLETION_TIME, new DateTime(2017, 10, 4, 13, 17, 45, 340)), with(COMPLETION_TIME, new DateTime(2017, 10, 4, 13, 17, 45, 340)),
with(RRULE, new RRule("RRULE:FREQ=HOURLY;INTERVAL=6")), with(RRULE, new RRule("RRULE:FREQ=HOURLY;INTERVAL=6")),
with(AFTER_COMPLETE, true)); with(AFTER_COMPLETE, true));
repeatAndVerify(task, repeatAndVerify(
new DateTime(2017, 10, 4, 13, 30, 1), task, new DateTime(2017, 10, 4, 13, 30, 1), new DateTime(2017, 10, 4, 19, 17, 1));
new DateTime(2017, 10, 4, 19, 17, 1));
} }
@Test @Test
public void testDailyRepeat() throws ParseException { public void testDailyRepeat() throws ParseException {
Task task = newTask(with(ID, 1L), Task task =
newTask(
with(ID, 1L),
with(DUE_TIME, new DateTime(2017, 10, 4, 13, 30)), with(DUE_TIME, new DateTime(2017, 10, 4, 13, 30)),
with(RRULE, new RRule("RRULE:FREQ=DAILY;INTERVAL=6"))); with(RRULE, new RRule("RRULE:FREQ=DAILY;INTERVAL=6")));
repeatAndVerify(task, repeatAndVerify(
new DateTime(2017, 10, 4, 13, 30, 1), task, new DateTime(2017, 10, 4, 13, 30, 1), new DateTime(2017, 10, 10, 13, 30, 1));
new DateTime(2017, 10, 10, 13, 30, 1));
} }
@Test @Test
public void testRepeatWeeklyNoDays() throws ParseException { public void testRepeatWeeklyNoDays() throws ParseException {
Task task = newTask(with(ID, 1L), Task task =
newTask(
with(ID, 1L),
with(DUE_TIME, new DateTime(2017, 10, 4, 13, 30)), with(DUE_TIME, new DateTime(2017, 10, 4, 13, 30)),
with(RRULE, new RRule("RRULE:FREQ=WEEKLY;INTERVAL=2"))); with(RRULE, new RRule("RRULE:FREQ=WEEKLY;INTERVAL=2")));
repeatAndVerify(task, repeatAndVerify(
new DateTime(2017, 10, 4, 13, 30, 1), task, new DateTime(2017, 10, 4, 13, 30, 1), new DateTime(2017, 10, 18, 13, 30, 1));
new DateTime(2017, 10, 18, 13, 30, 1));
} }
@Test @Test
public void testYearly() throws ParseException { public void testYearly() throws ParseException {
Task task = newTask(with(ID, 1L), Task task =
newTask(
with(ID, 1L),
with(DUE_TIME, new DateTime(2017, 10, 4, 13, 30)), with(DUE_TIME, new DateTime(2017, 10, 4, 13, 30)),
with(RRULE, new RRule("RRULE:FREQ=YEARLY;INTERVAL=3"))); with(RRULE, new RRule("RRULE:FREQ=YEARLY;INTERVAL=3")));
repeatAndVerify(task, repeatAndVerify(
new DateTime(2017, 10, 4, 13, 30, 1), task, new DateTime(2017, 10, 4, 13, 30, 1), new DateTime(2020, 10, 4, 13, 30, 1));
new DateTime(2020, 10, 4, 13, 30, 1));
} }
@Test @Test
public void testMonthlyRepeat() throws ParseException { public void testMonthlyRepeat() throws ParseException {
Task task = newTask(with(ID, 1L), Task task =
newTask(
with(ID, 1L),
with(DUE_TIME, new DateTime(2017, 10, 4, 13, 30)), with(DUE_TIME, new DateTime(2017, 10, 4, 13, 30)),
with(RRULE, new RRule("RRULE:FREQ=MONTHLY;INTERVAL=3"))); with(RRULE, new RRule("RRULE:FREQ=MONTHLY;INTERVAL=3")));
repeatAndVerify(task, repeatAndVerify(
new DateTime(2017, 10, 4, 13, 30, 1), task, new DateTime(2017, 10, 4, 13, 30, 1), new DateTime(2018, 1, 4, 13, 30, 1));
new DateTime(2018, 1, 4, 13, 30, 1));
} }
@Test @Test
public void testMonthlyRepeatAtEndOfMonth() throws ParseException { public void testMonthlyRepeatAtEndOfMonth() throws ParseException {
Task task = newTask(with(ID, 1L), Task task =
newTask(
with(ID, 1L),
with(DUE_TIME, new DateTime(2017, 1, 31, 13, 30)), with(DUE_TIME, new DateTime(2017, 1, 31, 13, 30)),
with(RRULE, new RRule("RRULE:FREQ=MONTHLY;INTERVAL=1"))); with(RRULE, new RRule("RRULE:FREQ=MONTHLY;INTERVAL=1")));
repeatAndVerify(task, repeatAndVerify(
new DateTime(2017, 1, 31, 13, 30, 1), task, new DateTime(2017, 1, 31, 13, 30, 1), new DateTime(2017, 2, 28, 13, 30, 1));
new DateTime(2017, 2, 28, 13, 30, 1));
} }
private void repeatAndVerify(Task task, DateTime oldDueDate, DateTime newDueDate) { private void repeatAndVerify(Task task, DateTime oldDueDate, DateTime newDueDate) {
@ -192,7 +204,8 @@ public class RepeatTaskHelperTest extends InjectingTestCase {
mocks.verify(gCalHelper).rescheduleRepeatingTask(task); mocks.verify(gCalHelper).rescheduleRepeatingTask(task);
mocks.verify(alarmService).rescheduleAlarms(1, oldDueDate.getMillis(), newDueDate.getMillis()); mocks.verify(alarmService).rescheduleAlarms(1, oldDueDate.getMillis(), newDueDate.getMillis());
mocks.verify(localBroadcastManager) mocks
.verify(localBroadcastManager)
.broadcastRepeat(1, oldDueDate.getMillis(), newDueDate.getMillis()); .broadcastRepeat(1, oldDueDate.getMillis(), newDueDate.getMillis());
} }

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.service; package com.todoroo.astrid.service;
import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertEquals;

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* <p> *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.service; package com.todoroo.astrid.service;
import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertEquals;
@ -60,9 +59,7 @@ public class TitleParserTest extends InjectingTestCase {
assertEquals(task.getRecurrence(), nothing.getRecurrence()); assertEquals(task.getRecurrence(), nothing.getRecurrence());
} }
/** /** Tests correct date is parsed */
* Tests correct date is parsed
**/
@Test @Test
public void testMonthDate() { public void testMonthDate() {
String[] titleMonthStrings = { String[] titleMonthStrings = {
@ -138,11 +135,7 @@ public class TitleParserTest extends InjectingTestCase {
@Test @Test
public void test_several_forms_of_eight() { public void test_several_forms_of_eight() {
String[] testTitles = { String[] testTitles = {"Jog 8 AM", "Jog 8 o'clock AM", "at 8:00 AM"};
"Jog 8 AM",
"Jog 8 o'clock AM",
"at 8:00 AM"
};
for (String testTitle : testTitles) { for (String testTitle : testTitles) {
Task task = insertTitleAddTask(testTitle); Task task = insertTitleAddTask(testTitle);
DateTime date = newDateTime(task.getDueDate()); DateTime date = newDateTime(task.getDueDate());
@ -154,11 +147,7 @@ public class TitleParserTest extends InjectingTestCase {
@Test @Test
public void test_several_forms_of_1230PM() { public void test_several_forms_of_1230PM() {
String[] testTitles = { String[] testTitles = {
"Jog 12:30 PM", "Jog 12:30 PM", "at 12:30 PM", "Do something on 12:30 PM", "Jog at 12:30 PM Friday"
"at 12:30 PM",
"Do something on 12:30 PM",
"Jog at 12:30 PM Friday"
}; };
for (String testTitle : testTitles) { for (String testTitle : testTitles) {
Task task = insertTitleAddTask(testTitle); Task task = insertTitleAddTask(testTitle);
@ -172,7 +161,6 @@ public class TitleParserTest extends InjectingTestCase {
return taskCreator.createWithValues(null, title); return taskCreator.createWithValues(null, title);
} }
// ----------------Days begin----------------// // ----------------Days begin----------------//
@Test @Test
public void testDays() { public void testDays() {
@ -182,7 +170,7 @@ public class TitleParserTest extends InjectingTestCase {
Task task = taskCreator.createWithValues(null, title); Task task = taskCreator.createWithValues(null, title);
DateTime date = newDateTime(task.getDueDate()); DateTime date = newDateTime(task.getDueDate());
assertEquals(date.getDayOfWeek(), today.get(Calendar.DAY_OF_WEEK)); assertEquals(date.getDayOfWeek(), today.get(Calendar.DAY_OF_WEEK));
//Calendar starts 1-6, date.getDay() starts at 0 // Calendar starts 1-6, date.getDay() starts at 0
title = "Jog tomorrow"; title = "Jog tomorrow";
task = taskCreator.createWithValues(null, title); task = taskCreator.createWithValues(null, title);
@ -190,23 +178,9 @@ public class TitleParserTest extends InjectingTestCase {
assertEquals((date.getDayOfWeek()) % 7, (today.get(Calendar.DAY_OF_WEEK) + 1) % 7); assertEquals((date.getDayOfWeek()) % 7, (today.get(Calendar.DAY_OF_WEEK) + 1) % 7);
String[] days = { String[] days = {
"sunday", "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday",
"monday",
"tuesday",
"wednesday",
"thursday",
"friday",
"saturday",
};
String[] abrevDays = {
"sun.",
"mon.",
"tue.",
"wed.",
"thu.",
"fri.",
"sat."
}; };
String[] abrevDays = {"sun.", "mon.", "tue.", "wed.", "thu.", "fri.", "sat."};
for (int i = 1; i <= 6; i++) { for (int i = 1; i <= 6; i++) {
title = "Jog " + days[i]; title = "Jog " + days[i];
@ -219,24 +193,16 @@ public class TitleParserTest extends InjectingTestCase {
date = newDateTime(task.getDueDate()); date = newDateTime(task.getDueDate());
assertEquals(date.getDayOfWeek(), i + 1); assertEquals(date.getDayOfWeek(), i + 1);
} }
} }
//----------------Days end----------------// // ----------------Days end----------------//
//----------------Priority begin----------------// // ----------------Priority begin----------------//
/** /** tests all words using priority 0 */
* tests all words using priority 0
*/
@Test @Test
public void testPriority0() { public void testPriority0() {
String[] acceptedStrings = { String[] acceptedStrings = {"priority 0", "least priority", "lowest priority", "bang 0"};
"priority 0",
"least priority",
"lowest priority",
"bang 0"
};
for (String acceptedString : acceptedStrings) { for (String acceptedString : acceptedStrings) {
String title = "Jog " + acceptedString; String title = "Jog " + acceptedString;
Task task = taskCreator.createWithValues(null, title); Task task = taskCreator.createWithValues(null, title);
@ -251,50 +217,39 @@ public class TitleParserTest extends InjectingTestCase {
@Test @Test
public void testPriority1() { public void testPriority1() {
String[] acceptedStringsAtEnd = { String[] acceptedStringsAtEnd = {"priority 1", "low priority", "bang", "bang 1"};
"priority 1", String[] acceptedStringsAnywhere = {"!1", "!"};
"low priority",
"bang",
"bang 1"
};
String[] acceptedStringsAnywhere = {
"!1",
"!"
};
Task task; Task task;
for (String acceptedStringAtEnd : acceptedStringsAtEnd) { for (String acceptedStringAtEnd : acceptedStringsAtEnd) {
task = taskCreator.basicQuickAddTask( task =
"Jog " + acceptedStringAtEnd); //test at end of task. should set importance. taskCreator.basicQuickAddTask(
"Jog " + acceptedStringAtEnd); // test at end of task. should set importance.
assertEquals((int) task.getImportance(), Task.IMPORTANCE_SHOULD_DO); assertEquals((int) task.getImportance(), Task.IMPORTANCE_SHOULD_DO);
} }
for (String acceptedStringAtEnd : acceptedStringsAtEnd) { for (String acceptedStringAtEnd : acceptedStringsAtEnd) {
task = taskCreator.basicQuickAddTask( task =
acceptedStringAtEnd + " jog"); //test at beginning of task. should not set importance. taskCreator.basicQuickAddTask(
acceptedStringAtEnd
+ " jog"); // test at beginning of task. should not set importance.
assertEquals((int) task.getImportance(), Task.IMPORTANCE_SHOULD_DO); assertEquals((int) task.getImportance(), Task.IMPORTANCE_SHOULD_DO);
} }
for (String acceptedStringAnywhere : acceptedStringsAnywhere) { for (String acceptedStringAnywhere : acceptedStringsAnywhere) {
task = taskCreator.basicQuickAddTask( task =
"Jog " + acceptedStringAnywhere); //test at end of task. should set importance. taskCreator.basicQuickAddTask(
"Jog " + acceptedStringAnywhere); // test at end of task. should set importance.
assertEquals((int) task.getImportance(), Task.IMPORTANCE_SHOULD_DO); assertEquals((int) task.getImportance(), Task.IMPORTANCE_SHOULD_DO);
task = taskCreator.basicQuickAddTask( task =
acceptedStringAnywhere + " jog"); //test at beginning of task. should set importance. taskCreator.basicQuickAddTask(
acceptedStringAnywhere + " jog"); // test at beginning of task. should set importance.
assertEquals((int) task.getImportance(), Task.IMPORTANCE_SHOULD_DO); assertEquals((int) task.getImportance(), Task.IMPORTANCE_SHOULD_DO);
} }
} }
@Test @Test
public void testPriority2() { public void testPriority2() {
String[] acceptedStringsAtEnd = { String[] acceptedStringsAtEnd = {"priority 2", "high priority", "bang bang", "bang 2"};
"priority 2", String[] acceptedStringsAnywhere = {"!2", "!!"};
"high priority",
"bang bang",
"bang 2"
};
String[] acceptedStringsAnywhere = {
"!2",
"!!"
};
for (String acceptedStringAtEnd : acceptedStringsAtEnd) { for (String acceptedStringAtEnd : acceptedStringsAtEnd) {
String title = "Jog " + acceptedStringAtEnd; String title = "Jog " + acceptedStringAtEnd;
Task task = taskCreator.createWithValues(null, title); Task task = taskCreator.createWithValues(null, title);
@ -324,12 +279,7 @@ public class TitleParserTest extends InjectingTestCase {
"bang 3", "bang 3",
"bang bang bang bang bang bang bang" "bang bang bang bang bang bang bang"
}; };
String[] acceptedStringsAnywhere = { String[] acceptedStringsAnywhere = {"!3", "!!!", "!6", "!!!!!!!!!!!!!"};
"!3",
"!!!",
"!6",
"!!!!!!!!!!!!!"
};
for (String acceptedStringAtEnd : acceptedStringsAtEnd) { for (String acceptedStringAtEnd : acceptedStringsAtEnd) {
String title = "Jog " + acceptedStringAtEnd; String title = "Jog " + acceptedStringAtEnd;
Task task = taskCreator.createWithValues(null, title); Task task = taskCreator.createWithValues(null, title);
@ -350,13 +300,11 @@ public class TitleParserTest extends InjectingTestCase {
} }
} }
//----------------Priority end----------------// // ----------------Priority end----------------//
//----------------Repeats begin----------------// // ----------------Repeats begin----------------//
/** /** test daily repeat from due date, but with no due date set */
* test daily repeat from due date, but with no due date set
*/
@Test @Test
public void testDailyWithNoDueDate() { public void testDailyWithNoDueDate() {
String title = "Jog daily"; String title = "Jog daily";
@ -382,12 +330,9 @@ public class TitleParserTest extends InjectingTestCase {
assertFalse(task.hasDueTime()); assertFalse(task.hasDueTime());
assertFalse(task.hasDueDate()); assertFalse(task.hasDueDate());
} }
} }
/** /** test weekly repeat from due date, with no due date & time set */
* test weekly repeat from due date, with no due date & time set
*/
@Test @Test
public void testWeeklyWithNoDueDate() { public void testWeeklyWithNoDueDate() {
String title = "Jog weekly"; String title = "Jog weekly";
@ -415,9 +360,7 @@ public class TitleParserTest extends InjectingTestCase {
} }
} }
/** /** test hourly repeat from due date, with no due date but no time */
* test hourly repeat from due date, with no due date but no time
*/
@Test @Test
public void testMonthlyFromNoDueDate() { public void testMonthlyFromNoDueDate() {
String title = "Jog monthly"; String title = "Jog monthly";
@ -493,25 +436,18 @@ public class TitleParserTest extends InjectingTestCase {
} }
} }
//----------------Repeats end----------------// // ----------------Repeats end----------------//
//----------------Tags begin----------------// // ----------------Tags begin----------------//
/** /** tests all words using priority 0 */
* tests all words using priority 0
*/
@Test @Test
public void testTagsPound() { public void testTagsPound() {
String[] acceptedStrings = { String[] acceptedStrings = {"#tag", "#a", "#(a cool tag)", "#(cool)"};
"#tag",
"#a",
"#(a cool tag)",
"#(cool)"
};
Task task; Task task;
for (String acceptedString : acceptedStrings) { for (String acceptedString : acceptedStrings) {
task = new Task(); task = new Task();
task.setTitle("Jog " + acceptedString); //test at end of task. should set importance. task.setTitle("Jog " + acceptedString); // test at end of task. should set importance.
ArrayList<String> tags = new ArrayList<>(); ArrayList<String> tags = new ArrayList<>();
TitleParser.listHelper(tagService, task, tags); TitleParser.listHelper(tagService, task, tags);
String tag = TitleParser.trimParenthesis(acceptedString); String tag = TitleParser.trimParenthesis(acceptedString);
@ -521,21 +457,14 @@ public class TitleParserTest extends InjectingTestCase {
} }
} }
/** /** tests all words using priority 0 */
* tests all words using priority 0
*/
@Test @Test
public void testTagsAt() { public void testTagsAt() {
String[] acceptedStrings = { String[] acceptedStrings = {"@tag", "@a", "@(a cool tag)", "@(cool)"};
"@tag",
"@a",
"@(a cool tag)",
"@(cool)"
};
Task task; Task task;
for (String acceptedString : acceptedStrings) { for (String acceptedString : acceptedStrings) {
task = new Task(); task = new Task();
task.setTitle("Jog " + acceptedString); //test at end of task. should set importance. task.setTitle("Jog " + acceptedString); // test at end of task. should set importance.
ArrayList<String> tags = new ArrayList<>(); ArrayList<String> tags = new ArrayList<>();
TitleParser.listHelper(tagService, task, tags); TitleParser.listHelper(tagService, task, tags);
String tag = TitleParser.trimParenthesis(acceptedString); String tag = TitleParser.trimParenthesis(acceptedString);

@ -15,8 +15,8 @@ import org.tasks.injection.TestComponent;
public class SubtasksHelperTest extends SubtasksTestCase { public class SubtasksHelperTest extends SubtasksTestCase {
private static final String[] EXPECTED_ORDER = {"-1", "1", "2", "3", "4", "5", "6"}; private static final String[] EXPECTED_ORDER = {"-1", "1", "2", "3", "4", "5", "6"};
private static final String EXPECTED_REMOTE = "[\"-1\", [\"6\", \"4\", [\"3\", \"1\"]], \"2\", \"5\"]" private static final String EXPECTED_REMOTE =
.replaceAll("\\s", ""); "[\"-1\", [\"6\", \"4\", [\"3\", \"1\"]], \"2\", \"5\"]".replaceAll("\\s", "");
@Inject TaskDao taskDao; @Inject TaskDao taskDao;
@Override @Override
@ -25,8 +25,8 @@ public class SubtasksHelperTest extends SubtasksTestCase {
createTasks(); createTasks();
TaskListMetadata m = new TaskListMetadata(); TaskListMetadata m = new TaskListMetadata();
m.setFilter(TaskListMetadata.FILTER_ID_ALL); m.setFilter(TaskListMetadata.FILTER_ID_ALL);
updater.initializeFromSerializedTree(m, filter, updater.initializeFromSerializedTree(
SubtasksHelper.convertTreeToRemoteIds(taskDao, DEFAULT_SERIALIZED_TREE)); m, filter, SubtasksHelper.convertTreeToRemoteIds(taskDao, DEFAULT_SERIALIZED_TREE));
} }
private void createTask(String title, String uuid) { private void createTask(String title, String uuid) {
@ -58,7 +58,8 @@ public class SubtasksHelperTest extends SubtasksTestCase {
@Test @Test
public void testLocalToRemoteIdMapping() { public void testLocalToRemoteIdMapping() {
String mapped = SubtasksHelper.convertTreeToRemoteIds(taskDao, DEFAULT_SERIALIZED_TREE) String mapped =
SubtasksHelper.convertTreeToRemoteIds(taskDao, DEFAULT_SERIALIZED_TREE)
.replaceAll("\\s", ""); .replaceAll("\\s", "");
assertEquals(EXPECTED_REMOTE, mapped); assertEquals(EXPECTED_REMOTE, mapped);
} }

@ -22,8 +22,8 @@ public class SubtasksMovingTest extends SubtasksTestCase {
createTasks(); createTasks();
TaskListMetadata m = new TaskListMetadata(); TaskListMetadata m = new TaskListMetadata();
m.setFilter(TaskListMetadata.FILTER_ID_ALL); m.setFilter(TaskListMetadata.FILTER_ID_ALL);
updater.initializeFromSerializedTree(m, filter, updater.initializeFromSerializedTree(
SubtasksHelper.convertTreeToRemoteIds(taskDao, DEFAULT_SERIALIZED_TREE)); m, filter, SubtasksHelper.convertTreeToRemoteIds(taskDao, DEFAULT_SERIALIZED_TREE));
// Assert initial state is correct // Assert initial state is correct
expectParentAndPosition(A, null, 0); expectParentAndPosition(A, null, 0);

@ -31,8 +31,7 @@ public class SubtasksTestCase extends InjectingTestCase {
* E * E
* F * F
*/ */
static final String DEFAULT_SERIALIZED_TREE = "[-1, [1, 2, [3, 4]], 5, 6]" static final String DEFAULT_SERIALIZED_TREE = "[-1, [1, 2, [3, 4]], 5, 6]".replaceAll("\\s", "");
.replaceAll("\\s", "");
SubtasksFilterUpdater updater; SubtasksFilterUpdater updater;
Filter filter; Filter filter;
@Inject TaskListMetadataDao taskListMetadataDao; @Inject TaskListMetadataDao taskListMetadataDao;
@ -59,5 +58,4 @@ public class SubtasksTestCase extends InjectingTestCase {
assertEquals("Parent mismatch", parentId, n.parent.uuid); assertEquals("Parent mismatch", parentId, n.parent.uuid);
assertEquals("Position mismatch", positionInParent, n.parent.children.indexOf(n)); assertEquals("Position mismatch", positionInParent, n.parent.children.indexOf(n));
} }
} }

@ -22,5 +22,4 @@ public class SyncModelTest extends NewSyncTestCase {
TagData tag = createTagData(); TagData tag = createTagData();
assertFalse(Task.NO_UUID.equals(tag.getRemoteId())); assertFalse(Task.NO_UUID.equals(tag.getRemoteId()));
} }
} }

@ -1,5 +1,3 @@
package org.tasks; package org.tasks;
public class Snippet { public class Snippet {}
}

@ -19,16 +19,26 @@ public class DateTimeUtilsTest {
@Test @Test
public void testGetCurrentTime() { public void testGetCurrentTime() {
freezeAt(now).thawAfter(new Snippet() {{ freezeAt(now)
.thawAfter(
new Snippet() {
{
assertEquals(now.getMillis(), currentTimeMillis()); assertEquals(now.getMillis(), currentTimeMillis());
}}); }
});
} }
@Test @Test
public void testCreateNewUtcDate() { public void testCreateNewUtcDate() {
DateTime utc = now.toUTC(); DateTime utc = now.toUTC();
DateTime actual = newDateUtc(utc.getYear(), utc.getMonthOfYear(), utc.getDayOfMonth(), DateTime actual =
utc.getHourOfDay(), utc.getMinuteOfHour(), utc.getSecondOfMinute()); newDateUtc(
utc.getYear(),
utc.getMonthOfYear(),
utc.getDayOfMonth(),
utc.getHourOfDay(),
utc.getMinuteOfHour(),
utc.getSecondOfMinute());
assertEquals(utc.getMillis(), actual.getMillis()); assertEquals(utc.getMillis(), actual.getMillis());
} }

@ -13,9 +13,8 @@ public abstract class InjectingTestCase {
public void setUp() { public void setUp() {
initializeMockito(getTargetContext()); initializeMockito(getTargetContext());
component = DaggerTestComponent.builder() component =
.testModule(new TestModule(getTargetContext())) DaggerTestComponent.builder().testModule(new TestModule(getTargetContext())).build();
.build();
inject(component); inject(component);
} }

@ -17,6 +17,12 @@ import org.tasks.time.DateTime;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class BackupJobTest { public class BackupJobTest {
private static File newFile(DateTime lastModified) {
File result = mock(File.class);
stub(result.lastModified()).toReturn(lastModified.getMillis());
return result;
}
@Test @Test
public void filterExcludesXmlFiles() { public void filterExcludesXmlFiles() {
assertFalse(BackupJob.FILE_FILTER.accept(new File("/a/b/c/d/auto.180329-0001.xml"))); assertFalse(BackupJob.FILE_FILTER.accept(new File("/a/b/c/d/auto.180329-0001.xml")));
@ -33,9 +39,7 @@ public class BackupJobTest {
File file2 = newFile(newDate(2018, 3, 28)); File file2 = newFile(newDate(2018, 3, 28));
File file3 = newFile(newDate(2018, 3, 29)); File file3 = newFile(newDate(2018, 3, 29));
assertEquals( assertEquals(emptyList(), BackupJob.getDeleteList(new File[] {file2, file1, file3}, 7));
emptyList(),
BackupJob.getDeleteList(new File[] {file2, file1, file3}, 7));
} }
@Test @Test
@ -50,13 +54,6 @@ public class BackupJobTest {
File file3 = newFile(newDate(2018, 3, 29)); File file3 = newFile(newDate(2018, 3, 29));
assertEquals( assertEquals(
singletonList(file1), singletonList(file1), BackupJob.getDeleteList(new File[] {file2, file1, file3}, 2));
BackupJob.getDeleteList(new File[] {file2, file1, file3}, 2));
}
private static File newFile(DateTime lastModified) {
File result = mock(File.class);
stub(result.lastModified()).toReturn(lastModified.getMillis());
return result;
} }
} }

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package org.tasks.jobs; package org.tasks.jobs;
import static android.support.test.InstrumentationRegistry.getTargetContext; import static android.support.test.InstrumentationRegistry.getTargetContext;
@ -31,12 +30,10 @@ import org.tasks.preferences.Preferences;
public class BackupServiceTests extends InjectingTestCase { public class BackupServiceTests extends InjectingTestCase {
private static final long BACKUP_WAIT_TIME = 500L; private static final long BACKUP_WAIT_TIME = 500L;
private File temporaryDirectory = null;
@Inject TasksJsonExporter jsonExporter; @Inject TasksJsonExporter jsonExporter;
@Inject TaskDao taskDao; @Inject TaskDao taskDao;
@Inject Preferences preferences; @Inject Preferences preferences;
private File temporaryDirectory = null;
@Override @Override
public void setUp() { public void setUp() {

@ -59,12 +59,15 @@ public class NotificationQueueTest {
verify(jobManager).scheduleNotification(now); verify(jobManager).scheduleNotification(now);
Freeze.freezeAt(now).thawAfter(new Snippet() {{ Freeze.freezeAt(now)
.thawAfter(
new Snippet() {
{
assertEquals( assertEquals(
newHashSet(new AlarmEntry(1, 1, now), newHashSet(new AlarmEntry(1, 1, now), new ReminderEntry(1, now, TYPE_DUE)),
new ReminderEntry(1, now, TYPE_DUE)),
newHashSet(queue.getOverdueJobs())); newHashSet(queue.getOverdueJobs()));
}}); }
});
} }
@Test @Test
@ -78,11 +81,14 @@ public class NotificationQueueTest {
queue.remove(singletonList(new AlarmEntry(1, 1, now))); queue.remove(singletonList(new AlarmEntry(1, 1, now)));
Freeze.freezeAt(now).thawAfter(new Snippet() {{ Freeze.freezeAt(now)
.thawAfter(
new Snippet() {
{
assertEquals( assertEquals(
singletonList(new ReminderEntry(1, now, TYPE_DUE)), singletonList(new ReminderEntry(1, now, TYPE_DUE)), queue.getOverdueJobs());
queue.getOverdueJobs()); }
}}); });
} }
@Test @Test
@ -96,11 +102,13 @@ public class NotificationQueueTest {
queue.remove(singletonList(new ReminderEntry(1, now, TYPE_DUE))); queue.remove(singletonList(new ReminderEntry(1, now, TYPE_DUE)));
Freeze.freezeAt(now).thawAfter(new Snippet() {{ Freeze.freezeAt(now)
assertEquals( .thawAfter(
singletonList(new AlarmEntry(1, 1, now)), new Snippet() {
queue.getOverdueJobs()); {
}}); assertEquals(singletonList(new AlarmEntry(1, 1, now)), queue.getOverdueJobs());
}
});
} }
@Test @Test
@ -194,11 +202,14 @@ public class NotificationQueueTest {
verify(jobManager).scheduleNotification(now); verify(jobManager).scheduleNotification(now);
Freeze.freezeAt(now).thawAfter(new Snippet() {{ Freeze.freezeAt(now)
.thawAfter(
new Snippet() {
{
assertEquals( assertEquals(
singletonList(new ReminderEntry(1, now, TYPE_DUE)), singletonList(new ReminderEntry(1, now, TYPE_DUE)), queue.getOverdueJobs());
queue.getOverdueJobs()); }
}}); });
} }
@Test @Test
@ -210,11 +221,16 @@ public class NotificationQueueTest {
verify(jobManager).scheduleNotification(now); verify(jobManager).scheduleNotification(now);
Freeze.freezeAt(now).thawAfter(new Snippet() {{ Freeze.freezeAt(now)
.thawAfter(
new Snippet() {
{
assertEquals( assertEquals(
asList(new ReminderEntry(1, now, TYPE_DUE), new ReminderEntry(2, now, TYPE_DUE)), asList(
new ReminderEntry(1, now, TYPE_DUE), new ReminderEntry(2, now, TYPE_DUE)),
queue.getOverdueJobs()); queue.getOverdueJobs());
}}); }
});
} }
@Test @Test
@ -226,11 +242,17 @@ public class NotificationQueueTest {
verify(jobManager).scheduleNotification(now); verify(jobManager).scheduleNotification(now);
Freeze.freezeAt(now + 2 * ONE_MINUTE).thawAfter(new Snippet() {{ Freeze.freezeAt(now + 2 * ONE_MINUTE)
.thawAfter(
new Snippet() {
{
assertEquals( assertEquals(
asList(new ReminderEntry(1, now, TYPE_DUE), new ReminderEntry(2, now + ONE_MINUTE, TYPE_DUE)), asList(
new ReminderEntry(1, now, TYPE_DUE),
new ReminderEntry(2, now + ONE_MINUTE, TYPE_DUE)),
queue.getOverdueJobs()); queue.getOverdueJobs());
}}); }
});
} }
@Test @Test
@ -242,13 +264,15 @@ public class NotificationQueueTest {
verify(jobManager).scheduleNotification(now); verify(jobManager).scheduleNotification(now);
Freeze.freezeAt(now).thawAfter(new Snippet() {{ Freeze.freezeAt(now)
.thawAfter(
new Snippet() {
{
queue.remove(queue.getOverdueJobs()); queue.remove(queue.getOverdueJobs());
}}); }
});
assertEquals( assertEquals(singletonList(new ReminderEntry(2, now + ONE_MINUTE, TYPE_DUE)), queue.getJobs());
singletonList(new ReminderEntry(2, now + ONE_MINUTE, TYPE_DUE)),
queue.getJobs());
} }
@Test @Test
@ -261,13 +285,16 @@ public class NotificationQueueTest {
verify(jobManager).scheduleNotification(now); verify(jobManager).scheduleNotification(now);
Freeze.freezeAt(now + ONE_MINUTE).thawAfter(new Snippet() {{ Freeze.freezeAt(now + ONE_MINUTE)
.thawAfter(
new Snippet() {
{
queue.remove(queue.getOverdueJobs()); queue.remove(queue.getOverdueJobs());
}}); }
});
assertEquals( assertEquals(
singletonList(new ReminderEntry(3, now + 2 * ONE_MINUTE, TYPE_DUE)), singletonList(new ReminderEntry(3, now + 2 * ONE_MINUTE, TYPE_DUE)), queue.getJobs());
queue.getJobs());
} }
@Test @Test
@ -304,16 +331,21 @@ public class NotificationQueueTest {
verify(jobManager).scheduleNotification(due.getMillis()); verify(jobManager).scheduleNotification(due.getMillis());
Freeze.freezeAt(now).thawAfter(new Snippet() {{ Freeze.freezeAt(now)
.thawAfter(
new Snippet() {
{
List<? extends NotificationQueueEntry> overdueJobs = queue.getOverdueJobs(); List<? extends NotificationQueueEntry> overdueJobs = queue.getOverdueJobs();
assertEquals( assertEquals(
asList(new ReminderEntry(1, due.getMillis(), TYPE_DUE), asList(
new ReminderEntry(1, due.getMillis(), TYPE_DUE),
new ReminderEntry(2, snooze.getMillis(), TYPE_SNOOZE)), new ReminderEntry(2, snooze.getMillis(), TYPE_SNOOZE)),
overdueJobs); overdueJobs);
queue.remove(overdueJobs); queue.remove(overdueJobs);
assertEquals( assertEquals(
singletonList(new ReminderEntry(3, due.plusMinutes(1).getMillis(), TYPE_DUE)), singletonList(new ReminderEntry(3, due.plusMinutes(1).getMillis(), TYPE_DUE)),
queue.getJobs()); queue.getJobs());
}}); }
});
} }
} }

@ -11,12 +11,15 @@ import org.tasks.data.GoogleTaskList;
public class GtaskListMaker { public class GtaskListMaker {
public static final Property<GoogleTaskList, Long> ID = newProperty(); public static final Property<GoogleTaskList, Long> ID = newProperty();
private static final Property<GoogleTaskList, Integer> ORDER = newProperty();
public static final Property<GoogleTaskList, String> REMOTE_ID = newProperty(); public static final Property<GoogleTaskList, String> REMOTE_ID = newProperty();
public static final Property<GoogleTaskList, Long> LAST_SYNC = newProperty(); public static final Property<GoogleTaskList, Long> LAST_SYNC = newProperty();
public static final Property<GoogleTaskList, String> NAME = newProperty(); public static final Property<GoogleTaskList, String> NAME = newProperty();
private static final Property<GoogleTaskList, Integer> ORDER = newProperty();
private static final Property<GoogleTaskList, Integer> COLOR = newProperty(); private static final Property<GoogleTaskList, Integer> COLOR = newProperty();
private static final Instantiator<GoogleTaskList> instantiator = lookup -> new GoogleTaskList() {{ private static final Instantiator<GoogleTaskList> instantiator =
lookup ->
new GoogleTaskList() {
{
setDeleted(0L); setDeleted(0L);
setId(lookup.valueOf(GtaskListMaker.ID, 0L)); setId(lookup.valueOf(GtaskListMaker.ID, 0L));
setRemoteId(lookup.valueOf(REMOTE_ID, "1")); setRemoteId(lookup.valueOf(REMOTE_ID, "1"));
@ -24,7 +27,8 @@ public class GtaskListMaker {
setRemoteOrder(lookup.valueOf(ORDER, 0)); setRemoteOrder(lookup.valueOf(ORDER, 0));
setLastSync(lookup.valueOf(LAST_SYNC, 0L)); setLastSync(lookup.valueOf(LAST_SYNC, 0L));
setColor(lookup.valueOf(COLOR, -1)); setColor(lookup.valueOf(COLOR, -1));
}}; }
};
public static GoogleTaskList newGtaskList( public static GoogleTaskList newGtaskList(
PropertyValue<? super GoogleTaskList, ?>... properties) { PropertyValue<? super GoogleTaskList, ?>... properties) {

@ -8,8 +8,8 @@ import com.natpryce.makeiteasy.PropertyValue;
class Maker { class Maker {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T> T make(Instantiator<T> instantiator, public static <T> T make(
PropertyValue<? super T, ?>... properties) { Instantiator<T> instantiator, PropertyValue<? super T, ?>... properties) {
return com.natpryce.makeiteasy.MakeItEasy.make(a(instantiator, properties)); return com.natpryce.makeiteasy.MakeItEasy.make(a(instantiator, properties));
} }
} }

@ -15,10 +15,8 @@ import org.tasks.time.DateTime;
public class TaskMaker { public class TaskMaker {
public static final Property<Task, Long> ID = newProperty(); public static final Property<Task, Long> ID = newProperty();
private static final Property<Task, String> TITLE = newProperty();
public static final Property<Task, DateTime> DUE_DATE = newProperty(); public static final Property<Task, DateTime> DUE_DATE = newProperty();
public static final Property<Task, DateTime> DUE_TIME = newProperty(); public static final Property<Task, DateTime> DUE_TIME = newProperty();
private static final Property<Task, Integer> PRIORITY = newProperty();
public static final Property<Task, DateTime> REMINDER_LAST = newProperty(); public static final Property<Task, DateTime> REMINDER_LAST = newProperty();
public static final Property<Task, Long> RANDOM_REMINDER_PERIOD = newProperty(); public static final Property<Task, Long> RANDOM_REMINDER_PERIOD = newProperty();
public static final Property<Task, Integer> HIDE_TYPE = newProperty(); public static final Property<Task, Integer> HIDE_TYPE = newProperty();
@ -29,7 +27,10 @@ public class TaskMaker {
public static final Property<Task, DateTime> SNOOZE_TIME = newProperty(); public static final Property<Task, DateTime> SNOOZE_TIME = newProperty();
public static final Property<Task, RRule> RRULE = newProperty(); public static final Property<Task, RRule> RRULE = newProperty();
public static final Property<Task, Boolean> AFTER_COMPLETE = newProperty(); public static final Property<Task, Boolean> AFTER_COMPLETE = newProperty();
private static final Instantiator<Task> instantiator = lookup -> { private static final Property<Task, String> TITLE = newProperty();
private static final Property<Task, Integer> PRIORITY = newProperty();
private static final Instantiator<Task> instantiator =
lookup -> {
Task task = new Task(); Task task = new Task();
String title = lookup.valueOf(TITLE, (String) null); String title = lookup.valueOf(TITLE, (String) null);

@ -45,8 +45,8 @@ public class PreferenceTests {
long dueDate = new DateTime(2015, 12, 29, 18, 0, 1).getMillis(); long dueDate = new DateTime(2015, 12, 29, 18, 0, 1).getMillis();
assertEquals(new DateTime(2015, 12, 29, 19, 0).getMillis(), assertEquals(
preferences.adjustForQuietHours(dueDate)); new DateTime(2015, 12, 29, 19, 0).getMillis(), preferences.adjustForQuietHours(dueDate));
} }
@Test @Test
@ -56,8 +56,8 @@ public class PreferenceTests {
long dueDate = new DateTime(2015, 12, 29, 22, 0, 1).getMillis(); long dueDate = new DateTime(2015, 12, 29, 22, 0, 1).getMillis();
assertEquals(new DateTime(2015, 12, 30, 10, 0).getMillis(), assertEquals(
preferences.adjustForQuietHours(dueDate)); new DateTime(2015, 12, 30, 10, 0).getMillis(), preferences.adjustForQuietHours(dueDate));
} }
@Test @Test
@ -67,8 +67,8 @@ public class PreferenceTests {
long dueDate = new DateTime(2015, 12, 29, 23, 30).getMillis(); long dueDate = new DateTime(2015, 12, 29, 23, 30).getMillis();
assertEquals(new DateTime(2015, 12, 30, 10, 0).getMillis(), assertEquals(
preferences.adjustForQuietHours(dueDate)); new DateTime(2015, 12, 30, 10, 0).getMillis(), preferences.adjustForQuietHours(dueDate));
} }
@Test @Test
@ -78,8 +78,8 @@ public class PreferenceTests {
long dueDate = new DateTime(2015, 12, 30, 7, 15).getMillis(); long dueDate = new DateTime(2015, 12, 30, 7, 15).getMillis();
assertEquals(new DateTime(2015, 12, 30, 10, 0).getMillis(), assertEquals(
preferences.adjustForQuietHours(dueDate)); new DateTime(2015, 12, 30, 10, 0).getMillis(), preferences.adjustForQuietHours(dueDate));
} }
@Test @Test

@ -25,19 +25,22 @@ public class RepeatRuleToStringTest {
@Test @Test
public void weeklyByDay() { public void weeklyByDay() {
assertEquals("Repeats weekly on Mon, Tue, Wed, Thu, Fri", assertEquals(
"Repeats weekly on Mon, Tue, Wed, Thu, Fri",
toString("RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR")); toString("RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR"));
} }
@Test @Test
public void printDaysInRepeatRuleOrder() { public void printDaysInRepeatRuleOrder() {
assertEquals("Repeats weekly on Fri, Thu, Wed, Tue, Mon", assertEquals(
"Repeats weekly on Fri, Thu, Wed, Tue, Mon",
toString("RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=FR,TH,WE,TU,MO")); toString("RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=FR,TH,WE,TU,MO"));
} }
@Test @Test
public void useLocaleForDays() { public void useLocaleForDays() {
assertEquals("Wiederhole wöchentlich am Sa., So.", assertEquals(
"Wiederhole wöchentlich am Sa., So.",
toString("de", "RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=SA,SU")); toString("de", "RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=SA,SU"));
} }

@ -32,8 +32,10 @@ public class DateTimeTest {
TimeZone def = TimeZone.getDefault(); TimeZone def = TimeZone.getDefault();
try { try {
TimeZone.setDefault(TimeZone.getTimeZone("America/Chicago")); TimeZone.setDefault(TimeZone.getTimeZone("America/Chicago"));
assertEquals(2, assertEquals(
new DateTime(2015, 10, 31, 2, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(2)) 2,
new DateTime(2015, 10, 31, 2, 0, 0)
.withMillisOfDay((int) TimeUnit.HOURS.toMillis(2))
.getHourOfDay()); .getHourOfDay());
} finally { } finally {
TimeZone.setDefault(def); TimeZone.setDefault(def);
@ -45,8 +47,10 @@ public class DateTimeTest {
TimeZone def = TimeZone.getDefault(); TimeZone def = TimeZone.getDefault();
try { try {
TimeZone.setDefault(TimeZone.getTimeZone("America/Chicago")); TimeZone.setDefault(TimeZone.getTimeZone("America/Chicago"));
assertEquals(2, assertEquals(
new DateTime(2015, 11, 2, 2, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(2)) 2,
new DateTime(2015, 11, 2, 2, 0, 0)
.withMillisOfDay((int) TimeUnit.HOURS.toMillis(2))
.getHourOfDay()); .getHourOfDay());
} finally { } finally {
TimeZone.setDefault(def); TimeZone.setDefault(def);
@ -58,23 +62,33 @@ public class DateTimeTest {
TimeZone def = TimeZone.getDefault(); TimeZone def = TimeZone.getDefault();
try { try {
TimeZone.setDefault(TimeZone.getTimeZone("America/Chicago")); TimeZone.setDefault(TimeZone.getTimeZone("America/Chicago"));
assertEquals(1, assertEquals(
new DateTime(2015, 3, 8, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(1)) 1,
new DateTime(2015, 3, 8, 0, 0, 0)
.withMillisOfDay((int) TimeUnit.HOURS.toMillis(1))
.getHourOfDay()); .getHourOfDay());
assertEquals(3, assertEquals(
new DateTime(2015, 3, 8, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(2)) 3,
new DateTime(2015, 3, 8, 0, 0, 0)
.withMillisOfDay((int) TimeUnit.HOURS.toMillis(2))
.getHourOfDay()); .getHourOfDay());
assertEquals(3, assertEquals(
new DateTime(2015, 3, 8, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(3)) 3,
new DateTime(2015, 3, 8, 0, 0, 0)
.withMillisOfDay((int) TimeUnit.HOURS.toMillis(3))
.getHourOfDay()); .getHourOfDay());
assertEquals(4, assertEquals(
new DateTime(2015, 3, 8, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(4)) 4,
new DateTime(2015, 3, 8, 0, 0, 0)
.withMillisOfDay((int) TimeUnit.HOURS.toMillis(4))
.getHourOfDay()); .getHourOfDay());
assertEquals( assertEquals(
new DateTime(2015, 3, 8, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(2)) new DateTime(2015, 3, 8, 0, 0, 0)
.withMillisOfDay((int) TimeUnit.HOURS.toMillis(2))
.getMillis(), .getMillis(),
new DateTime(2015, 3, 8, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(3)) new DateTime(2015, 3, 8, 0, 0, 0)
.withMillisOfDay((int) TimeUnit.HOURS.toMillis(3))
.getMillis()); .getMillis());
} finally { } finally {
TimeZone.setDefault(def); TimeZone.setDefault(def);
@ -86,14 +100,20 @@ public class DateTimeTest {
TimeZone def = TimeZone.getDefault(); TimeZone def = TimeZone.getDefault();
try { try {
TimeZone.setDefault(TimeZone.getTimeZone("America/Chicago")); TimeZone.setDefault(TimeZone.getTimeZone("America/Chicago"));
assertEquals(1, assertEquals(
new DateTime(2015, 11, 1, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(1)) 1,
new DateTime(2015, 11, 1, 0, 0, 0)
.withMillisOfDay((int) TimeUnit.HOURS.toMillis(1))
.getHourOfDay()); .getHourOfDay());
assertEquals(2, assertEquals(
new DateTime(2015, 11, 1, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(2)) 2,
new DateTime(2015, 11, 1, 0, 0, 0)
.withMillisOfDay((int) TimeUnit.HOURS.toMillis(2))
.getHourOfDay()); .getHourOfDay());
assertEquals(3, assertEquals(
new DateTime(2015, 11, 1, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(3)) 3,
new DateTime(2015, 11, 1, 0, 0, 0)
.withMillisOfDay((int) TimeUnit.HOURS.toMillis(3))
.getHourOfDay()); .getHourOfDay());
} finally { } finally {
TimeZone.setDefault(def); TimeZone.setDefault(def);
@ -196,8 +216,7 @@ public class DateTimeTest {
@Test @Test
public void testWithHourOfDay() { public void testWithHourOfDay() {
assertEquals( assertEquals(
new DateTime(2015, 11, 6, 23, 0, 0), new DateTime(2015, 11, 6, 23, 0, 0), new DateTime(2015, 11, 6, 1, 0, 0).withHourOfDay(23));
new DateTime(2015, 11, 6, 1, 0, 0).withHourOfDay(23));
} }
@Test @Test
@ -222,17 +241,15 @@ public class DateTimeTest {
@Test @Test
public void testMinusMinutes() { public void testMinusMinutes() {
assertEquals( assertEquals(
new DateTime(2015, 11, 4, 23, 59, 0), new DateTime(2015, 11, 4, 23, 59, 0), new DateTime(2015, 11, 5, 0, 1, 0).minusMinutes(2));
new DateTime(2015, 11, 5, 0, 1, 0).minusMinutes(2));
} }
@Test @Test
public void testIsBefore() { public void testIsBefore() {
assertTrue(new DateTime(2015, 11, 4, 23, 59, 0) assertTrue(new DateTime(2015, 11, 4, 23, 59, 0).isBefore(new DateTime(2015, 11, 4, 23, 59, 1)));
.isBefore(new DateTime(2015, 11, 4, 23, 59, 1)));
assertFalse(new DateTime(2015, 11, 4, 23, 59, 0) assertFalse(
.isBefore(new DateTime(2015, 11, 4, 23, 59, 0))); new DateTime(2015, 11, 4, 23, 59, 0).isBefore(new DateTime(2015, 11, 4, 23, 59, 0)));
} }
@Test @Test
@ -242,25 +259,21 @@ public class DateTimeTest {
@Test @Test
public void testIsAfter() { public void testIsAfter() {
assertTrue(new DateTime(2015, 11, 4, 23, 59, 1) assertTrue(new DateTime(2015, 11, 4, 23, 59, 1).isAfter(new DateTime(2015, 11, 4, 23, 59, 0)));
.isAfter(new DateTime(2015, 11, 4, 23, 59, 0)));
assertFalse(new DateTime(2015, 11, 4, 23, 59, 0) assertFalse(new DateTime(2015, 11, 4, 23, 59, 0).isAfter(new DateTime(2015, 11, 4, 23, 59, 0)));
.isAfter(new DateTime(2015, 11, 4, 23, 59, 0)));
} }
@Test @Test
public void testWithYear() { public void testWithYear() {
assertEquals( assertEquals(
new DateTime(2016, 1, 1, 1, 1, 1), new DateTime(2016, 1, 1, 1, 1, 1), new DateTime(2015, 1, 1, 1, 1, 1).withYear(2016));
new DateTime(2015, 1, 1, 1, 1, 1).withYear(2016));
} }
@Test @Test
public void testWithMonthOfYear() { public void testWithMonthOfYear() {
assertEquals( assertEquals(
new DateTime(2015, 1, 2, 3, 4, 5), new DateTime(2015, 1, 2, 3, 4, 5), new DateTime(2015, 2, 2, 3, 4, 5).withMonthOfYear(1));
new DateTime(2015, 2, 2, 3, 4, 5).withMonthOfYear(1));
} }
@Test @Test
@ -271,37 +284,37 @@ public class DateTimeTest {
@Test @Test
public void testWithDayOfMonth() { public void testWithDayOfMonth() {
assertEquals( assertEquals(
new DateTime(2015, 1, 2, 3, 4, 5), new DateTime(2015, 1, 2, 3, 4, 5), new DateTime(2015, 1, 1, 3, 4, 5).withDayOfMonth(2));
new DateTime(2015, 1, 1, 3, 4, 5).withDayOfMonth(2));
} }
@Test @Test
public void testPlusMinutes() { public void testPlusMinutes() {
assertEquals( assertEquals(
new DateTime(2015, 1, 2, 3, 4, 5), new DateTime(2015, 1, 2, 3, 4, 5), new DateTime(2015, 1, 2, 2, 59, 5).plusMinutes(5));
new DateTime(2015, 1, 2, 2, 59, 5).plusMinutes(5));
} }
@Test @Test
public void testPlusHours() { public void testPlusHours() {
assertEquals( assertEquals(
new DateTime(2015, 1, 2, 3, 4, 5), new DateTime(2015, 1, 2, 3, 4, 5), new DateTime(2015, 1, 1, 3, 4, 5).plusHours(24));
new DateTime(2015, 1, 1, 3, 4, 5).plusHours(24));
} }
@Test @Test
public void testPlusWeeks() { public void testPlusWeeks() {
assertEquals( assertEquals(
new DateTime(2015, 1, 2, 3, 4, 5), new DateTime(2015, 1, 2, 3, 4, 5), new DateTime(2014, 12, 12, 3, 4, 5).plusWeeks(3));
new DateTime(2014, 12, 12, 3, 4, 5).plusWeeks(3));
} }
@Test @Test
public void testIsBeforeNow() { public void testIsBeforeNow() {
Freeze.freezeAt(new DateTime(2015, 10, 6, 16, 15, 27)).thawAfter(new Snippet() {{ Freeze.freezeAt(new DateTime(2015, 10, 6, 16, 15, 27))
.thawAfter(
new Snippet() {
{
assertFalse(new DateTime(2015, 10, 6, 16, 15, 27).isBeforeNow()); assertFalse(new DateTime(2015, 10, 6, 16, 15, 27).isBeforeNow());
assertTrue(new DateTime(2015, 10, 6, 16, 15, 26).isBeforeNow()); assertTrue(new DateTime(2015, 10, 6, 16, 15, 26).isBeforeNow());
}}); }
});
} }
@Test @Test
@ -314,12 +327,10 @@ public class DateTimeTest {
@Test @Test
public void testMinusDays() { public void testMinusDays() {
assertEquals( assertEquals(
new DateTime(2015, 11, 6, 16, 19, 16), new DateTime(2015, 11, 6, 16, 19, 16), new DateTime(2015, 12, 4, 16, 19, 16).minusDays(28));
new DateTime(2015, 12, 4, 16, 19, 16).minusDays(28));
assertEquals( assertEquals(
new DateTime(2015, 11, 6, 16, 19, 16), new DateTime(2015, 11, 6, 16, 19, 16), new DateTime(2015, 11, 7, 16, 19, 16).minusDays(1));
new DateTime(2015, 11, 7, 16, 19, 16).minusDays(1));
} }
@Test @Test

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.gtasks; package com.todoroo.astrid.gtasks;
import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNotNull;
@ -188,8 +187,7 @@ public class GtasksIndentActionTest extends InjectingTestCase {
GoogleTask metadata = googleTaskDao.getByTaskId(targetTask.getId()); GoogleTask metadata = googleTaskDao.getByTaskId(targetTask.getId());
assertNotNull("task has metadata", metadata); assertNotNull("task has metadata", metadata);
int indentation = metadata.getIndent(); int indentation = metadata.getIndent();
assertTrue("indentation: " + indentation, assertTrue("indentation: " + indentation, indentation == expected);
indentation == expected);
} }
private void givenTask(Task taskToTest) { private void givenTask(Task taskToTest) {

@ -43,8 +43,9 @@ public class GtasksListServiceTest extends InjectingTestCase {
@Override @Override
public void setUp() { public void setUp() {
super.setUp(); super.setUp();
gtasksListService = new GtasksListService(googleTaskListDao, taskDeleter, gtasksListService =
localBroadcastManager, googleTaskDao, taskDao); new GtasksListService(
googleTaskListDao, taskDeleter, localBroadcastManager, googleTaskDao, taskDao);
} }
@Override @Override
@ -54,15 +55,12 @@ public class GtasksListServiceTest extends InjectingTestCase {
@Test @Test
public void testCreateNewList() { public void testCreateNewList() {
setLists(newRemoteList( setLists(
with(RemoteGtaskListMaker.REMOTE_ID, "1"), newRemoteList(
with(RemoteGtaskListMaker.NAME, "Default"))); with(RemoteGtaskListMaker.REMOTE_ID, "1"), with(RemoteGtaskListMaker.NAME, "Default")));
assertEquals( assertEquals(
newGtaskList( newGtaskList(with(ID, 1L), with(REMOTE_ID, "1"), with(NAME, "Default")),
with(ID, 1L),
with(REMOTE_ID, "1"),
with(NAME, "Default")),
googleTaskListDao.getById(1L)); googleTaskListDao.getById(1L));
} }
@ -87,20 +85,19 @@ public class GtasksListServiceTest extends InjectingTestCase {
setLists(taskList); setLists(taskList);
assertEquals(singletonList(newGtaskList(with(ID, 2L), with(REMOTE_ID, "2"))), assertEquals(
singletonList(newGtaskList(with(ID, 2L), with(REMOTE_ID, "2"))),
googleTaskListDao.getActiveLists()); googleTaskListDao.getActiveLists());
} }
@Test @Test
public void testUpdateListName() { public void testUpdateListName() {
googleTaskListDao.insertOrReplace(newGtaskList( googleTaskListDao.insertOrReplace(
with(ID, 1L), newGtaskList(with(ID, 1L), with(REMOTE_ID, "1"), with(NAME, "oldName")));
with(REMOTE_ID, "1"),
with(NAME, "oldName")));
setLists(newRemoteList( setLists(
with(RemoteGtaskListMaker.REMOTE_ID, "1"), newRemoteList(
with(RemoteGtaskListMaker.NAME, "newName"))); with(RemoteGtaskListMaker.REMOTE_ID, "1"), with(RemoteGtaskListMaker.NAME, "newName")));
assertEquals("newName", googleTaskListDao.getById(1).getTitle()); assertEquals("newName", googleTaskListDao.getById(1).getTitle());
} }
@ -114,8 +111,8 @@ public class GtasksListServiceTest extends InjectingTestCase {
@Test @Test
public void testNewListNeedsUpdate() { public void testNewListNeedsUpdate() {
TaskList taskList = new TaskList().setId("1").setTitle("Default") TaskList taskList =
.setUpdated(new DateTime(currentTimeMillis())); new TaskList().setId("1").setTitle("Default").setUpdated(new DateTime(currentTimeMillis()));
setLists(taskList); setLists(taskList);

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.gtasks; package com.todoroo.astrid.gtasks;
import static android.support.test.InstrumentationRegistry.getTargetContext; import static android.support.test.InstrumentationRegistry.getTargetContext;
@ -37,9 +36,7 @@ public class GtasksMetadataServiceTest extends InjectingTestCase {
@Override @Override
protected void inject(TestComponent component) { protected void inject(TestComponent component) {
component component.plus(new GtasksMetadataServiceTestModule(getTargetContext())).inject(this);
.plus(new GtasksMetadataServiceTestModule(getTargetContext()))
.inject(this);
} }
@Test @Test

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.gtasks; package com.todoroo.astrid.gtasks;
import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertEquals;
@ -110,8 +109,10 @@ public class GtasksTaskListUpdaterTest extends InjectingTestCase {
if (expectedParent == null) { if (expectedParent == null) {
assertEquals("Task " + task.getTitle() + " parent none", 0, parent); assertEquals("Task " + task.getTitle() + " parent none", 0, parent);
} else { } else {
assertEquals("Task " + task.getTitle() + " parent " + assertEquals(
expectedParent.getTitle(), expectedParent.getId(), parent); "Task " + task.getTitle() + " parent " + expectedParent.getTitle(),
expectedParent.getId(),
parent);
} }
} }
@ -120,8 +121,10 @@ public class GtasksTaskListUpdaterTest extends InjectingTestCase {
if (expectedSibling == null) { if (expectedSibling == null) {
assertEquals("Task " + task.getTitle() + " sibling null", 0L, sibling); assertEquals("Task " + task.getTitle() + " sibling null", 0L, sibling);
} else { } else {
assertEquals("Task " + task.getTitle() + " sibling " + assertEquals(
expectedSibling.getTitle(), expectedSibling.getId(), sibling); "Task " + task.getTitle() + " sibling " + expectedSibling.getTitle(),
expectedSibling.getId(),
sibling);
} }
} }
@ -130,8 +133,10 @@ public class GtasksTaskListUpdaterTest extends InjectingTestCase {
if (expectedParent == null) { if (expectedParent == null) {
assertEquals("Task " + task.getTitle() + " parent null", 0L, parent); assertEquals("Task " + task.getTitle() + " parent null", 0L, parent);
} else { } else {
assertEquals("Task " + task.getTitle() + " parent " + assertEquals(
expectedParent.getTitle(), expectedParent.getId(), parent); "Task " + task.getTitle() + " parent " + expectedParent.getTitle(),
expectedParent.getId(),
parent);
} }
} }
@ -162,15 +167,13 @@ public class GtasksTaskListUpdaterTest extends InjectingTestCase {
} }
} }
/** // A
* A // B
* B // C
* C // D
* D // E
* E
*/
private Task[] givenTasksABCDE() { private Task[] givenTasksABCDE() {
return new Task[]{ return new Task[] {
createTask("A", 0, 0), createTask("A", 0, 0),
createTask("B", 1, 1), createTask("B", 1, 1),
createTask("C", 2, 1), createTask("C", 2, 1),
@ -179,7 +182,6 @@ public class GtasksTaskListUpdaterTest extends InjectingTestCase {
}; };
} }
private Task createTask(String title, long order, int indent) { private Task createTask(String title, long order, int indent) {
Task task = new Task(); Task task = new Task();
task.setTitle(title); task.setTitle(title);

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.gtasks; package com.todoroo.astrid.gtasks;
import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertEquals;
@ -245,9 +244,7 @@ public class GtasksTaskMovingTest extends InjectingTestCase {
// --- helpers // --- helpers
/** /** moveTo = null => move to end */
* moveTo = null => move to end
*/
private void whenTriggerMove(Task target, Task moveTo) { private void whenTriggerMove(Task target, Task moveTo) {
gtasksTaskListUpdater.moveTo(list, target.getId(), moveTo == null ? -1 : moveTo.getId()); gtasksTaskListUpdater.moveTo(list, target.getId(), moveTo == null ? -1 : moveTo.getId());
} }
@ -278,14 +275,12 @@ public class GtasksTaskMovingTest extends InjectingTestCase {
component.inject(this); component.inject(this);
} }
/** // A
* A // B
* B // C
* C // D
* D // E
* E // F
* F
*/
private void givenTasksABCDEF() { private void givenTasksABCDEF() {
A = createTask("A", 0, 0); A = createTask("A", 0, 0);
B = createTask("B", 1, 1); B = createTask("B", 1, 1);

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.gtasks; package com.todoroo.astrid.gtasks;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;

@ -65,8 +65,7 @@ public class GtasksApiUtilitiesTest {
TimeZone.getTimeZone("GMT")); TimeZone.getTimeZone("GMT"));
assertEquals( assertEquals(
new DateTime(2014, 1, 8, 6, 0, 0, 0).getMillis(), new DateTime(2014, 1, 8, 6, 0, 0, 0).getMillis(), gtasksDueTimeToUnixTime(googleDueDate));
gtasksDueTimeToUnixTime(googleDueDate));
} }
@Test @Test

@ -25,9 +25,7 @@ public class GoogleTaskSynchronizerTest {
mergeDates(newTask(with(DUE_DATE, new DateTime(2016, 3, 11))).getDueDate(), local); mergeDates(newTask(with(DUE_DATE, new DateTime(2016, 3, 11))).getDueDate(), local);
assertEquals( assertEquals(new DateTime(2016, 3, 11, 12, 0).getMillis(), local.getDueDate().longValue());
new DateTime(2016, 3, 11, 12, 0).getMillis(),
local.getDueDate().longValue());
} }
@Test @Test
@ -36,63 +34,59 @@ public class GoogleTaskSynchronizerTest {
mergeDates(newTask(with(DUE_DATE, new DateTime(2016, 3, 11))).getDueDate(), local); mergeDates(newTask(with(DUE_DATE, new DateTime(2016, 3, 11))).getDueDate(), local);
assertEquals( assertEquals(new DateTime(2016, 3, 11, 13, 30, 1).getMillis(), local.getDueDate().longValue());
new DateTime(2016, 3, 11, 13, 30, 1).getMillis(),
local.getDueDate().longValue());
} }
@Test @Test
public void testDueDateAdjustHideBackwards() { public void testDueDateAdjustHideBackwards() {
Task local = newTask(with(DUE_DATE, new DateTime(2016, 3, 12)), Task local =
with(HIDE_TYPE, HIDE_UNTIL_DUE)); newTask(with(DUE_DATE, new DateTime(2016, 3, 12)), with(HIDE_TYPE, HIDE_UNTIL_DUE));
mergeDates(newTask(with(DUE_DATE, new DateTime(2016, 3, 11))).getDueDate(), local); mergeDates(newTask(with(DUE_DATE, new DateTime(2016, 3, 11))).getDueDate(), local);
assertEquals( assertEquals(new DateTime(2016, 3, 11).getMillis(), local.getHideUntil().longValue());
new DateTime(2016, 3, 11).getMillis(),
local.getHideUntil().longValue());
} }
@Test @Test
public void testDueDateAdjustHideForwards() { public void testDueDateAdjustHideForwards() {
Task local = newTask(with(DUE_DATE, new DateTime(2016, 3, 12)), Task local =
with(HIDE_TYPE, HIDE_UNTIL_DUE)); newTask(with(DUE_DATE, new DateTime(2016, 3, 12)), with(HIDE_TYPE, HIDE_UNTIL_DUE));
mergeDates(newTask(with(DUE_DATE, new DateTime(2016, 3, 14))).getDueDate(), local); mergeDates(newTask(with(DUE_DATE, new DateTime(2016, 3, 14))).getDueDate(), local);
assertEquals( assertEquals(new DateTime(2016, 3, 14).getMillis(), local.getHideUntil().longValue());
new DateTime(2016, 3, 14).getMillis(),
local.getHideUntil().longValue());
} }
@Test @Test
public void testDueTimeAdjustHideBackwards() { public void testDueTimeAdjustHideBackwards() {
Task local = newTask(with(DUE_TIME, new DateTime(2016, 3, 12, 13, 30)), Task local =
newTask(
with(DUE_TIME, new DateTime(2016, 3, 12, 13, 30)),
with(HIDE_TYPE, HIDE_UNTIL_DUE_TIME)); with(HIDE_TYPE, HIDE_UNTIL_DUE_TIME));
mergeDates(newTask(with(DUE_DATE, new DateTime(2016, 3, 11))).getDueDate(), local); mergeDates(newTask(with(DUE_DATE, new DateTime(2016, 3, 11))).getDueDate(), local);
assertEquals( assertEquals(
new DateTime(2016, 3, 11, 13, 30, 1).getMillis(), new DateTime(2016, 3, 11, 13, 30, 1).getMillis(), local.getHideUntil().longValue());
local.getHideUntil().longValue());
} }
@Test @Test
public void testDueTimeAdjustTimeForwards() { public void testDueTimeAdjustTimeForwards() {
Task local = newTask(with(DUE_TIME, new DateTime(2016, 3, 12, 13, 30)), Task local =
newTask(
with(DUE_TIME, new DateTime(2016, 3, 12, 13, 30)),
with(HIDE_TYPE, HIDE_UNTIL_DUE_TIME)); with(HIDE_TYPE, HIDE_UNTIL_DUE_TIME));
mergeDates(newTask(with(DUE_DATE, new DateTime(2016, 3, 14))).getDueDate(), local); mergeDates(newTask(with(DUE_DATE, new DateTime(2016, 3, 14))).getDueDate(), local);
assertEquals( assertEquals(
new DateTime(2016, 3, 14, 13, 30, 1).getMillis(), new DateTime(2016, 3, 14, 13, 30, 1).getMillis(), local.getHideUntil().longValue());
local.getHideUntil().longValue());
} }
@Test @Test
public void testDueDateClearHide() { public void testDueDateClearHide() {
Task local = newTask(with(DUE_DATE, new DateTime(2016, 3, 12)), Task local =
with(HIDE_TYPE, HIDE_UNTIL_DUE)); newTask(with(DUE_DATE, new DateTime(2016, 3, 12)), with(HIDE_TYPE, HIDE_UNTIL_DUE));
mergeDates(newTask().getDueDate(), local); mergeDates(newTask().getDueDate(), local);
@ -101,7 +95,9 @@ public class GoogleTaskSynchronizerTest {
@Test @Test
public void testDueTimeClearHide() { public void testDueTimeClearHide() {
Task local = newTask(with(DUE_TIME, new DateTime(2016, 3, 12, 13, 30)), Task local =
newTask(
with(DUE_TIME, new DateTime(2016, 3, 12, 13, 30)),
with(HIDE_TYPE, HIDE_UNTIL_DUE_TIME)); with(HIDE_TYPE, HIDE_UNTIL_DUE_TIME));
mergeDates(newTask().getDueDate(), local); mergeDates(newTask().getDueDate(), local);

@ -14,7 +14,9 @@ public class RemoteGtaskListMaker {
public static final Property<TaskList, String> REMOTE_ID = newProperty(); public static final Property<TaskList, String> REMOTE_ID = newProperty();
public static final Property<TaskList, String> NAME = newProperty(); public static final Property<TaskList, String> NAME = newProperty();
private static final Instantiator<TaskList> instantiator = lookup -> new TaskList() private static final Instantiator<TaskList> instantiator =
lookup ->
new TaskList()
.setId(lookup.valueOf(REMOTE_ID, "1")) .setId(lookup.valueOf(REMOTE_ID, "1"))
.setTitle(lookup.valueOf(NAME, "Default")) .setTitle(lookup.valueOf(NAME, "Default"))
.setUpdated(new DateTime(currentTimeMillis())); .setUpdated(new DateTime(currentTimeMillis()));

@ -2,6 +2,4 @@ package org.tasks;
import android.support.multidex.MultiDexApplication; import android.support.multidex.MultiDexApplication;
public abstract class BaseApplication extends MultiDexApplication { public abstract class BaseApplication extends MultiDexApplication {}
}

@ -32,13 +32,15 @@ public class BuildSetup {
} }
LeakCanary.install(application); LeakCanary.install(application);
if (preferences.getBoolean(R.string.p_strict_mode, false)) { if (preferences.getBoolean(R.string.p_strict_mode, false)) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() StrictMode.setThreadPolicy(
new StrictMode.ThreadPolicy.Builder()
.detectDiskReads() .detectDiskReads()
.detectDiskWrites() .detectDiskWrites()
.detectNetwork() .detectNetwork()
.penaltyLog() .penaltyLog()
.build()); .build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() StrictMode.setVmPolicy(
new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects() .detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects() .detectLeakedClosableObjects()
.penaltyLog() .penaltyLog()

@ -5,9 +5,7 @@ import javax.inject.Inject;
public class FlavorSetup { public class FlavorSetup {
@Inject @Inject
public FlavorSetup() { public FlavorSetup() {}
}
public void setup() { public void setup() {}
}
} }

@ -6,13 +6,9 @@ import timber.log.Timber;
public class Tracker { public class Tracker {
@Inject @Inject
public Tracker() { public Tracker() {}
} public void setTrackingEnabled(boolean enabled) {}
public void setTrackingEnabled(boolean enabled) {
}
public void reportException(Throwable t) { public void reportException(Throwable t) {
Timber.e(t, t.getMessage()); Timber.e(t, t.getMessage());
@ -22,19 +18,11 @@ public class Tracker {
Timber.e(t, t.getMessage()); Timber.e(t, t.getMessage());
} }
public void reportEvent(Tracking.Events event) { public void reportEvent(Tracking.Events event) {}
}
public void reportEvent(Tracking.Events event, String string) {
}
public void reportEvent(Tracking.Events setPreference, int resId, String s) {
} public void reportEvent(Tracking.Events event, String string) {}
public void reportEvent(Tracking.Events category, String action, String label) { public void reportEvent(Tracking.Events setPreference, int resId, String s) {}
} public void reportEvent(Tracking.Events category, String action, String label) {}
} }

@ -14,24 +14,21 @@ public class PurchaseHelper {
this.preferences = preferences; this.preferences = preferences;
} }
public boolean purchase(final Activity activity, public boolean purchase(
final String sku, final String pref, final Activity activity,
final int requestCode, final PurchaseHelperCallback callback) { final String sku,
final String pref,
final int requestCode,
final PurchaseHelperCallback callback) {
preferences.setBoolean(pref, true); preferences.setBoolean(pref, true);
callback.purchaseCompleted(true, sku); callback.purchaseCompleted(true, sku);
return true; return true;
} }
public void handleActivityResult(PurchaseHelperCallback callback, int requestCode, int resultCode, public void handleActivityResult(
Intent data) { PurchaseHelperCallback callback, int requestCode, int resultCode, Intent data) {}
} public void disposeIabHelper() {}
public void disposeIabHelper() {
}
public void consumePurchases() {
} public void consumePurchases() {}
} }

@ -8,9 +8,7 @@ import javax.inject.Inject;
public class PlayServices { public class PlayServices {
@Inject @Inject
public PlayServices() { public PlayServices() {}
}
public boolean isPlayServicesAvailable() { public boolean isPlayServicesAvailable() {
return false; return false;
@ -20,9 +18,7 @@ public class PlayServices {
return false; return false;
} }
public void resolve(Activity activity) { public void resolve(Activity activity) {}
}
public String getStatus() { public String getStatus() {
return null; return null;
@ -32,8 +28,8 @@ public class PlayServices {
return false; return false;
} }
public void getAuthToken(GtasksLoginActivity gtasksLoginActivity, String a, public void getAuthToken(
GtasksLoginActivity.AuthResultHandler authResultHandler) { GtasksLoginActivity gtasksLoginActivity,
String a,
} GtasksLoginActivity.AuthResultHandler authResultHandler) {}
} }

@ -8,19 +8,11 @@ import org.tasks.data.Location;
public class GeofenceApi { public class GeofenceApi {
@Inject @Inject
public GeofenceApi() { public GeofenceApi() {}
} public void register(List<Location> activeGeofences) {}
public void register(List<Location> activeGeofences) { public void cancel(Location geofence) {}
} public void cancel(List<Location> geofences) {}
public void cancel(Location geofence) {
}
public void cancel(List<Location> geofences) {
}
} }

@ -1,5 +1,3 @@
package org.tasks.location; package org.tasks.location;
public class GeofenceTransitionsIntentService { public class GeofenceTransitionsIntentService {}
}

@ -20,24 +20,20 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
/** /**
* Receiver for the "com.android.vending.billing.PURCHASES_UPDATED" Action * Receiver for the "com.android.vending.billing.PURCHASES_UPDATED" Action from the Play Store.
* from the Play Store.
* *
* <p>It is possible that an in-app item may be acquired without the * <p>It is possible that an in-app item may be acquired without the application calling
* application calling getBuyIntent(), for example if the item can be * getBuyIntent(), for example if the item can be redeemed from inside the Play Store using a
* redeemed from inside the Play Store using a promotional code. If this * promotional code. If this application isn't running at the time, then when it is started a call
* application isn't running at the time, then when it is started a call * to getPurchases() will be sufficient notification. However, if the application is already running
* to getPurchases() will be sufficient notification. However, if the * in the background when the item is acquired, a message to this BroadcastReceiver will indicate
* application is already running in the background when the item is acquired, * that the an item has been acquired.
* a message to this BroadcastReceiver will indicate that the an item
* has been acquired.</p>
*/ */
public class IabBroadcastReceiver extends BroadcastReceiver { public class IabBroadcastReceiver extends BroadcastReceiver {
/** /** The Intent action that this Receiver should filter for. */
* The Intent action that this Receiver should filter for.
*/
public static final String ACTION = "com.android.vending.billing.PURCHASES_UPDATED"; public static final String ACTION = "com.android.vending.billing.PURCHASES_UPDATED";
private final IabBroadcastListener mListener; private final IabBroadcastListener mListener;
public IabBroadcastReceiver(IabBroadcastListener listener) { public IabBroadcastReceiver(IabBroadcastListener listener) {
@ -51,9 +47,7 @@ public class IabBroadcastReceiver extends BroadcastReceiver {
} }
} }
/** /** Listener interface for received broadcast messages. */
* Listener interface for received broadcast messages.
*/
public interface IabBroadcastListener { public interface IabBroadcastListener {
void receivedBroadcast(); void receivedBroadcast();

@ -16,10 +16,9 @@
package com.android.vending.billing; package com.android.vending.billing;
/** /**
* Exception thrown when something went wrong with in-app billing. * Exception thrown when something went wrong with in-app billing. An IabException has an associated
* An IabException has an associated IabResult (an error). * IabResult (an error). To get the IAB result that caused this exception to be thrown, call {@link
* To get the IAB result that caused this exception to be thrown, * #getResult()}.
* call {@link #getResult()}.
*/ */
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
public class IabException extends Exception { public class IabException extends Exception {
@ -43,9 +42,7 @@ public class IabException extends Exception {
this(new IabResult(response, message), cause); this(new IabResult(response, message), cause);
} }
/** /** Returns the IAB result (error) that this exception signals. */
* Returns the IAB result (error) that this exception signals.
*/
public IabResult getResult() { public IabResult getResult() {
return mResult; return mResult;
} }

@ -35,35 +35,29 @@ import java.util.List;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import org.json.JSONException; import org.json.JSONException;
/** /**
* Provides convenience methods for in-app billing. You can create one instance of this * Provides convenience methods for in-app billing. You can create one instance of this class for
* class for your application and use it to process in-app billing operations. * your application and use it to process in-app billing operations. It provides synchronous
* It provides synchronous (blocking) and asynchronous (non-blocking) methods for * (blocking) and asynchronous (non-blocking) methods for many common in-app billing operations, as
* many common in-app billing operations, as well as automatic signature * well as automatic signature verification.
* verification.
* *
* After instantiating, you must perform setup in order to start using the object. * <p>After instantiating, you must perform setup in order to start using the object. To perform
* To perform setup, call the {@link #startSetup} method and provide a listener; * setup, call the {@link #startSetup} method and provide a listener; that listener will be notified
* that listener will be notified when setup is complete, after which (and not before) * when setup is complete, after which (and not before) you may call other methods.
* you may call other methods.
* *
* After setup is complete, you will typically want to request an inventory of owned * <p>After setup is complete, you will typically want to request an inventory of owned items and
* items and subscriptions. See {@link #queryInventory}, {@link #queryInventoryAsync} * subscriptions. See {@link #queryInventory}, {@link #queryInventoryAsync} and related methods.
* and related methods.
* *
* When you are done with this object, don't forget to call {@link #dispose} * <p>When you are done with this object, don't forget to call {@link #dispose} to ensure proper
* to ensure proper cleanup. This object holds a binding to the in-app billing * cleanup. This object holds a binding to the in-app billing service, which will leak unless you
* service, which will leak unless you dispose of it correctly. If you created * dispose of it correctly. If you created the object on an Activity's onCreate method, then the
* the object on an Activity's onCreate method, then the recommended * recommended place to dispose of it is the Activity's onDestroy method.
* place to dispose of it is the Activity's onDestroy method.
* *
* A note about threading: When using this object from a background thread, you may * <p>A note about threading: When using this object from a background thread, you may call the
* call the blocking versions of methods; when using from a UI thread, call * blocking versions of methods; when using from a UI thread, call only the asynchronous versions
* only the asynchronous versions and handle the results via callbacks. * and handle the results via callbacks. Also, notice that you can only call one asynchronous
* Also, notice that you can only call one asynchronous operation at a time; * operation at a time; attempting to start a second asynchronous operation while the first one has
* attempting to start a second asynchronous operation while the first one * not yet completed will result in an exception being thrown.
* has not yet completed will result in an exception being thrown.
*/ */
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
@SuppressLint("all") @SuppressLint("all")
@ -142,15 +136,15 @@ public class IabHelper {
OnIabPurchaseFinishedListener mPurchaseListener; OnIabPurchaseFinishedListener mPurchaseListener;
/** /**
* Creates an instance. After creation, it will not yet be ready to use. You must perform * Creates an instance. After creation, it will not yet be ready to use. You must perform setup by
* setup by calling {@link #startSetup} and wait for setup to complete. This constructor does not * calling {@link #startSetup} and wait for setup to complete. This constructor does not block and
* block and is safe to call from a UI thread. * is safe to call from a UI thread.
* *
* @param ctx Your application or Activity context. Needed to bind to the in-app billing service. * @param ctx Your application or Activity context. Needed to bind to the in-app billing service.
* @param base64PublicKey Your application's public key, encoded in base64. This is used for * @param base64PublicKey Your application's public key, encoded in base64. This is used for
* verification of purchase signatures. You can find your app's base64-encoded public key in your * verification of purchase signatures. You can find your app's base64-encoded public key in
* application's page on Google Play Developer Console. Note that this is NOT your "developer * your application's page on Google Play Developer Console. Note that this is NOT your
* public key". * "developer public key".
*/ */
public IabHelper(Context ctx, String base64PublicKey, Executor executor) { public IabHelper(Context ctx, String base64PublicKey, Executor executor) {
mContext = ctx.getApplicationContext(); mContext = ctx.getApplicationContext();
@ -167,20 +161,24 @@ public class IabHelper {
* numerically. * numerically.
*/ */
public static String getResponseDesc(int code) { public static String getResponseDesc(int code) {
String[] iab_msgs = ("0:OK/1:User Canceled/2:Unknown/" + String[] iab_msgs =
"3:Billing Unavailable/4:Item unavailable/" + ("0:OK/1:User Canceled/2:Unknown/"
"5:Developer Error/6:Error/7:Item Already Owned/" + + "3:Billing Unavailable/4:Item unavailable/"
"8:Item not owned").split("/"); + "5:Developer Error/6:Error/7:Item Already Owned/"
String[] iabhelper_msgs = ("0:OK/-1001:Remote exception during initialization/" + + "8:Item not owned")
"-1002:Bad response received/" + .split("/");
"-1003:Purchase signature verification failed/" + String[] iabhelper_msgs =
"-1004:Send intent failed/" + ("0:OK/-1001:Remote exception during initialization/"
"-1005:User cancelled/" + + "-1002:Bad response received/"
"-1006:Unknown purchase response/" + + "-1003:Purchase signature verification failed/"
"-1007:Missing token/" + + "-1004:Send intent failed/"
"-1008:Unknown error/" + + "-1005:User cancelled/"
"-1009:Subscriptions not available/" + + "-1006:Unknown purchase response/"
"-1010:Invalid consumption attempt").split("/"); + "-1007:Missing token/"
+ "-1008:Unknown error/"
+ "-1009:Subscriptions not available/"
+ "-1010:Invalid consumption attempt")
.split("/");
if (code <= IABHELPER_ERROR_BASE) { if (code <= IABHELPER_ERROR_BASE) {
int index = IABHELPER_ERROR_BASE - code; int index = IABHELPER_ERROR_BASE - code;
@ -196,9 +194,7 @@ public class IabHelper {
} }
} }
/** /** Enables or disable debug logging through LogCat. */
* Enables or disable debug logging through LogCat.
*/
public void enableDebugLogging(boolean enable, String tag) { public void enableDebugLogging(boolean enable, String tag) {
checkNotDisposed(); checkNotDisposed();
mDebugLog = enable; mDebugLog = enable;
@ -211,9 +207,9 @@ public class IabHelper {
} }
/** /**
* Starts the setup process. This will start up the setup process asynchronously. * Starts the setup process. This will start up the setup process asynchronously. You will be
* You will be notified through the listener when the setup process is complete. * notified through the listener when the setup process is complete. This method is safe to call
* This method is safe to call from a UI thread. * from a UI thread.
* *
* @param listener The listener to notify when the setup process is complete. * @param listener The listener to notify when the setup process is complete.
*/ */
@ -226,7 +222,8 @@ public class IabHelper {
// Connection to IAB service // Connection to IAB service
logDebug("Starting in-app billing setup."); logDebug("Starting in-app billing setup.");
mServiceConn = new ServiceConnection() { mServiceConn =
new ServiceConnection() {
@Override @Override
public void onServiceDisconnected(ComponentName name) { public void onServiceDisconnected(ComponentName name) {
logDebug("Billing service disconnected."); logDebug("Billing service disconnected.");
@ -248,8 +245,8 @@ public class IabHelper {
int response = mService.isBillingSupported(3, packageName, ITEM_TYPE_INAPP); int response = mService.isBillingSupported(3, packageName, ITEM_TYPE_INAPP);
if (response != BILLING_RESPONSE_RESULT_OK) { if (response != BILLING_RESPONSE_RESULT_OK) {
if (listener != null) { if (listener != null) {
listener.onIabSetupFinished(new IabResult(response, listener.onIabSetupFinished(
"Error checking for billing v3 support.")); new IabResult(response, "Error checking for billing v3 support."));
} }
// if in-app purchases aren't supported, neither are subscriptions // if in-app purchases aren't supported, neither are subscriptions
@ -289,7 +286,9 @@ public class IabHelper {
mSetupDone = true; mSetupDone = true;
} catch (RemoteException e) { } catch (RemoteException e) {
if (listener != null) { if (listener != null) {
listener.onIabSetupFinished(new IabResult(IABHELPER_REMOTE_EXCEPTION, listener.onIabSetupFinished(
new IabResult(
IABHELPER_REMOTE_EXCEPTION,
"RemoteException while setting up in-app billing.")); "RemoteException while setting up in-app billing."));
} }
e.printStackTrace(); e.printStackTrace();
@ -297,16 +296,16 @@ public class IabHelper {
} }
if (listener != null) { if (listener != null) {
listener listener.onIabSetupFinished(
.onIabSetupFinished(new IabResult(BILLING_RESPONSE_RESULT_OK, "Setup successful.")); new IabResult(BILLING_RESPONSE_RESULT_OK, "Setup successful."));
} }
} }
}; };
Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND"); Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
serviceIntent.setPackage("com.android.vending"); serviceIntent.setPackage("com.android.vending");
List<ResolveInfo> intentServices = mContext.getPackageManager() List<ResolveInfo> intentServices =
.queryIntentServices(serviceIntent, 0); mContext.getPackageManager().queryIntentServices(serviceIntent, 0);
if (intentServices != null && !intentServices.isEmpty()) { if (intentServices != null && !intentServices.isEmpty()) {
// service available to handle that Intent // service available to handle that Intent
mContext.bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE); mContext.bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
@ -314,17 +313,17 @@ public class IabHelper {
// no service available to handle that Intent // no service available to handle that Intent
if (listener != null) { if (listener != null) {
listener.onIabSetupFinished( listener.onIabSetupFinished(
new IabResult(BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE, new IabResult(
BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE,
"Billing service unavailable on device.")); "Billing service unavailable on device."));
} }
} }
} }
/** /**
* Dispose of object, releasing resources. It's very important to call this * Dispose of object, releasing resources. It's very important to call this method when you are
* method when you are done with this object. It will release any resources * done with this object. It will release any resources used by it such as service connections.
* used by it such as service connections. Naturally, once the object is * Naturally, once the object is disposed of, it can't be used again.
* disposed of, it can't be used again.
*/ */
public void dispose() { public void dispose() {
logDebug("Disposing."); logDebug("Disposing.");
@ -348,41 +347,47 @@ public class IabHelper {
} }
} }
/** /** Returns whether subscriptions are supported. */
* Returns whether subscriptions are supported.
*/
public boolean subscriptionsSupported() { public boolean subscriptionsSupported() {
checkNotDisposed(); checkNotDisposed();
return mSubscriptionsSupported; return mSubscriptionsSupported;
} }
public void launchPurchaseFlow(Activity act, String sku, int requestCode, public void launchPurchaseFlow(
OnIabPurchaseFinishedListener listener) { Activity act, String sku, int requestCode, OnIabPurchaseFinishedListener listener) {
launchPurchaseFlow(act, sku, requestCode, listener, ""); launchPurchaseFlow(act, sku, requestCode, listener, "");
} }
public void launchPurchaseFlow(Activity act, String sku, int requestCode, public void launchPurchaseFlow(
OnIabPurchaseFinishedListener listener, String extraData) { Activity act,
String sku,
int requestCode,
OnIabPurchaseFinishedListener listener,
String extraData) {
launchPurchaseFlow(act, sku, ITEM_TYPE_INAPP, null, requestCode, listener, extraData); launchPurchaseFlow(act, sku, ITEM_TYPE_INAPP, null, requestCode, listener, extraData);
} }
public void launchSubscriptionPurchaseFlow(Activity act, String sku, int requestCode, public void launchSubscriptionPurchaseFlow(
OnIabPurchaseFinishedListener listener) { Activity act, String sku, int requestCode, OnIabPurchaseFinishedListener listener) {
launchSubscriptionPurchaseFlow(act, sku, requestCode, listener, ""); launchSubscriptionPurchaseFlow(act, sku, requestCode, listener, "");
} }
public void launchSubscriptionPurchaseFlow(Activity act, String sku, int requestCode, public void launchSubscriptionPurchaseFlow(
OnIabPurchaseFinishedListener listener, String extraData) { Activity act,
String sku,
int requestCode,
OnIabPurchaseFinishedListener listener,
String extraData) {
launchPurchaseFlow(act, sku, ITEM_TYPE_SUBS, null, requestCode, listener, extraData); launchPurchaseFlow(act, sku, ITEM_TYPE_SUBS, null, requestCode, listener, extraData);
} }
/** /**
* Initiate the UI flow for an in-app purchase. Call this method to initiate an in-app purchase, * Initiate the UI flow for an in-app purchase. Call this method to initiate an in-app purchase,
* which will involve bringing up the Google Play screen. The calling activity will be paused * which will involve bringing up the Google Play screen. The calling activity will be paused
* while the user interacts with Google Play, and the result will be delivered via the * while the user interacts with Google Play, and the result will be delivered via the activity's
* activity's {@link android.app.Activity#onActivityResult} method, at which point you must call * {@link android.app.Activity#onActivityResult} method, at which point you must call this
* this object's {@link #handleActivityResult} method to continue the purchase flow. This method * object's {@link #handleActivityResult} method to continue the purchase flow. This method MUST
* MUST be called from the UI thread of the Activity. * be called from the UI thread of the Activity.
* *
* @param act The calling activity. * @param act The calling activity.
* @param sku The sku of the item to purchase. * @param sku The sku of the item to purchase.
@ -396,16 +401,22 @@ public class IabHelper {
* when the purchase completes. This extra data will be permanently bound to that purchase and * when the purchase completes. This extra data will be permanently bound to that purchase and
* will always be returned when the purchase is queried. * will always be returned when the purchase is queried.
*/ */
public void launchPurchaseFlow(Activity act, String sku, String itemType, List<String> oldSkus, public void launchPurchaseFlow(
int requestCode, OnIabPurchaseFinishedListener listener, String extraData) { Activity act,
String sku,
String itemType,
List<String> oldSkus,
int requestCode,
OnIabPurchaseFinishedListener listener,
String extraData) {
checkNotDisposed(); checkNotDisposed();
checkSetupDone("launchPurchaseFlow"); checkSetupDone("launchPurchaseFlow");
flagStartAsync("launchPurchaseFlow"); flagStartAsync("launchPurchaseFlow");
IabResult result; IabResult result;
if (itemType.equals(ITEM_TYPE_SUBS) && !mSubscriptionsSupported) { if (itemType.equals(ITEM_TYPE_SUBS) && !mSubscriptionsSupported) {
IabResult r = new IabResult(IABHELPER_SUBSCRIPTIONS_NOT_AVAILABLE, IabResult r =
"Subscriptions are not available."); new IabResult(IABHELPER_SUBSCRIPTIONS_NOT_AVAILABLE, "Subscriptions are not available.");
flagEndAsync(); flagEndAsync();
if (listener != null) { if (listener != null) {
listener.onIabPurchaseFinished(r, null); listener.onIabPurchaseFinished(r, null);
@ -418,12 +429,14 @@ public class IabHelper {
Bundle buyIntentBundle; Bundle buyIntentBundle;
if (oldSkus == null || oldSkus.isEmpty()) { if (oldSkus == null || oldSkus.isEmpty()) {
// Purchasing a new item or subscription re-signup // Purchasing a new item or subscription re-signup
buyIntentBundle = mService.getBuyIntent(3, mContext.getPackageName(), sku, itemType, buyIntentBundle =
extraData); mService.getBuyIntent(3, mContext.getPackageName(), sku, itemType, extraData);
} else { } else {
// Subscription upgrade/downgrade // Subscription upgrade/downgrade
if (!mSubscriptionUpdateSupported) { if (!mSubscriptionUpdateSupported) {
IabResult r = new IabResult(IABHELPER_SUBSCRIPTION_UPDATE_NOT_AVAILABLE, IabResult r =
new IabResult(
IABHELPER_SUBSCRIPTION_UPDATE_NOT_AVAILABLE,
"Subscription updates are not available."); "Subscription updates are not available.");
flagEndAsync(); flagEndAsync();
if (listener != null) { if (listener != null) {
@ -431,8 +444,9 @@ public class IabHelper {
} }
return; return;
} }
buyIntentBundle = mService.getBuyIntentToReplaceSkus(5, mContext.getPackageName(), buyIntentBundle =
oldSkus, sku, itemType, extraData); mService.getBuyIntentToReplaceSkus(
5, mContext.getPackageName(), oldSkus, sku, itemType, extraData);
} }
int response = getResponseCodeFromBundle(buyIntentBundle); int response = getResponseCodeFromBundle(buyIntentBundle);
if (response != BILLING_RESPONSE_RESULT_OK) { if (response != BILLING_RESPONSE_RESULT_OK) {
@ -450,9 +464,12 @@ public class IabHelper {
mRequestCode = requestCode; mRequestCode = requestCode;
mPurchaseListener = listener; mPurchaseListener = listener;
mPurchasingItemType = itemType; mPurchasingItemType = itemType;
act.startIntentSenderForResult(pendingIntent.getIntentSender(), act.startIntentSenderForResult(
requestCode, new Intent(), pendingIntent.getIntentSender(),
Integer.valueOf(0), Integer.valueOf(0), requestCode,
new Intent(),
Integer.valueOf(0),
Integer.valueOf(0),
Integer.valueOf(0)); Integer.valueOf(0));
} catch (SendIntentException e) { } catch (SendIntentException e) {
logError("SendIntentException while launching purchase flow for sku " + sku); logError("SendIntentException while launching purchase flow for sku " + sku);
@ -468,8 +485,9 @@ public class IabHelper {
e.printStackTrace(); e.printStackTrace();
flagEndAsync(); flagEndAsync();
result = new IabResult(IABHELPER_REMOTE_EXCEPTION, result =
"Remote exception while starting purchase flow"); new IabResult(
IABHELPER_REMOTE_EXCEPTION, "Remote exception while starting purchase flow");
if (listener != null) { if (listener != null) {
listener.onIabPurchaseFinished(result, null); listener.onIabPurchaseFinished(result, null);
} }
@ -477,10 +495,10 @@ public class IabHelper {
} }
/** /**
* Handles an activity result that's part of the purchase flow in in-app billing. If you * Handles an activity result that's part of the purchase flow in in-app billing. If you are
* are calling {@link #launchPurchaseFlow}, then you must call this method from your * calling {@link #launchPurchaseFlow}, then you must call this method from your Activity's {@link
* Activity's {@link android.app.Activity@onActivityResult} method. This method * android.app.Activity@onActivityResult} method. This method MUST be called from the UI thread of
* MUST be called from the UI thread of the Activity. * the Activity.
* *
* @param requestCode The requestCode as you received it. * @param requestCode The requestCode as you received it.
* @param resultCode The resultCode as you received it. * @param resultCode The resultCode as you received it.
@ -523,8 +541,9 @@ public class IabHelper {
if (purchaseData == null || dataSignature == null) { if (purchaseData == null || dataSignature == null) {
logError("BUG: either purchaseData or dataSignature is null."); logError("BUG: either purchaseData or dataSignature is null.");
logDebug("Extras: " + data.getExtras().toString()); logDebug("Extras: " + data.getExtras().toString());
result = new IabResult(IABHELPER_UNKNOWN_ERROR, result =
"IAB returned null purchaseData or dataSignature"); new IabResult(
IABHELPER_UNKNOWN_ERROR, "IAB returned null purchaseData or dataSignature");
if (mPurchaseListener != null) { if (mPurchaseListener != null) {
mPurchaseListener.onIabPurchaseFinished(result, null); mPurchaseListener.onIabPurchaseFinished(result, null);
} }
@ -539,8 +558,9 @@ public class IabHelper {
// Verify signature // Verify signature
if (!Security.verifyPurchase(mSignatureBase64, purchaseData, dataSignature)) { if (!Security.verifyPurchase(mSignatureBase64, purchaseData, dataSignature)) {
logError("Purchase signature verification FAILED for sku " + sku); logError("Purchase signature verification FAILED for sku " + sku);
result = new IabResult(IABHELPER_VERIFICATION_FAILED, result =
"Signature verification failed for sku " + sku); new IabResult(
IABHELPER_VERIFICATION_FAILED, "Signature verification failed for sku " + sku);
if (mPurchaseListener != null) { if (mPurchaseListener != null) {
mPurchaseListener.onIabPurchaseFinished(result, purchase); mPurchaseListener.onIabPurchaseFinished(result, purchase);
} }
@ -558,13 +578,14 @@ public class IabHelper {
} }
if (mPurchaseListener != null) { if (mPurchaseListener != null) {
mPurchaseListener mPurchaseListener.onIabPurchaseFinished(
.onIabPurchaseFinished(new IabResult(BILLING_RESPONSE_RESULT_OK, "Success"), purchase); new IabResult(BILLING_RESPONSE_RESULT_OK, "Success"), purchase);
} }
} else if (resultCode == Activity.RESULT_OK) { } else if (resultCode == Activity.RESULT_OK) {
// result code was OK, but in-app billing response was not OK. // result code was OK, but in-app billing response was not OK.
logDebug("Result code was OK but in-app billing response was not OK: " + getResponseDesc( logDebug(
responseCode)); "Result code was OK but in-app billing response was not OK: "
+ getResponseDesc(responseCode));
if (mPurchaseListener != null) { if (mPurchaseListener != null) {
result = new IabResult(responseCode, "Problem purchashing item."); result = new IabResult(responseCode, "Problem purchashing item.");
mPurchaseListener.onIabPurchaseFinished(result, null); mPurchaseListener.onIabPurchaseFinished(result, null);
@ -576,8 +597,11 @@ public class IabHelper {
mPurchaseListener.onIabPurchaseFinished(result, null); mPurchaseListener.onIabPurchaseFinished(result, null);
} }
} else { } else {
logError("Purchase failed. Result code: " + Integer.toString(resultCode) logError(
+ ". Response: " + getResponseDesc(responseCode)); "Purchase failed. Result code: "
+ Integer.toString(resultCode)
+ ". Response: "
+ getResponseDesc(responseCode));
result = new IabResult(IABHELPER_UNKNOWN_PURCHASE_RESPONSE, "Unknown purchase response."); result = new IabResult(IABHELPER_UNKNOWN_PURCHASE_RESPONSE, "Unknown purchase response.");
if (mPurchaseListener != null) { if (mPurchaseListener != null) {
mPurchaseListener.onIabPurchaseFinished(result, null); mPurchaseListener.onIabPurchaseFinished(result, null);
@ -604,8 +628,9 @@ public class IabHelper {
* ownership. Ignored if null or if querySkuDetails is false. * ownership. Ignored if null or if querySkuDetails is false.
* @throws IabException if a problem occurs while refreshing the inventory. * @throws IabException if a problem occurs while refreshing the inventory.
*/ */
public Inventory queryInventory(boolean querySkuDetails, List<String> moreItemSkus, public Inventory queryInventory(
List<String> moreSubsSkus) throws IabException { boolean querySkuDetails, List<String> moreItemSkus, List<String> moreSubsSkus)
throws IabException {
checkNotDisposed(); checkNotDisposed();
checkSetupDone("queryInventory"); checkSetupDone("queryInventory");
try { try {
@ -632,40 +657,43 @@ public class IabHelper {
if (querySkuDetails) { if (querySkuDetails) {
r = querySkuDetails(ITEM_TYPE_SUBS, inv, moreSubsSkus); r = querySkuDetails(ITEM_TYPE_SUBS, inv, moreSubsSkus);
if (r != BILLING_RESPONSE_RESULT_OK) { if (r != BILLING_RESPONSE_RESULT_OK) {
throw new IabException(r, throw new IabException(
"Error refreshing inventory (querying prices of subscriptions)."); r, "Error refreshing inventory (querying prices of subscriptions).");
} }
} }
} }
return inv; return inv;
} catch (RemoteException e) { } catch (RemoteException e) {
throw new IabException(IABHELPER_REMOTE_EXCEPTION, throw new IabException(
"Remote exception while refreshing inventory.", e); IABHELPER_REMOTE_EXCEPTION, "Remote exception while refreshing inventory.", e);
} catch (JSONException e) { } catch (JSONException e) {
throw new IabException(IABHELPER_BAD_RESPONSE, throw new IabException(
"Error parsing JSON response while refreshing inventory.", e); IABHELPER_BAD_RESPONSE, "Error parsing JSON response while refreshing inventory.", e);
} }
} }
/** /**
* Asynchronous wrapper for inventory query. This will perform an inventory * Asynchronous wrapper for inventory query. This will perform an inventory query as described in
* query as described in {@link #queryInventory}, but will do so asynchronously * {@link #queryInventory}, but will do so asynchronously and call back the specified listener
* and call back the specified listener upon completion. This method is safe to * upon completion. This method is safe to call from a UI thread.
* call from a UI thread.
* *
* @param querySkuDetails as in {@link #queryInventory} * @param querySkuDetails as in {@link #queryInventory}
* @param moreSkus as in {@link #queryInventory} * @param moreSkus as in {@link #queryInventory}
* @param listener The listener to notify when the refresh operation completes. * @param listener The listener to notify when the refresh operation completes.
*/ */
public void queryInventoryAsync(final boolean querySkuDetails, final List<String> moreSkus, public void queryInventoryAsync(
final boolean querySkuDetails,
final List<String> moreSkus,
final QueryInventoryFinishedListener listener) { final QueryInventoryFinishedListener listener) {
final Handler handler = new Handler(); final Handler handler = new Handler();
checkNotDisposed(); checkNotDisposed();
checkSetupDone("queryInventory"); checkSetupDone("queryInventory");
flagStartAsync("refresh inventory"); flagStartAsync("refresh inventory");
executor.execute(() -> { executor.execute(
IabResult result = new IabResult(BILLING_RESPONSE_RESULT_OK, "Inventory refresh successful."); () -> {
IabResult result =
new IabResult(BILLING_RESPONSE_RESULT_OK, "Inventory refresh successful.");
Inventory inv = null; Inventory inv = null;
try { try {
inv = queryInventory(querySkuDetails, moreSkus); inv = queryInventory(querySkuDetails, moreSkus);
@ -687,16 +715,15 @@ public class IabHelper {
queryInventoryAsync(true, null, listener); queryInventoryAsync(true, null, listener);
} }
public void queryInventoryAsync(boolean querySkuDetails, public void queryInventoryAsync(
QueryInventoryFinishedListener listener) { boolean querySkuDetails, QueryInventoryFinishedListener listener) {
queryInventoryAsync(querySkuDetails, null, listener); queryInventoryAsync(querySkuDetails, null, listener);
} }
/** /**
* Consumes a given in-app product. Consuming can only be done on an item * Consumes a given in-app product. Consuming can only be done on an item that's owned, and as a
* that's owned, and as a result of consumption, the user will no longer own it. * result of consumption, the user will no longer own it. This method may block or take long to
* This method may block or take long to return. Do not call from the UI thread. * return. Do not call from the UI thread. For that, see {@link #consumeAsync}.
* For that, see {@link #consumeAsync}.
* *
* @param itemInfo The PurchaseInfo that represents the item to consume. * @param itemInfo The PurchaseInfo that represents the item to consume.
* @throws IabException if there is a problem during consumption. * @throws IabException if there is a problem during consumption.
@ -706,7 +733,8 @@ public class IabHelper {
checkSetupDone("consume"); checkSetupDone("consume");
if (!itemInfo.mItemType.equals(ITEM_TYPE_INAPP)) { if (!itemInfo.mItemType.equals(ITEM_TYPE_INAPP)) {
throw new IabException(IABHELPER_INVALID_CONSUMPTION, throw new IabException(
IABHELPER_INVALID_CONSUMPTION,
"Items of type '" + itemInfo.mItemType + "' can't be consumed."); "Items of type '" + itemInfo.mItemType + "' can't be consumed.");
} }
@ -715,8 +743,9 @@ public class IabHelper {
String sku = itemInfo.getSku(); String sku = itemInfo.getSku();
if (token == null || token.equals("")) { if (token == null || token.equals("")) {
logError("Can't consume " + sku + ". No token."); logError("Can't consume " + sku + ". No token.");
throw new IabException(IABHELPER_MISSING_TOKEN, "PurchaseInfo is missing token for sku: " throw new IabException(
+ sku + " " + itemInfo); IABHELPER_MISSING_TOKEN,
"PurchaseInfo is missing token for sku: " + sku + " " + itemInfo);
} }
logDebug("Consuming sku: " + sku + ", token: " + token); logDebug("Consuming sku: " + sku + ", token: " + token);
@ -728,15 +757,17 @@ public class IabHelper {
throw new IabException(response, "Error consuming sku " + sku); throw new IabException(response, "Error consuming sku " + sku);
} }
} catch (RemoteException e) { } catch (RemoteException e) {
throw new IabException(IABHELPER_REMOTE_EXCEPTION, throw new IabException(
"Remote exception while consuming. PurchaseInfo: " + itemInfo, e); IABHELPER_REMOTE_EXCEPTION,
"Remote exception while consuming. PurchaseInfo: " + itemInfo,
e);
} }
} }
/** /**
* Asynchronous wrapper to item consumption. Works like {@link #consume}, but * Asynchronous wrapper to item consumption. Works like {@link #consume}, but performs the
* performs the consumption in the background and notifies completion through * consumption in the background and notifies completion through the provided listener. This
* the provided listener. This method is safe to call from a UI thread. * method is safe to call from a UI thread.
* *
* @param purchase The purchase to be consumed. * @param purchase The purchase to be consumed.
* @param listener The listener to notify when the consumption operation finishes. * @param listener The listener to notify when the consumption operation finishes.
@ -808,8 +839,12 @@ public class IabHelper {
void flagStartAsync(String operation) { void flagStartAsync(String operation) {
if (mAsyncInProgress) { if (mAsyncInProgress) {
throw new IllegalStateException("Can't start async operation (" + throw new IllegalStateException(
operation + ") because another async operation(" + mAsyncOperation + ") is in progress."); "Can't start async operation ("
+ operation
+ ") because another async operation("
+ mAsyncOperation
+ ") is in progress.");
} }
mAsyncOperation = operation; mAsyncOperation = operation;
mAsyncInProgress = true; mAsyncInProgress = true;
@ -831,8 +866,8 @@ public class IabHelper {
do { do {
logDebug("Calling getPurchases with continuation token: " + continueToken); logDebug("Calling getPurchases with continuation token: " + continueToken);
Bundle ownedItems = mService.getPurchases(3, mContext.getPackageName(), Bundle ownedItems =
itemType, continueToken); mService.getPurchases(3, mContext.getPackageName(), itemType, continueToken);
int response = getResponseCodeFromBundle(ownedItems); int response = getResponseCodeFromBundle(ownedItems);
logDebug("Owned items response: " + String.valueOf(response)); logDebug("Owned items response: " + String.valueOf(response));
@ -847,12 +882,11 @@ public class IabHelper {
return IABHELPER_BAD_RESPONSE; return IABHELPER_BAD_RESPONSE;
} }
ArrayList<String> ownedSkus = ownedItems.getStringArrayList( ArrayList<String> ownedSkus = ownedItems.getStringArrayList(RESPONSE_INAPP_ITEM_LIST);
RESPONSE_INAPP_ITEM_LIST); ArrayList<String> purchaseDataList =
ArrayList<String> purchaseDataList = ownedItems.getStringArrayList( ownedItems.getStringArrayList(RESPONSE_INAPP_PURCHASE_DATA_LIST);
RESPONSE_INAPP_PURCHASE_DATA_LIST); ArrayList<String> signatureList =
ArrayList<String> signatureList = ownedItems.getStringArrayList( ownedItems.getStringArrayList(RESPONSE_INAPP_SIGNATURE_LIST);
RESPONSE_INAPP_SIGNATURE_LIST);
for (int i = 0; i < purchaseDataList.size(); ++i) { for (int i = 0; i < purchaseDataList.size(); ++i) {
String purchaseData = purchaseDataList.get(i); String purchaseData = purchaseDataList.get(i);
@ -925,8 +959,7 @@ public class IabHelper {
for (ArrayList<String> skuPartList : packs) { for (ArrayList<String> skuPartList : packs) {
Bundle querySkus = new Bundle(); Bundle querySkus = new Bundle();
querySkus.putStringArrayList(GET_SKU_DETAILS_ITEM_LIST, skuPartList); querySkus.putStringArrayList(GET_SKU_DETAILS_ITEM_LIST, skuPartList);
Bundle skuDetails = mService.getSkuDetails(3, mContext.getPackageName(), Bundle skuDetails = mService.getSkuDetails(3, mContext.getPackageName(), itemType, querySkus);
itemType, querySkus);
if (!skuDetails.containsKey(RESPONSE_GET_SKU_DETAILS_LIST)) { if (!skuDetails.containsKey(RESPONSE_GET_SKU_DETAILS_LIST)) {
int response = getResponseCodeFromBundle(skuDetails); int response = getResponseCodeFromBundle(skuDetails);
@ -939,8 +972,7 @@ public class IabHelper {
} }
} }
ArrayList<String> responseList = skuDetails.getStringArrayList( ArrayList<String> responseList = skuDetails.getStringArrayList(RESPONSE_GET_SKU_DETAILS_LIST);
RESPONSE_GET_SKU_DETAILS_LIST);
for (String thisResponse : responseList) { for (String thisResponse : responseList) {
SkuDetails d = new SkuDetails(itemType, thisResponse); SkuDetails d = new SkuDetails(itemType, thisResponse);
@ -952,17 +984,21 @@ public class IabHelper {
return BILLING_RESPONSE_RESULT_OK; return BILLING_RESPONSE_RESULT_OK;
} }
void consumeAsyncInternal(final List<Purchase> purchases, void consumeAsyncInternal(
final List<Purchase> purchases,
final OnConsumeFinishedListener singleListener, final OnConsumeFinishedListener singleListener,
final OnConsumeMultiFinishedListener multiListener) { final OnConsumeMultiFinishedListener multiListener) {
final Handler handler = new Handler(); final Handler handler = new Handler();
flagStartAsync("consume"); flagStartAsync("consume");
executor.execute(() -> { executor.execute(
() -> {
final List<IabResult> results = new ArrayList<IabResult>(); final List<IabResult> results = new ArrayList<IabResult>();
for (Purchase purchase : purchases) { for (Purchase purchase : purchases) {
try { try {
consume(purchase); consume(purchase);
results.add(new IabResult(BILLING_RESPONSE_RESULT_OK, results.add(
new IabResult(
BILLING_RESPONSE_RESULT_OK,
"Successful consume of sku " + purchase.getSku())); "Successful consume of sku " + purchase.getSku()));
} catch (IabException ex) { } catch (IabException ex) {
results.add(ex.getResult()); results.add(ex.getResult());
@ -994,8 +1030,8 @@ public class IabHelper {
} }
/** /**
* Callback for setup process. This listener's {@link #onIabSetupFinished} method is called * Callback for setup process. This listener's {@link #onIabSetupFinished} method is called when
* when the setup process is complete. * the setup process is complete.
*/ */
public interface OnIabSetupFinishedListener { public interface OnIabSetupFinishedListener {
@ -1007,16 +1043,13 @@ public class IabHelper {
void onIabSetupFinished(IabResult result); void onIabSetupFinished(IabResult result);
} }
/** /** Callback that notifies when a purchase is finished. */
* Callback that notifies when a purchase is finished.
*/
public interface OnIabPurchaseFinishedListener { public interface OnIabPurchaseFinishedListener {
/** /**
* Called to notify that an in-app purchase finished. If the purchase was successful, * Called to notify that an in-app purchase finished. If the purchase was successful, then the
* then the sku parameter specifies which item was purchased. If the purchase failed, * sku parameter specifies which item was purchased. If the purchase failed, the sku and
* the sku and extraData parameters may or may not be null, depending on how far the purchase * extraData parameters may or may not be null, depending on how far the purchase process went.
* process went.
* *
* @param result The result of the purchase. * @param result The result of the purchase.
* @param info The purchase information (null if purchase failed) * @param info The purchase information (null if purchase failed)
@ -1024,9 +1057,7 @@ public class IabHelper {
void onIabPurchaseFinished(IabResult result, Purchase info); void onIabPurchaseFinished(IabResult result, Purchase info);
} }
/** /** Listener that notifies when an inventory query operation completes. */
* Listener that notifies when an inventory query operation completes.
*/
public interface QueryInventoryFinishedListener { public interface QueryInventoryFinishedListener {
/** /**
@ -1038,9 +1069,7 @@ public class IabHelper {
void onQueryInventoryFinished(IabResult result, Inventory inv); void onQueryInventoryFinished(IabResult result, Inventory inv);
} }
/** /** Callback that notifies when a consumption operation finishes. */
* Callback that notifies when a consumption operation finishes.
*/
public interface OnConsumeFinishedListener { public interface OnConsumeFinishedListener {
/** /**
@ -1052,9 +1081,7 @@ public class IabHelper {
void onConsumeFinished(Purchase purchase, IabResult result); void onConsumeFinished(Purchase purchase, IabResult result);
} }
/** /** Callback that notifies when a multi-item consumption operation finishes. */
* Callback that notifies when a multi-item consumption operation finishes.
*/
public interface OnConsumeMultiFinishedListener { public interface OnConsumeMultiFinishedListener {
/** /**

@ -16,12 +16,10 @@
package com.android.vending.billing; package com.android.vending.billing;
/** /**
* Represents the result of an in-app billing operation. * Represents the result of an in-app billing operation. A result is composed of a response code (an
* A result is composed of a response code (an integer) and possibly a * integer) and possibly a message (String). You can get those by calling {@link #getResponse} and
* message (String). You can get those by calling * {@link #getMessage()}, respectively. You can also inquire whether a result is a success or a
* {@link #getResponse} and {@link #getMessage()}, respectively. You * failure by calling {@link #isSuccess()} and {@link #isFailure()}.
* can also inquire whether a result is a success or a failure by
* calling {@link #isSuccess()} and {@link #isFailure()}.
*/ */
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
public class IabResult { public class IabResult {
@ -58,4 +56,3 @@ public class IabResult {
return "IabResult: " + getMessage(); return "IabResult: " + getMessage();
} }
} }

@ -21,8 +21,8 @@ import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
* Represents a block of information about in-app items. * Represents a block of information about in-app items. An Inventory is returned by such methods as
* An Inventory is returned by such methods as {@link IabHelper#queryInventory}. * {@link IabHelper#queryInventory}.
*/ */
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
public class Inventory { public class Inventory {
@ -30,44 +30,34 @@ public class Inventory {
Map<String, SkuDetails> mSkuMap = new HashMap<String, SkuDetails>(); Map<String, SkuDetails> mSkuMap = new HashMap<String, SkuDetails>();
Map<String, Purchase> mPurchaseMap = new HashMap<String, Purchase>(); Map<String, Purchase> mPurchaseMap = new HashMap<String, Purchase>();
Inventory() { Inventory() {}
}
/** /** Returns the listing details for an in-app product. */
* Returns the listing details for an in-app product.
*/
public SkuDetails getSkuDetails(String sku) { public SkuDetails getSkuDetails(String sku) {
return mSkuMap.get(sku); return mSkuMap.get(sku);
} }
/** /** Returns purchase information for a given product, or null if there is no purchase. */
* Returns purchase information for a given product, or null if there is no purchase.
*/
public Purchase getPurchase(String sku) { public Purchase getPurchase(String sku) {
return mPurchaseMap.get(sku); return mPurchaseMap.get(sku);
} }
/** /** Returns whether or not there exists a purchase of the given product. */
* Returns whether or not there exists a purchase of the given product.
*/
public boolean hasPurchase(String sku) { public boolean hasPurchase(String sku) {
return mPurchaseMap.containsKey(sku); return mPurchaseMap.containsKey(sku);
} }
/** /** Return whether or not details about the given product are available. */
* Return whether or not details about the given product are available.
*/
public boolean hasDetails(String sku) { public boolean hasDetails(String sku) {
return mSkuMap.containsKey(sku); return mSkuMap.containsKey(sku);
} }
/** /**
* Erase a purchase (locally) from the inventory, given its product ID. This just * Erase a purchase (locally) from the inventory, given its product ID. This just modifies the
* modifies the Inventory object locally and has no effect on the server! This is * Inventory object locally and has no effect on the server! This is useful when you have an
* useful when you have an existing Inventory object which you know to be up to date, * existing Inventory object which you know to be up to date, and you have just consumed an item
* and you have just consumed an item successfully, which means that erasing its * successfully, which means that erasing its purchase data from the Inventory you already have is
* purchase data from the Inventory you already have is quicker than querying for * quicker than querying for a new Inventory.
* a new Inventory.
*/ */
public void erasePurchase(String sku) { public void erasePurchase(String sku) {
if (mPurchaseMap.containsKey(sku)) { if (mPurchaseMap.containsKey(sku)) {
@ -75,16 +65,12 @@ public class Inventory {
} }
} }
/** /** Returns a list of all owned product IDs. */
* Returns a list of all owned product IDs.
*/
List<String> getAllOwnedSkus() { List<String> getAllOwnedSkus() {
return new ArrayList<String>(mPurchaseMap.keySet()); return new ArrayList<String>(mPurchaseMap.keySet());
} }
/** /** Returns a list of all owned product IDs of a given type */
* Returns a list of all owned product IDs of a given type
*/
List<String> getAllOwnedSkus(String itemType) { List<String> getAllOwnedSkus(String itemType) {
List<String> result = new ArrayList<String>(); List<String> result = new ArrayList<String>();
for (Purchase p : mPurchaseMap.values()) { for (Purchase p : mPurchaseMap.values()) {
@ -95,9 +81,7 @@ public class Inventory {
return result; return result;
} }
/** /** Returns a list of all purchases. */
* Returns a list of all purchases.
*/
List<Purchase> getAllPurchases() { List<Purchase> getAllPurchases() {
return new ArrayList<Purchase>(mPurchaseMap.values()); return new ArrayList<Purchase>(mPurchaseMap.values());
} }

@ -18,9 +18,7 @@ package com.android.vending.billing;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
/** /** Represents an in-app billing purchase. */
* Represents an in-app billing purchase.
*/
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
public class Purchase { public class Purchase {

@ -29,13 +29,11 @@ import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec; import java.security.spec.X509EncodedKeySpec;
/** /**
* Security-related methods. For a secure implementation, all of this code * Security-related methods. For a secure implementation, all of this code should be implemented on
* should be implemented on a server that communicates with the * a server that communicates with the application on the device. For the sake of simplicity and
* application on the device. For the sake of simplicity and clarity of this * clarity of this example, this code is included here and is executed on the device. If you must
* example, this code is included here and is executed on the device. If you * verify the purchases on the phone, you should obfuscate this code to make it harder for an
* must verify the purchases on the phone, you should obfuscate this code to * attacker to replace the code with stubs that treat all purchases as verified.
* make it harder for an attacker to replace the code with stubs that treat all
* purchases as verified.
*/ */
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
@SuppressLint("all") @SuppressLint("all")
@ -47,19 +45,19 @@ public class Security {
private static final String SIGNATURE_ALGORITHM = "SHA1withRSA"; private static final String SIGNATURE_ALGORITHM = "SHA1withRSA";
/** /**
* Verifies that the data was signed with the given signature, and returns * Verifies that the data was signed with the given signature, and returns the verified purchase.
* the verified purchase. The data is in JSON format and signed * The data is in JSON format and signed with a private key. The data also contains the {@link
* with a private key. The data also contains the {@link PurchaseState} * PurchaseState} and product ID of the purchase.
* and product ID of the purchase.
* *
* @param base64PublicKey the base64-encoded public key to use for verifying. * @param base64PublicKey the base64-encoded public key to use for verifying.
* @param signedData the signed JSON string (signed, not encrypted) * @param signedData the signed JSON string (signed, not encrypted)
* @param signature the signature for the data, signed with the private key * @param signature the signature for the data, signed with the private key
*/ */
public static boolean verifyPurchase(String base64PublicKey, String signedData, public static boolean verifyPurchase(
String signature) { String base64PublicKey, String signedData, String signature) {
if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey) || if (TextUtils.isEmpty(signedData)
TextUtils.isEmpty(signature)) { || TextUtils.isEmpty(base64PublicKey)
|| TextUtils.isEmpty(signature)) {
Log.e(TAG, "Purchase verification failed: missing data."); Log.e(TAG, "Purchase verification failed: missing data.");
return false; return false;
} }
@ -69,8 +67,7 @@ public class Security {
} }
/** /**
* Generates a PublicKey instance from a string containing the * Generates a PublicKey instance from a string containing the Base64-encoded public key.
* Base64-encoded public key.
* *
* @param encodedPublicKey Base64-encoded public key * @param encodedPublicKey Base64-encoded public key
* @throws IllegalArgumentException if encodedPublicKey is invalid * @throws IllegalArgumentException if encodedPublicKey is invalid
@ -89,8 +86,8 @@ public class Security {
} }
/** /**
* Verifies that the signature from the server matches the computed * Verifies that the signature from the server matches the computed signature on the data. Returns
* signature on the data. Returns true if the data is correctly signed. * true if the data is correctly signed.
* *
* @param publicKey public key associated with the developer account * @param publicKey public key associated with the developer account
* @param signedData signed data from server * @param signedData signed data from server

@ -18,9 +18,7 @@ package com.android.vending.billing;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
/** /** Represents an in-app product's listing details. */
* Represents an in-app product's listing details.
*/
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
public class SkuDetails { public class SkuDetails {

@ -29,24 +29,23 @@ public class Tracker {
analytics = GoogleAnalytics.getInstance(context); analytics = GoogleAnalytics.getInstance(context);
tracker = analytics.newTracker(R.xml.google_analytics); tracker = analytics.newTracker(R.xml.google_analytics);
tracker.setAppVersion(Integer.toString(BuildConfig.VERSION_CODE)); tracker.setAppVersion(Integer.toString(BuildConfig.VERSION_CODE));
final StandardExceptionParser standardExceptionParser = new StandardExceptionParser(context, final StandardExceptionParser standardExceptionParser =
null); new StandardExceptionParser(context, null);
exceptionParser = (thread, throwable) -> { exceptionParser =
StringBuilder stack = new StringBuilder() (thread, throwable) -> {
StringBuilder stack =
new StringBuilder()
.append(standardExceptionParser.getDescription(thread, throwable)) .append(standardExceptionParser.getDescription(thread, throwable))
.append("\n") .append("\n")
.append(throwable.getClass().getName()) .append(throwable.getClass().getName())
.append("\n"); .append("\n");
for (StackTraceElement element : throwable.getStackTrace()) { for (StackTraceElement element : throwable.getStackTrace()) {
stack.append(element.toString()) stack.append(element.toString()).append("\n");
.append("\n");
} }
return stack.toString(); return stack.toString();
}; };
ExceptionReporter reporter = new ExceptionReporter( ExceptionReporter reporter =
tracker, new ExceptionReporter(tracker, Thread.getDefaultUncaughtExceptionHandler(), context);
Thread.getDefaultUncaughtExceptionHandler(),
context);
reporter.setExceptionParser(exceptionParser); reporter.setExceptionParser(exceptionParser);
Thread.setDefaultUncaughtExceptionHandler(reporter); Thread.setDefaultUncaughtExceptionHandler(reporter);
} }
@ -61,7 +60,8 @@ public class Tracker {
public void reportException(Thread thread, Throwable t) { public void reportException(Thread thread, Throwable t) {
Timber.e(t, t.getMessage()); Timber.e(t, t.getMessage());
tracker.send(new HitBuilders.ExceptionBuilder() tracker.send(
new HitBuilders.ExceptionBuilder()
.setDescription(exceptionParser.getDescription(thread.getName(), t)) .setDescription(exceptionParser.getDescription(thread.getName(), t))
.setFatal(false) .setFatal(false)
.build()); .build());
@ -84,9 +84,8 @@ public class Tracker {
} }
private void reportEvent(int category, String action, String label) { private void reportEvent(int category, String action, String label) {
HitBuilders.EventBuilder eventBuilder = new HitBuilders.EventBuilder() HitBuilders.EventBuilder eventBuilder =
.setCategory(context.getString(category)) new HitBuilders.EventBuilder().setCategory(context.getString(category)).setAction(action);
.setAction(action);
if (!Strings.isNullOrEmpty(label)) { if (!Strings.isNullOrEmpty(label)) {
eventBuilder.setLabel(label); eventBuilder.setLabel(label);
} }
@ -94,7 +93,8 @@ public class Tracker {
} }
public void reportIabResult(IabResult result, String sku) { public void reportIabResult(IabResult result, String sku) {
tracker.send(new HitBuilders.EventBuilder() tracker.send(
new HitBuilders.EventBuilder()
.setCategory(context.getString(R.string.tracking_category_iab)) .setCategory(context.getString(R.string.tracking_category_iab))
.setAction(sku) .setAction(sku)
.setLabel(result.getMessage()) .setLabel(result.getMessage())

@ -27,8 +27,11 @@ public class InventoryHelper implements IabBroadcastReceiver.IabBroadcastListene
private Inventory inventory; private Inventory inventory;
@Inject @Inject
public InventoryHelper(@ForApplication Context context, Preferences preferences, public InventoryHelper(
LocalBroadcastManager localBroadcastManager, @Named("iab-executor") Executor executor) { @ForApplication Context context,
Preferences preferences,
LocalBroadcastManager localBroadcastManager,
@Named("iab-executor") Executor executor) {
this.context = context; this.context = context;
this.preferences = preferences; this.preferences = preferences;
this.localBroadcastManager = localBroadcastManager; this.localBroadcastManager = localBroadcastManager;
@ -36,8 +39,8 @@ public class InventoryHelper implements IabBroadcastReceiver.IabBroadcastListene
} }
public void initialize() { public void initialize() {
context.registerReceiver(new IabBroadcastReceiver(this), context.registerReceiver(
new IntentFilter(IabBroadcastReceiver.ACTION)); new IabBroadcastReceiver(this), new IntentFilter(IabBroadcastReceiver.ACTION));
refreshInventory(); refreshInventory();
} }

@ -36,8 +36,12 @@ public class PurchaseHelper implements IabHelper.OnIabSetupFinishedListener {
private IabHelper iabHelper; private IabHelper iabHelper;
@Inject @Inject
public PurchaseHelper(@ForApplication Context context, Preferences preferences, Tracker tracker, public PurchaseHelper(
InventoryHelper inventory, @Named("iab-executor") Executor executor, @ForApplication Context context,
Preferences preferences,
Tracker tracker,
InventoryHelper inventory,
@Named("iab-executor") Executor executor,
LocalBroadcastManager localBroadcastManager) { LocalBroadcastManager localBroadcastManager) {
this.context = context; this.context = context;
this.preferences = preferences; this.preferences = preferences;
@ -54,8 +58,12 @@ public class PurchaseHelper implements IabHelper.OnIabSetupFinishedListener {
} }
} }
public boolean purchase(final Activity activity, final String sku, final String pref, public boolean purchase(
final int requestCode, final PurchaseHelperCallback callback) { final Activity activity,
final String sku,
final String pref,
final int requestCode,
final PurchaseHelperCallback callback) {
launchPurchaseFlow(activity, sku, pref, requestCode, callback); launchPurchaseFlow(activity, sku, pref, requestCode, callback);
return true; return true;
} }
@ -75,12 +83,15 @@ public class PurchaseHelper implements IabHelper.OnIabSetupFinishedListener {
if (themes != null) { if (themes != null) {
purchases.add(themes); purchases.add(themes);
} }
final IabHelper iabHelper = new IabHelper(context, context.getString(R.string.gp_key), final IabHelper iabHelper =
executor); new IabHelper(context, context.getString(R.string.gp_key), executor);
iabHelper.enableDebugLogging(true); iabHelper.enableDebugLogging(true);
iabHelper.startSetup(result -> { iabHelper.startSetup(
result -> {
if (result.isSuccess()) { if (result.isSuccess()) {
iabHelper.consumeAsync(purchases, (purchases1, results) -> { iabHelper.consumeAsync(
purchases,
(purchases1, results) -> {
for (int i = 0; i < purchases1.size(); i++) { for (int i = 0; i < purchases1.size(); i++) {
Purchase purchase = purchases1.get(i); Purchase purchase = purchases1.get(i);
IabResult iabResult = results.get(i); IabResult iabResult = results.get(i);
@ -110,8 +121,12 @@ public class PurchaseHelper implements IabHelper.OnIabSetupFinishedListener {
} }
} }
private void launchPurchaseFlow(final Activity activity, final String sku, final String pref, private void launchPurchaseFlow(
final int requestCode, final PurchaseHelperCallback callback) { final Activity activity,
final String sku,
final String pref,
final int requestCode,
final PurchaseHelperCallback callback) {
if (iabHelper != null) { if (iabHelper != null) {
Toast.makeText(activity, R.string.billing_service_busy, Toast.LENGTH_LONG).show(); Toast.makeText(activity, R.string.billing_service_busy, Toast.LENGTH_LONG).show();
callback.purchaseCompleted(false, sku); callback.purchaseCompleted(false, sku);
@ -120,11 +135,16 @@ public class PurchaseHelper implements IabHelper.OnIabSetupFinishedListener {
iabHelper = new IabHelper(context, context.getString(R.string.gp_key), executor); iabHelper = new IabHelper(context, context.getString(R.string.gp_key), executor);
iabHelper.enableDebugLogging(BuildConfig.DEBUG); iabHelper.enableDebugLogging(BuildConfig.DEBUG);
Timber.d("%s: startSetup", iabHelper); Timber.d("%s: startSetup", iabHelper);
iabHelper.startSetup(result -> { iabHelper.startSetup(
result -> {
if (result.isSuccess()) { if (result.isSuccess()) {
try { try {
Timber.d("%s: launchPurchaseFlow for %s", iabHelper, sku); Timber.d("%s: launchPurchaseFlow for %s", iabHelper, sku);
iabHelper.launchPurchaseFlow(activity, sku, requestCode, (result1, info) -> { iabHelper.launchPurchaseFlow(
activity,
sku,
requestCode,
(result1, info) -> {
Timber.d(result1.toString()); Timber.d(result1.toString());
tracker.reportIabResult(result1, sku); tracker.reportIabResult(result1, sku);
if (result1.isSuccess()) { if (result1.isSuccess()) {
@ -133,8 +153,9 @@ public class PurchaseHelper implements IabHelper.OnIabSetupFinishedListener {
localBroadcastManager.broadcastRefresh(); localBroadcastManager.broadcastRefresh();
} }
inventory.refreshInventory(); inventory.refreshInventory();
} else if (result1.getResponse() != IabHelper.BILLING_RESPONSE_RESULT_USER_CANCELED && } else if (result1.getResponse()
result1.getResponse() != IabHelper.IABHELPER_USER_CANCELLED) { != IabHelper.BILLING_RESPONSE_RESULT_USER_CANCELED
&& result1.getResponse() != IabHelper.IABHELPER_USER_CANCELLED) {
Toast.makeText(activity, result1.getMessage(), Toast.LENGTH_LONG).show(); Toast.makeText(activity, result1.getMessage(), Toast.LENGTH_LONG).show();
} }
if (activityResultCallback != null) { if (activityResultCallback != null) {
@ -165,8 +186,8 @@ public class PurchaseHelper implements IabHelper.OnIabSetupFinishedListener {
} }
} }
public void handleActivityResult(PurchaseHelperCallback callback, int requestCode, int resultCode, public void handleActivityResult(
Intent data) { PurchaseHelperCallback callback, int requestCode, int resultCode, Intent data) {
this.activityResultCallback = callback; this.activityResultCallback = callback;
if (iabHelper != null) { if (iabHelper != null) {

@ -28,7 +28,9 @@ public class PlayServices {
private final GoogleAccountManager accountManager; private final GoogleAccountManager accountManager;
@Inject @Inject
public PlayServices(@ForApplication Context context, Preferences preferences, public PlayServices(
@ForApplication Context context,
Preferences preferences,
GoogleAccountManager googleAccountManager) { GoogleAccountManager googleAccountManager) {
this.context = context; this.context = context;
this.preferences = preferences; this.preferences = preferences;
@ -60,8 +62,9 @@ public class PlayServices {
if (googleApiAvailability.isUserResolvableError(error)) { if (googleApiAvailability.isUserResolvableError(error)) {
googleApiAvailability.getErrorDialog(activity, error, REQUEST_RESOLUTION).show(); googleApiAvailability.getErrorDialog(activity, error, REQUEST_RESOLUTION).show();
} else { } else {
Toast.makeText(activity, R.string.common_google_play_services_notification_ticker, Toast.makeText(
Toast.LENGTH_LONG).show(); activity, R.string.common_google_play_services_notification_ticker, Toast.LENGTH_LONG)
.show();
} }
} }
@ -78,8 +81,8 @@ public class PlayServices {
String token = credential.getToken(); String token = credential.getToken();
Timber.d("Invalidating %s", token); Timber.d("Invalidating %s", token);
GoogleAuthUtil.clearToken(context, token); GoogleAuthUtil.clearToken(context, token);
GoogleAuthUtil GoogleAuthUtil.getToken(
.getToken(context, credential.getSelectedAccount(), "oauth2:" + TasksScopes.TASKS, null); context, credential.getSelectedAccount(), "oauth2:" + TasksScopes.TASKS, null);
return true; return true;
} catch (GoogleAuthException e) { } catch (GoogleAuthException e) {
Timber.e(e, e.getMessage()); Timber.e(e, e.getMessage());
@ -90,25 +93,30 @@ public class PlayServices {
} }
} }
public void getAuthToken(final Activity activity, final String accountName, public void getAuthToken(
final Activity activity,
final String accountName,
final GtasksLoginActivity.AuthResultHandler handler) { final GtasksLoginActivity.AuthResultHandler handler) {
final Account account = accountManager.getAccount(accountName); final Account account = accountManager.getAccount(accountName);
if (account == null) { if (account == null) {
handler.authenticationFailed( handler.authenticationFailed(
activity.getString(R.string.gtasks_error_accountNotFound, accountName)); activity.getString(R.string.gtasks_error_accountNotFound, accountName));
} else { } else {
new Thread(() -> { new Thread(
() -> {
try { try {
GoogleAuthUtil.getToken(activity, account, "oauth2:" + TasksScopes.TASKS, null); GoogleAuthUtil.getToken(activity, account, "oauth2:" + TasksScopes.TASKS, null);
handler.authenticationSuccessful(accountName); handler.authenticationSuccessful(accountName);
} catch (UserRecoverableAuthException e) { } catch (UserRecoverableAuthException e) {
Timber.e(e, e.getMessage()); Timber.e(e, e.getMessage());
activity.startActivityForResult(e.getIntent(), GtasksLoginActivity.RC_REQUEST_OAUTH); activity.startActivityForResult(
e.getIntent(), GtasksLoginActivity.RC_REQUEST_OAUTH);
} catch (GoogleAuthException | IOException e) { } catch (GoogleAuthException | IOException e) {
Timber.e(e, e.getMessage()); Timber.e(e, e.getMessage());
handler.authenticationFailed(activity.getString(R.string.gtasks_GLA_errorIOAuth)); handler.authenticationFailed(activity.getString(R.string.gtasks_GLA_errorIOAuth));
} }
}).start(); })
.start();
} }
} }
} }

@ -31,7 +31,9 @@ public class GeofenceApi {
private final PermissionChecker permissionChecker; private final PermissionChecker permissionChecker;
@Inject @Inject
public GeofenceApi(@ForApplication Context context, Preferences preferences, public GeofenceApi(
@ForApplication Context context,
Preferences preferences,
PermissionChecker permissionChecker) { PermissionChecker permissionChecker) {
this.context = context; this.context = context;
this.preferences = preferences; this.preferences = preferences;
@ -43,16 +45,21 @@ public class GeofenceApi {
return; return;
} }
newClient(client -> { newClient(
client -> {
@SuppressWarnings("ResourceType") @SuppressWarnings("ResourceType")
@SuppressLint("MissingPermission") @SuppressLint("MissingPermission")
PendingResult<Status> result = LocationServices.GeofencingApi.addGeofences( PendingResult<Status> result =
LocationServices.GeofencingApi.addGeofences(
client, client,
getRequests(locations), getRequests(locations),
PendingIntent.getBroadcast(context, 0, PendingIntent.getBroadcast(
context,
0,
new Intent(context, GeofenceTransitionsIntentService.Broadcast.class), new Intent(context, GeofenceTransitionsIntentService.Broadcast.class),
PendingIntent.FLAG_UPDATE_CURRENT)); PendingIntent.FLAG_UPDATE_CURRENT));
result.setResultCallback(status -> { result.setResultCallback(
status -> {
if (status.isSuccess()) { if (status.isSuccess()) {
Timber.i("Registered %s", locations); Timber.i("Registered %s", locations);
} else { } else {
@ -75,8 +82,11 @@ public class GeofenceApi {
List<String> ids = Lists.transform(locations, geofence -> Long.toString(geofence.getId())); List<String> ids = Lists.transform(locations, geofence -> Long.toString(geofence.getId()));
newClient(client -> LocationServices.GeofencingApi.removeGeofences(client, ids) newClient(
.setResultCallback(status -> { client ->
LocationServices.GeofencingApi.removeGeofences(client, ids)
.setResultCallback(
status -> {
if (status.isSuccess()) { if (status.isSuccess()) {
Timber.i("Removed %s", locations); Timber.i("Removed %s", locations);
} else { } else {
@ -97,8 +107,10 @@ public class GeofenceApi {
private com.google.android.gms.location.Geofence toGoogleGeofence(Location location) { private com.google.android.gms.location.Geofence toGoogleGeofence(Location location) {
int radius = preferences.getIntegerFromString(R.string.p_geofence_radius, 250); int radius = preferences.getIntegerFromString(R.string.p_geofence_radius, 250);
int responsiveness = (int) TimeUnit.SECONDS int responsiveness =
.toMillis(preferences.getIntegerFromString(R.string.p_geofence_responsiveness, 60)); (int)
TimeUnit.SECONDS.toMillis(
preferences.getIntegerFromString(R.string.p_geofence_responsiveness, 60));
return new com.google.android.gms.location.Geofence.Builder() return new com.google.android.gms.location.Geofence.Builder()
.setCircularRegion(location.getLatitude(), location.getLongitude(), radius) .setCircularRegion(location.getLatitude(), location.getLongitude(), radius)
.setNotificationResponsiveness(responsiveness) .setNotificationResponsiveness(responsiveness)

@ -33,8 +33,8 @@ public class GeofenceTransitionsIntentService extends InjectingJobIntentService
int transitionType = geofencingEvent.getGeofenceTransition(); int transitionType = geofencingEvent.getGeofenceTransition();
List<com.google.android.gms.location.Geofence> triggeringGeofences = geofencingEvent List<com.google.android.gms.location.Geofence> triggeringGeofences =
.getTriggeringGeofences(); geofencingEvent.getTriggeringGeofences();
Timber.i("Received geofence transition: %s, %s", transitionType, triggeringGeofences); Timber.i("Received geofence transition: %s, %s", transitionType, triggeringGeofences);
if (transitionType == com.google.android.gms.location.Geofence.GEOFENCE_TRANSITION_ENTER) { if (transitionType == com.google.android.gms.location.Geofence.GEOFENCE_TRANSITION_ENTER) {
for (com.google.android.gms.location.Geofence triggerGeofence : triggeringGeofences) { for (com.google.android.gms.location.Geofence triggerGeofence : triggeringGeofences) {
@ -64,8 +64,11 @@ public class GeofenceTransitionsIntentService extends InjectingJobIntentService
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
JobIntentService.enqueueWork(context, GeofenceTransitionsIntentService.class, JobIntentService.enqueueWork(
JobManager.JOB_ID_GEOFENCE_TRANSITION, intent); context,
GeofenceTransitionsIntentService.class,
JobManager.JOB_ID_GEOFENCE_TRANSITION,
intent);
} }
} }
} }

@ -17,23 +17,24 @@ public class GoogleApi implements GoogleApiClient.ConnectionCallbacks {
@Inject @Inject
public GoogleApi(@ForApplication Context context) { public GoogleApi(@ForApplication Context context) {
builder = new GoogleApiClient.Builder(context) builder =
new GoogleApiClient.Builder(context)
.addApi(LocationServices.API) .addApi(LocationServices.API)
.addApi(Places.GEO_DATA_API) .addApi(Places.GEO_DATA_API)
.addConnectionCallbacks(this); .addConnectionCallbacks(this);
} }
public void connect(final GoogleApiClientConnectionHandler googleApiClientConnectionHandler) { public void connect(final GoogleApiClientConnectionHandler googleApiClientConnectionHandler) {
connect(googleApiClientConnectionHandler, connect(
googleApiClientConnectionHandler,
connectionResult -> Timber.e("onConnectionFailed(%s)", connectionResult)); connectionResult -> Timber.e("onConnectionFailed(%s)", connectionResult));
} }
private void connect(final GoogleApiClientConnectionHandler googleApiClientConnectionHandler, private void connect(
final GoogleApiClientConnectionHandler googleApiClientConnectionHandler,
GoogleApiClient.OnConnectionFailedListener onConnectionFailedListener) { GoogleApiClient.OnConnectionFailedListener onConnectionFailedListener) {
this.googleApiClientConnectionHandler = googleApiClientConnectionHandler; this.googleApiClientConnectionHandler = googleApiClientConnectionHandler;
googleApiClient = builder googleApiClient = builder.addOnConnectionFailedListener(onConnectionFailedListener).build();
.addOnConnectionFailedListener(onConnectionFailedListener)
.build();
googleApiClient.connect(); googleApiClient.connect();
} }

@ -25,8 +25,9 @@ public class PlacePicker {
activity.startActivity(e.getIntent()); activity.startActivity(e.getIntent());
} catch (GooglePlayServicesNotAvailableException e) { } catch (GooglePlayServicesNotAvailableException e) {
Timber.e(e, e.getMessage()); Timber.e(e, e.getMessage());
Toast.makeText(activity, R.string.common_google_play_services_notification_ticker, Toast.makeText(
Toast.LENGTH_LONG).show(); activity, R.string.common_google_play_services_notification_ticker, Toast.LENGTH_LONG)
.show();
} }
return null; return null;
} }

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.mdimension.jchronic; package com.mdimension.jchronic;
import com.mdimension.jchronic.handlers.Handler; import com.mdimension.jchronic.handlers.Handler;
@ -30,47 +29,41 @@ public class AstridChronic {
} }
/** /**
* Parses a string containing a natural language date or time. If the parser * Parses a string containing a natural language date or time. If the parser can find a date or
* can find a date or time, either a Time or Chronic::Span will be returned * time, either a Time or Chronic::Span will be returned (depending on the value of
* (depending on the value of <tt>:guess</tt>). If no date or time can be found, * <tt>:guess</tt>). If no date or time can be found, +nil+ will be returned.
* +nil+ will be returned.
* *
* Options are: * <p>Options are:
* *
* [<tt>:context</tt>] * <p>[<tt>:context</tt>] <tt>:past</tt> or <tt>:future</tt> (defaults to <tt>:future</tt>)
* <tt>:past</tt> or <tt>:future</tt> (defaults to <tt>:future</tt>)
* *
* If your string represents a birthday, you can set <tt>:context</tt> to <tt>:past</tt> * <p>If your string represents a birthday, you can set <tt>:context</tt> to <tt>:past</tt> and if
* and if an ambiguous string is given, it will assume it is in the * an ambiguous string is given, it will assume it is in the past. Specify <tt>:future</tt> or
* past. Specify <tt>:future</tt> or omit to set a future context. * omit to set a future context.
* *
* [<tt>:now</tt>] * <p>[<tt>:now</tt>] Time (defaults to Time.now)
* Time (defaults to Time.now)
* *
* By setting <tt>:now</tt> to a Time, all computations will be based off * <p>By setting <tt>:now</tt> to a Time, all computations will be based off of that time instead
* of that time instead of Time.now * of Time.now
* *
* [<tt>:guess</tt>] * <p>[<tt>:guess</tt>] +true+ or +false+ (defaults to +true+)
* +true+ or +false+ (defaults to +true+)
* *
* By default, the parser will guess a single point in time for the * <p>By default, the parser will guess a single point in time for the given date or time. If
* given date or time. If you'd rather have the entire time span returned, * you'd rather have the entire time span returned, set <tt>:guess</tt> to +false+ and a
* set <tt>:guess</tt> to +false+ and a Chronic::Span will be returned. * Chronic::Span will be returned.
* *
* [<tt>:ambiguous_time_range</tt>] * <p>[<tt>:ambiguous_time_range</tt>] Integer or <tt>:none</tt> (defaults to <tt>6</tt>
* Integer or <tt>:none</tt> (defaults to <tt>6</tt> (6am-6pm)) * (6am-6pm))
* *
* If an Integer is given, ambiguous times (like 5:00) will be * <p>If an Integer is given, ambiguous times (like 5:00) will be assumed to be within the range
* assumed to be within the range of that time in the AM to that time * of that time in the AM to that time in the PM. For example, if you set it to <tt>7</tt>, then
* in the PM. For example, if you set it to <tt>7</tt>, then the parser will * the parser will look for the time between 7am and 7pm. In the case of 5:00, it would assume
* look for the time between 7am and 7pm. In the case of 5:00, it would * that means 5:00pm. If <tt>:none</tt> is given, no assumption will be made, and the first
* assume that means 5:00pm. If <tt>:none</tt> is given, no assumption * matching instance of that time will be used.
* will be made, and the first matching instance of that time will
* be used.
*/ */
private static Span parse(String text, Options options) { private static Span parse(String text, Options options) {
// store now for later =) // store now for later =)
//_now = options.getNow(); // _now = options.getNow();
// put the text into a normal format to ease scanning // put the text into a normal format to ease scanning
String normalizedText = AstridChronic.preNormalize(text); String normalizedText = AstridChronic.preNormalize(text);
@ -114,10 +107,9 @@ public class AstridChronic {
} }
/** /**
* Clean up the specified input text by stripping unwanted characters, * Clean up the specified input text by stripping unwanted characters, converting idioms to their
* converting idioms to their canonical form, converting number words * canonical form, converting number words to numbers (three => 3), and converting ordinal words
* to numbers (three => 3), and converting ordinal words to numeric * to numeric ordinals (third => 3rd)
* ordinals (third => 3rd)
*/ */
private static String preNormalize(String text) { private static String preNormalize(String text) {
String normalizedText = text.toLowerCase(); String normalizedText = text.toLowerCase();
@ -135,8 +127,8 @@ public class AstridChronic {
normalizedText = normalizedText.replaceAll("\\bthis past\\b", "last"); normalizedText = normalizedText.replaceAll("\\bthis past\\b", "last");
normalizedText = normalizedText.replaceAll("\\bthis last\\b", "last"); normalizedText = normalizedText.replaceAll("\\bthis last\\b", "last");
normalizedText = normalizedText.replaceAll("\\b(?:in|during) the (morning)\\b", "$1"); normalizedText = normalizedText.replaceAll("\\b(?:in|during) the (morning)\\b", "$1");
normalizedText = normalizedText normalizedText =
.replaceAll("\\b(?:in the|during the|at) (afternoon|evening|night)\\b", "$1"); normalizedText.replaceAll("\\b(?:in the|during the|at) (afternoon|evening|night)\\b", "$1");
normalizedText = normalizedText.replaceAll("\\btonight\\b", "this night"); normalizedText = normalizedText.replaceAll("\\btonight\\b", "this night");
normalizedText = normalizedText.replaceAll("(?=\\w)([ap]m|oclock)\\b", " $1"); normalizedText = normalizedText.replaceAll("(?=\\w)([ap]m|oclock)\\b", " $1");
normalizedText = normalizedText.replaceAll("\\b(hence|after|from)\\b", "future"); normalizedText = normalizedText.replaceAll("\\b(hence|after|from)\\b", "future");
@ -144,17 +136,12 @@ public class AstridChronic {
return normalizedText; return normalizedText;
} }
/** /** Convert ordinal words to numeric ordinals (third => 3rd) */
* Convert ordinal words to numeric ordinals (third => 3rd)
*/
private static String numericizeOrdinals(String text) { private static String numericizeOrdinals(String text) {
return text; return text;
} }
/** /** Split the text on spaces and convert each word into a Token */
* Split the text on spaces and convert each word into
* a Token
*/
private static List<Token> baseTokenize(String text) { private static List<Token> baseTokenize(String text) {
String[] words = text.split(" "); String[] words = text.split(" ");
List<Token> tokens = new LinkedList<>(); List<Token> tokens = new LinkedList<>();
@ -164,9 +151,7 @@ public class AstridChronic {
return tokens; return tokens;
} }
/** /** Guess a specific time within the given span */
* Guess a specific time within the given span
*/
// DIFF: We return Span instead of Date // DIFF: We return Span instead of Date
private static Span guess(Span span) { private static Span guess(Span span) {
if (span == null) { if (span == null) {

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.data; package com.todoroo.andlib.data;
import android.text.TextUtils; import android.text.TextUtils;
@ -12,9 +11,9 @@ import com.todoroo.andlib.sql.Field;
/** /**
* Property represents a typed column in a database. * Property represents a typed column in a database.
* *
* Within a given database row, the parameter may not exist, in which case the * <p>Within a given database row, the parameter may not exist, in which case the value is null, it
* value is null, it may be of an incorrect type, in which case an exception is * may be of an incorrect type, in which case an exception is thrown, or the correct type, in which
* thrown, or the correct type, in which case the value is returned. * case the value is returned.
* *
* @param <TYPE> a database supported type, such as String or Integer * @param <TYPE> a database supported type, such as String or Integer
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
@ -23,37 +22,27 @@ public abstract class Property<TYPE> extends Field implements Cloneable {
// --- implementation // --- implementation
/** /** The database column name for this property */
* The database table name this property
*/
private final Table table;
/**
* The database column name for this property
*/
public final String name; public final String name;
/** The database table name this property */
private final Table table;
/** /**
* Create a property by table and column name. Uses the default property * Create a property by table and column name. Uses the default property expression which is
* expression which is derived from default table name * derived from default table name
*/ */
Property(Table table, String columnName) { Property(Table table, String columnName) {
this(table, columnName, (table == null) ? (columnName) : (table.name() + "." + columnName)); this(table, columnName, (table == null) ? (columnName) : (table.name() + "." + columnName));
} }
/** /** Create a property by table and column name, manually specifying an expression to use in SQL */
* Create a property by table and column name, manually specifying an
* expression to use in SQL
*/
Property(Table table, String columnName, String expression) { Property(Table table, String columnName, String expression) {
super(expression); super(expression);
this.table = table; this.table = table;
this.name = columnName; this.name = columnName;
} }
/** /** Return a clone of this property */
* Return a clone of this property
*/
@Override @Override
public Property<TYPE> clone() { public Property<TYPE> clone() {
try { try {
@ -63,9 +52,7 @@ public abstract class Property<TYPE> extends Field implements Cloneable {
} }
} }
/** /** Return a clone of this property */
* Return a clone of this property
*/
Property<TYPE> cloneAs(String tableAlias, String columnAlias) { Property<TYPE> cloneAs(String tableAlias, String columnAlias) {
Table aliasedTable = this.table; Table aliasedTable = this.table;
if (!TextUtils.isEmpty(tableAlias)) { if (!TextUtils.isEmpty(tableAlias)) {
@ -73,7 +60,9 @@ public abstract class Property<TYPE> extends Field implements Cloneable {
} }
try { try {
Property<TYPE> newInstance = this.getClass().getConstructor(Table.class, String.class) Property<TYPE> newInstance =
this.getClass()
.getConstructor(Table.class, String.class)
.newInstance(aliasedTable, this.name); .newInstance(aliasedTable, this.name);
if (!TextUtils.isEmpty(columnAlias)) { if (!TextUtils.isEmpty(columnAlias)) {
return (Property<TYPE>) newInstance.as(columnAlias); return (Property<TYPE>) newInstance.as(columnAlias);
@ -136,9 +125,7 @@ public abstract class Property<TYPE> extends Field implements Cloneable {
// --- pseudo-properties // --- pseudo-properties
/** /** Runs a SQL function and returns the result as a string */
* Runs a SQL function and returns the result as a string
*/
public static class CountProperty extends IntegerProperty { public static class CountProperty extends IntegerProperty {
public CountProperty() { public CountProperty() {

@ -1,16 +1,15 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.data; package com.todoroo.andlib.data;
import com.todoroo.andlib.sql.SqlTable; import com.todoroo.andlib.sql.SqlTable;
/** /**
* Table class. Most fields are final, so methods such as <code>as</code> will * Table class. Most fields are final, so methods such as <code>as</code> will clone the table when
* clone the table when it returns. * it returns.
* *
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
*/ */
@ -28,9 +27,7 @@ public final class Table extends SqlTable {
this.alias = alias; this.alias = alias;
} }
/** /** Create a new join table based on this table, but with an alias */
* Create a new join table based on this table, but with an alias
*/
@Override @Override
public Table as(String newAlias) { public Table as(String newAlias) {
return new Table(name, newAlias); return new Table(name, newAlias);
@ -39,7 +36,7 @@ public final class Table extends SqlTable {
@Override @Override
public String toString() { public String toString() {
if (hasAlias()) { if (hasAlias()) {
return expression + " AS " + alias; //$NON-NLS-1$ return expression + " AS " + alias; // $NON-NLS-1$
} }
return expression; return expression;
} }

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.sql; package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.AND; import static com.todoroo.andlib.sql.SqlConstants.AND;
@ -15,7 +14,8 @@ import static com.todoroo.andlib.sql.SqlConstants.SPACE;
public abstract class Criterion { public abstract class Criterion {
public static final Criterion all = new Criterion(Operator.exists) { public static final Criterion all =
new Criterion(Operator.exists) {
@Override @Override
protected void populate(StringBuilder sb) { protected void populate(StringBuilder sb) {
sb.append(1); sb.append(1);
@ -73,5 +73,4 @@ public abstract class Criterion {
builder.append(RIGHT_PARENTHESIS); builder.append(RIGHT_PARENTHESIS);
return builder.toString(); return builder.toString();
} }
} }

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.sql; package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.AS; import static com.todoroo.andlib.sql.SqlConstants.AS;
@ -46,7 +45,8 @@ public abstract class DBObject<T extends DBObject<?>> implements Cloneable {
if (alias != null ? !alias.equals(dbObject.alias) : dbObject.alias != null) { if (alias != null ? !alias.equals(dbObject.alias) : dbObject.alias != null) {
return false; return false;
} }
if (expression != null ? !expression.equals(dbObject.expression) if (expression != null
? !expression.equals(dbObject.expression)
: dbObject.expression != null) { : dbObject.expression != null) {
return false; return false;
} }

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.sql; package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.COMMA; import static com.todoroo.andlib.sql.SqlConstants.COMMA;
@ -57,7 +56,11 @@ public class Field extends DBObject<Field> {
@Override @Override
protected void populate(StringBuilder sb) { protected void populate(StringBuilder sb) {
sb.append(field).append(SPACE).append(Operator.in).append(SPACE).append(LEFT_PARENTHESIS) sb.append(field)
.append(SPACE)
.append(Operator.in)
.append(SPACE)
.append(LEFT_PARENTHESIS)
.append(SPACE); .append(SPACE);
for (T t : value) { for (T t : value) {
sb.append(t.toString()).append(COMMA); sb.append(t.toString()).append(COMMA);
@ -73,7 +76,11 @@ public class Field extends DBObject<Field> {
@Override @Override
protected void populate(StringBuilder sb) { protected void populate(StringBuilder sb) {
sb.append(field).append(SPACE).append(Operator.in).append(SPACE).append(LEFT_PARENTHESIS) sb.append(field)
.append(SPACE)
.append(Operator.in)
.append(SPACE)
.append(LEFT_PARENTHESIS)
.append(query) .append(query)
.append(RIGHT_PARENTHESIS); .append(RIGHT_PARENTHESIS);
} }

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.sql; package com.todoroo.andlib.sql;
public final class Functions { public final class Functions {
@ -12,9 +11,7 @@ public final class Functions {
return new Field("UPPER(" + title.toString() + ")"); return new Field("UPPER(" + title.toString() + ")");
} }
/** /** @return SQL now (in milliseconds) */
* @return SQL now (in milliseconds)
*/
public static Field now() { public static Field now() {
return new Field("(strftime('%s','now')*1000)"); return new Field("(strftime('%s','now')*1000)");
} }

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.sql; package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.AND; import static com.todoroo.andlib.sql.SqlConstants.AND;
@ -34,8 +33,15 @@ public class Join {
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(joinType).append(SPACE).append(JOIN).append(SPACE).append(joinTable).append(SPACE) sb.append(joinType)
.append(ON).append(SPACE).append("("); .append(SPACE)
.append(JOIN)
.append(SPACE)
.append(joinTable)
.append(SPACE)
.append(ON)
.append(SPACE)
.append("(");
for (int i = 0; i < criterions.length; i++) { for (int i = 0; i < criterions.length; i++) {
sb.append(criterions[i]); sb.append(criterions[i]);
if (i < criterions.length - 1) { if (i < criterions.length - 1) {

@ -1,11 +1,11 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.sql; package com.todoroo.andlib.sql;
public enum JoinType { public enum JoinType {
INNER, LEFT INNER,
LEFT
} }

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.sql; package com.todoroo.andlib.sql;
public final class Operator { public final class Operator {

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.sql; package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.SPACE; import static com.todoroo.andlib.sql.SqlConstants.SPACE;
@ -42,12 +41,10 @@ public class Order {
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(expression.toString()) sb.append(expression.toString()).append(SPACE).append(orderType.toString());
.append(SPACE)
.append(orderType.toString());
for (Order secondary : secondaryExpressions) { for (Order secondary : secondaryExpressions) {
sb.append(", ").append(secondary.toString()); //$NON-NLS-1$ sb.append(", ").append(secondary.toString()); // $NON-NLS-1$
} }
return sb.toString(); return sb.toString();

@ -1,11 +1,11 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.sql; package com.todoroo.andlib.sql;
public enum OrderType { public enum OrderType {
DESC, ASC DESC,
ASC
} }

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.sql; package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.ALL; import static com.todoroo.andlib.sql.SqlConstants.ALL;
@ -49,8 +48,8 @@ public final class Query {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
return this == o || !(o == null || getClass() != o.getClass()) && this.toString() return this == o
.equals(o.toString()); || !(o == null || getClass() != o.getClass()) && this.toString().equals(o.toString());
} }
@Override @Override

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.sql; package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.COMMA; import static com.todoroo.andlib.sql.SqlConstants.COMMA;
@ -16,8 +15,7 @@ import static java.util.Arrays.asList;
import java.util.ArrayList; import java.util.ArrayList;
/** /**
* Query Template returns a bunch of criteria that allows a query to be * Query Template returns a bunch of criteria that allows a query to be constructed
* constructed
* *
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
*/ */

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.sql; package com.todoroo.andlib.sql;
final class SqlConstants { final class SqlConstants {

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.sql; package com.todoroo.andlib.sql;
public class SqlTable extends DBObject<SqlTable> { public class SqlTable extends DBObject<SqlTable> {

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.sql; package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.SPACE; import static com.todoroo.andlib.sql.SqlConstants.SPACE;
@ -23,9 +22,7 @@ public class UnaryCriterion extends Criterion {
return new UnaryCriterion(expression, Operator.eq, value); return new UnaryCriterion(expression, Operator.eq, value);
} }
/** /** Sanitize the given input for SQL */
* Sanitize the given input for SQL
*/
public static String sanitize(String input) { public static String sanitize(String input) {
return input.replace("'", "''"); return input.replace("'", "''");
} }

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.utility; package com.todoroo.andlib.utility;
import android.app.Activity; import android.app.Activity;
@ -32,18 +31,17 @@ import timber.log.Timber;
*/ */
public class AndroidUtilities { public class AndroidUtilities {
public static final String SEPARATOR_ESCAPE = "!PIPE!"; //$NON-NLS-1$ public static final String SEPARATOR_ESCAPE = "!PIPE!"; // $NON-NLS-1$
public static final String SERIALIZATION_SEPARATOR = "|"; //$NON-NLS-1$ public static final String SERIALIZATION_SEPARATOR = "|"; // $NON-NLS-1$
// --- utility methods // --- utility methods
/** /** Suppress virtual keyboard until user's first tap */
* Suppress virtual keyboard until user's first tap
*/
public static void suppressVirtualKeyboard(final TextView editor) { public static void suppressVirtualKeyboard(final TextView editor) {
final int inputType = editor.getInputType(); final int inputType = editor.getInputType();
editor.setInputType(InputType.TYPE_NULL); editor.setInputType(InputType.TYPE_NULL);
editor.setOnTouchListener((v, event) -> { editor.setOnTouchListener(
(v, event) -> {
editor.setInputType(inputType); editor.setInputType(inputType);
editor.setOnTouchListener(null); editor.setOnTouchListener(null);
return false; return false;
@ -52,9 +50,7 @@ public class AndroidUtilities {
// --- serialization // --- serialization
/** /** Serializes a content value into a string */
* Serializes a content value into a string
*/
public static String mapToSerializedString(Map<String, Object> source) { public static String mapToSerializedString(Map<String, Object> source) {
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
for (Entry<String, Object> entry : source.entrySet()) { for (Entry<String, Object> entry : source.entrySet()) {
@ -63,13 +59,11 @@ public class AndroidUtilities {
return result.toString(); return result.toString();
} }
/** /** add serialized helper */
* add serialized helper private static void addSerialized(StringBuilder result, String key, Object value) {
*/ result
private static void addSerialized(StringBuilder result, .append(key.replace(SERIALIZATION_SEPARATOR, SEPARATOR_ESCAPE))
String key, Object value) { .append(SERIALIZATION_SEPARATOR);
result.append(key.replace(SERIALIZATION_SEPARATOR, SEPARATOR_ESCAPE)).append(
SERIALIZATION_SEPARATOR);
if (value instanceof Integer) { if (value instanceof Integer) {
result.append('i').append(value); result.append('i').append(value);
} else if (value instanceof Double) { } else if (value instanceof Double) {
@ -77,7 +71,8 @@ public class AndroidUtilities {
} else if (value instanceof Long) { } else if (value instanceof Long) {
result.append('l').append(value); result.append('l').append(value);
} else if (value instanceof String) { } else if (value instanceof String) {
result.append('s') result
.append('s')
.append(value.toString().replace(SERIALIZATION_SEPARATOR, SEPARATOR_ESCAPE)); .append(value.toString().replace(SERIALIZATION_SEPARATOR, SEPARATOR_ESCAPE));
} else if (value instanceof Boolean) { } else if (value instanceof Boolean) {
result.append('b').append(value); result.append('b').append(value);
@ -93,7 +88,10 @@ public class AndroidUtilities {
} }
Map<String, Object> result = new HashMap<>(); Map<String, Object> result = new HashMap<>();
fromSerialized(string, result, (object, key, type, value) -> { fromSerialized(
string,
result,
(object, key, type, value) -> {
switch (type) { switch (type) {
case 'i': case 'i':
object.put(key, Integer.parseInt(value)); object.put(key, Integer.parseInt(value));
@ -116,7 +114,7 @@ public class AndroidUtilities {
} }
private static <T> void fromSerialized(String string, T object, SerializedPut<T> putter) { private static <T> void fromSerialized(String string, T object, SerializedPut<T> putter) {
String[] pairs = string.split("\\" + SERIALIZATION_SEPARATOR); //$NON-NLS-1$ String[] pairs = string.split("\\" + SERIALIZATION_SEPARATOR); // $NON-NLS-1$
for (int i = 0; i < pairs.length; i += 2) { for (int i = 0; i < pairs.length; i += 2) {
try { try {
String key = pairs[i].replaceAll(SEPARATOR_ESCAPE, SERIALIZATION_SEPARATOR); String key = pairs[i].replaceAll(SEPARATOR_ESCAPE, SERIALIZATION_SEPARATOR);
@ -134,9 +132,7 @@ public class AndroidUtilities {
} }
} }
/** /** Copy a file from one place to another */
* Copy a file from one place to another
*/
public static void copyFile(File in, File out) throws Exception { public static void copyFile(File in, File out) throws Exception {
FileInputStream fis = new FileInputStream(in); FileInputStream fis = new FileInputStream(in);
FileOutputStream fos = new FileOutputStream(out); FileOutputStream fos = new FileOutputStream(out);
@ -148,9 +144,7 @@ public class AndroidUtilities {
} }
} }
/** /** Copy stream from source to destination */
* Copy stream from source to destination
*/
private static void copyStream(InputStream source, OutputStream dest) throws IOException { private static void copyStream(InputStream source, OutputStream dest) throws IOException {
int bytes; int bytes;
byte[] buffer; byte[] buffer;
@ -218,8 +212,8 @@ public class AndroidUtilities {
} }
/** /**
* Sleep, ignoring interruption. Before using this method, think carefully * Sleep, ignoring interruption. Before using this method, think carefully about why you are
* about why you are ignoring interruptions. * ignoring interruptions.
*/ */
public static void sleepDeep(long l) { public static void sleepDeep(long l) {
try { try {
@ -229,9 +223,7 @@ public class AndroidUtilities {
} }
} }
/** /** Capitalize the first character */
* Capitalize the first character
*/
public static String capitalize(String string) { public static String capitalize(String string) {
return string.substring(0, 1).toUpperCase() + string.substring(1); return string.substring(0, 1).toUpperCase() + string.substring(1);
} }
@ -240,8 +232,8 @@ public class AndroidUtilities {
try { try {
View currentFocus = activity.getCurrentFocus(); View currentFocus = activity.getCurrentFocus();
if (currentFocus != null) { if (currentFocus != null) {
InputMethodManager inputMethodManager = (InputMethodManager) activity InputMethodManager inputMethodManager =
.getSystemService(Context.INPUT_METHOD_SERVICE); (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(currentFocus.getWindowToken(), 0); inputMethodManager.hideSoftInputFromWindow(currentFocus.getWindowToken(), 0);
} }
} catch (Exception e) { } catch (Exception e) {
@ -255,16 +247,14 @@ public class AndroidUtilities {
* @param views - a list of views that might potentially be displaying the keyboard * @param views - a list of views that might potentially be displaying the keyboard
*/ */
public static void hideSoftInputForViews(Context context, View... views) { public static void hideSoftInputForViews(Context context, View... views) {
InputMethodManager imm = (InputMethodManager) context InputMethodManager imm =
.getSystemService(Context.INPUT_METHOD_SERVICE); (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
for (View v : views) { for (View v : views) {
imm.hideSoftInputFromWindow(v.getWindowToken(), 0); imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
} }
} }
/** /** Returns the final word characters after the last '.' */
* Returns the final word characters after the last '.'
*/
public static String getFileExtension(String file) { public static String getFileExtension(String file) {
int index = file.lastIndexOf('.'); int index = file.lastIndexOf('.');
String extension = ""; String extension = "";

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.utility; package com.todoroo.andlib.utility;
import static org.tasks.date.DateTimeUtils.newDateTime; import static org.tasks.date.DateTimeUtils.newDateTime;
@ -16,25 +15,17 @@ import org.tasks.R;
import org.tasks.locale.Locale; import org.tasks.locale.Locale;
import org.tasks.time.DateTime; import org.tasks.time.DateTime;
public class DateUtilities { public class DateUtilities {
/** /** Represents a single hour */
* Represents a single hour
*/
public static final long ONE_HOUR = 3600000L; public static final long ONE_HOUR = 3600000L;
/** /** Represents a single day */
* Represents a single day
*/
public static final long ONE_DAY = 24 * ONE_HOUR; public static final long ONE_DAY = 24 * ONE_HOUR;
/** /** Represents a single week */
* Represents a single week
*/
public static final long ONE_WEEK = 7 * ONE_DAY; public static final long ONE_WEEK = 7 * ONE_DAY;
/** /** Represents a single minute */
* Represents a single minute
*/
public static final long ONE_MINUTE = 60000L; public static final long ONE_MINUTE = 60000L;
private static final long abbreviationLimit = DateUtilities.ONE_DAY * 6; private static final long abbreviationLimit = DateUtilities.ONE_DAY * 6;
private static final String JA = "MMM d\u65E5"; private static final String JA = "MMM d\u65E5";
private static final String JA_YEAR = "yy\u5E74 " + JA; private static final String JA_YEAR = "yy\u5E74 " + JA;
@ -45,8 +36,8 @@ public class DateUtilities {
static Boolean is24HourOverride = null; static Boolean is24HourOverride = null;
/** /**
* Add the specified amount of months to the given time.<br/> * Add the specified amount of months to the given time.<br>
* The day of month will stay the same.<br/> * The day of month will stay the same.<br>
* *
* @param time the base-time (in milliseconds) to which the amount of months is added * @param time the base-time (in milliseconds) to which the amount of months is added
* @param interval the amount of months to be added * @param interval the amount of months to be added
@ -63,9 +54,7 @@ public class DateUtilities {
return result.getMillis(); return result.getMillis();
} }
/** /** Returns unixtime for current time */
* Returns unixtime for current time
*/
public static long now() { public static long now() {
return currentTimeMillis(); return currentTimeMillis();
} }
@ -74,9 +63,7 @@ public class DateUtilities {
* =========================================================== formatters * =========================================================== formatters
* ====================================================================== */ * ====================================================================== */
/** /** Returns unixtime one month from now */
* Returns unixtime one month from now
*/
public static long oneMonthFromNow() { public static long oneMonthFromNow() {
return addCalendarMonthsToUnixtime(currentTimeMillis(), 1); return addCalendarMonthsToUnixtime(currentTimeMillis(), 1);
} }
@ -138,26 +125,18 @@ public class DateUtilities {
case "KE": case "KE":
case "MN": case "MN":
case "US": case "US":
return includeYear return includeYear ? monthFormat + " d ''yy" : monthFormat + " d";
? monthFormat + " d ''yy"
: monthFormat + " d";
default: default:
return includeYear return includeYear ? "d " + monthFormat + " ''yy" : "d " + monthFormat;
? "d " + monthFormat + " ''yy"
: "d " + monthFormat;
} }
} }
/** /** @return weekday */
* @return weekday
*/
public static String getWeekday(DateTime date) { public static String getWeekday(DateTime date) {
return date.toString("EEEE"); return date.toString("EEEE");
} }
/** /** @return weekday */
* @return weekday
*/
public static String getWeekdayShort(DateTime date) { public static String getWeekdayShort(DateTime date) {
return date.toString("EEE"); return date.toString("EEE");
} }
@ -175,15 +154,16 @@ public class DateUtilities {
public static String getRelativeDateStringWithTime(Context context, long timestamp) { public static String getRelativeDateStringWithTime(Context context, long timestamp) {
String string = DateUtilities.getRelativeDay(context, timestamp, false); String string = DateUtilities.getRelativeDay(context, timestamp, false);
if (Task.hasDueTime(timestamp)) { if (Task.hasDueTime(timestamp)) {
string = String.format("%s %s", string, //$NON-NLS-1$ string =
String.format(
"%s %s",
string, // $NON-NLS-1$
DateUtilities.getTimeString(context, timestamp)); DateUtilities.getTimeString(context, timestamp));
} }
return string; return string;
} }
/** /** @return yesterday, today, tomorrow, or null */
* @return yesterday, today, tomorrow, or null
*/
public static String getRelativeDay(Context context, long date, boolean abbreviated) { public static String getRelativeDay(Context context, long date, boolean abbreviated) {
long today = getStartOfDay(currentTimeMillis()); long today = getStartOfDay(currentTimeMillis());
long input = getStartOfDay(date); long input = getStartOfDay(date);
@ -201,7 +181,8 @@ public class DateUtilities {
} }
if (today + abbreviationLimit >= input && today - abbreviationLimit <= input) { if (today + abbreviationLimit >= input && today - abbreviationLimit <= input) {
return abbreviated ? DateUtilities.getWeekdayShort(newDateTime(date)) return abbreviated
? DateUtilities.getWeekdayShort(newDateTime(date))
: DateUtilities.getWeekday(newDateTime(date)); : DateUtilities.getWeekday(newDateTime(date));
} }

@ -1,27 +1,24 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.utility; package com.todoroo.andlib.utility;
import android.app.Activity; import android.app.Activity;
import android.app.Dialog; import android.app.Dialog;
import timber.log.Timber; import timber.log.Timber;
public class DialogUtilities { public class DialogUtilities {
/** /** Dismiss a dialog off the UI thread */
* Dismiss a dialog off the UI thread
*/
@Deprecated @Deprecated
public static void dismissDialog(Activity activity, final Dialog dialog) { public static void dismissDialog(Activity activity, final Dialog dialog) {
if (dialog == null) { if (dialog == null) {
return; return;
} }
activity.runOnUiThread(() -> { activity.runOnUiThread(
() -> {
try { try {
dialog.dismiss(); dialog.dismiss();
} catch (Exception e) { } catch (Exception e) {

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.activity; package com.todoroo.astrid.activity;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
@ -29,13 +28,18 @@ import org.tasks.preferences.Preferences;
import org.tasks.preferences.beast.BeastModeRecyclerAdapter; import org.tasks.preferences.beast.BeastModeRecyclerAdapter;
import org.tasks.ui.MenuColorizer; import org.tasks.ui.MenuColorizer;
public class BeastModePreferences extends ThemedInjectingAppCompatActivity implements public class BeastModePreferences extends ThemedInjectingAppCompatActivity
Toolbar.OnMenuItemClickListener { implements Toolbar.OnMenuItemClickListener {
private static final String BEAST_MODE_ORDER_PREF = "beast_mode_order_v3"; //$NON-NLS-1$ private static final String BEAST_MODE_ORDER_PREF = "beast_mode_order_v3"; // $NON-NLS-1$
private static final String BEAST_MODE_PREF_ITEM_SEPARATOR = ";"; private static final String BEAST_MODE_PREF_ITEM_SEPARATOR = ";";
@BindView(R.id.toolbar) Toolbar toolbar;
@BindView(R.id.recycler_view) RecyclerView recyclerView; @BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.recycler_view)
RecyclerView recyclerView;
@Inject Preferences preferences; @Inject Preferences preferences;
private BeastModeRecyclerAdapter adapter; private BeastModeRecyclerAdapter adapter;
@ -53,8 +57,8 @@ public class BeastModePreferences extends ThemedInjectingAppCompatActivity imple
preferences.setString(BEAST_MODE_ORDER_PREF, newSetting.toString()); preferences.setString(BEAST_MODE_ORDER_PREF, newSetting.toString());
} }
public static ArrayList<String> constructOrderedControlList(Preferences preferences, public static ArrayList<String> constructOrderedControlList(
Context context) { Preferences preferences, Context context) {
String order = preferences.getStringValue(BEAST_MODE_ORDER_PREF); String order = preferences.getStringValue(BEAST_MODE_ORDER_PREF);
ArrayList<String> list = new ArrayList<>(); ArrayList<String> list = new ArrayList<>();
String[] itemsArray; String[] itemsArray;

@ -1,7 +1,4 @@
/** /** TODO: make this lightweight, don't extend the entire TaskListActivity */
* TODO: make this lightweight, don't extend the entire TaskListActivity
*/
package com.todoroo.astrid.activity; package com.todoroo.astrid.activity;
import static org.tasks.intents.TaskIntents.getEditTaskStack; import static org.tasks.intents.TaskIntents.getEditTaskStack;
@ -17,8 +14,7 @@ import org.tasks.injection.InjectingAppCompatActivity;
/** /**
* @author joshuagross * @author joshuagross
* * <p>Create a new task based on incoming links from the "share" menu
* Create a new task based on incoming links from the "share" menu
*/ */
public final class ShareLinkActivity extends InjectingAppCompatActivity { public final class ShareLinkActivity extends InjectingAppCompatActivity {

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.activity; package com.todoroo.astrid.activity;
import static org.tasks.date.DateTimeUtils.newDateTime; import static org.tasks.date.DateTimeUtils.newDateTime;
@ -53,8 +52,8 @@ import org.tasks.ui.MenuColorizer;
import org.tasks.ui.RemoteListFragment; import org.tasks.ui.RemoteListFragment;
import org.tasks.ui.TaskEditControlFragment; import org.tasks.ui.TaskEditControlFragment;
public final class TaskEditFragment extends InjectingFragment implements public final class TaskEditFragment extends InjectingFragment
Toolbar.OnMenuItemClickListener { implements Toolbar.OnMenuItemClickListener {
public static final String TAG_TASKEDIT_FRAGMENT = "taskedit_fragment"; public static final String TAG_TASKEDIT_FRAGMENT = "taskedit_fragment";
private static final String EXTRA_TASK = "extra_task"; private static final String EXTRA_TASK = "extra_task";
@ -70,9 +69,16 @@ public final class TaskEditFragment extends InjectingFragment implements
@Inject Tracker tracker; @Inject Tracker tracker;
@Inject TimerPlugin timerPlugin; @Inject TimerPlugin timerPlugin;
@Inject LocalBroadcastManager localBroadcastManager; @Inject LocalBroadcastManager localBroadcastManager;
@BindView(R.id.toolbar) Toolbar toolbar;
@BindView(R.id.comments) LinearLayout comments; @BindView(R.id.toolbar)
@BindView(R.id.control_sets) LinearLayout controlSets; Toolbar toolbar;
@BindView(R.id.comments)
LinearLayout comments;
@BindView(R.id.control_sets)
LinearLayout controlSets;
Task model = null; Task model = null;
private TaskEditFragmentCallbackHandler callback; private TaskEditFragmentCallbackHandler callback;
@ -97,8 +103,8 @@ public final class TaskEditFragment extends InjectingFragment implements
} }
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(
Bundle savedInstanceState) { LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_task_edit, container, false); View view = inflater.inflate(R.layout.fragment_task_edit, container, false);
ButterKnife.bind(this, view); ButterKnife.bind(this, view);
@ -106,9 +112,11 @@ public final class TaskEditFragment extends InjectingFragment implements
model = arguments.getParcelable(EXTRA_TASK); model = arguments.getParcelable(EXTRA_TASK);
final boolean backButtonSavesTask = preferences.backButtonSavesTask(); final boolean backButtonSavesTask = preferences.backButtonSavesTask();
toolbar.setNavigationIcon(ContextCompat.getDrawable(context, toolbar.setNavigationIcon(
backButtonSavesTask ? R.drawable.ic_close_24dp : R.drawable.ic_save_24dp)); ContextCompat.getDrawable(
toolbar.setNavigationOnClickListener(v -> { context, backButtonSavesTask ? R.drawable.ic_close_24dp : R.drawable.ic_save_24dp));
toolbar.setNavigationOnClickListener(
v -> {
if (backButtonSavesTask) { if (backButtonSavesTask) {
discardButtonClick(); discardButtonClick();
} else { } else {
@ -127,16 +135,17 @@ public final class TaskEditFragment extends InjectingFragment implements
commentsController.reloadView(); commentsController.reloadView();
FragmentManager fragmentManager = getChildFragmentManager(); FragmentManager fragmentManager = getChildFragmentManager();
List<TaskEditControlFragment> taskEditControlFragments = taskEditControlSetFragmentManager List<TaskEditControlFragment> taskEditControlFragments =
.getOrCreateFragments(fragmentManager, model); taskEditControlSetFragmentManager.getOrCreateFragments(fragmentManager, model);
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
for (int i = 0; i < taskEditControlFragments.size(); i++) { for (int i = 0; i < taskEditControlFragments.size(); i++) {
TaskEditControlFragment taskEditControlFragment = taskEditControlFragments.get(i); TaskEditControlFragment taskEditControlFragment = taskEditControlFragments.get(i);
String tag = getString(taskEditControlFragment.controlId()); String tag = getString(taskEditControlFragment.controlId());
fragmentTransaction fragmentTransaction.replace(
.replace(TaskEditControlSetFragmentManager.TASK_EDIT_CONTROL_FRAGMENT_ROWS[i], TaskEditControlSetFragmentManager.TASK_EDIT_CONTROL_FRAGMENT_ROWS[i],
taskEditControlFragment, tag); taskEditControlFragment,
tag);
} }
fragmentTransaction.commit(); fragmentTransaction.commit();
@ -163,29 +172,32 @@ public final class TaskEditFragment extends InjectingFragment implements
public Task stopTimer() { public Task stopTimer() {
timerPlugin.stopTimer(model); timerPlugin.stopTimer(model);
String elapsedTime = DateUtils.formatElapsedTime(model.getElapsedSeconds()); String elapsedTime = DateUtils.formatElapsedTime(model.getElapsedSeconds());
addComment(String.format("%s %s\n%s %s", //$NON-NLS-1$ addComment(
String.format(
"%s %s\n%s %s", // $NON-NLS-1$
getString(R.string.TEA_timer_comment_stopped), getString(R.string.TEA_timer_comment_stopped),
DateUtilities.getTimeString(getActivity(), newDateTime()), DateUtilities.getTimeString(getActivity(), newDateTime()),
getString(R.string.TEA_timer_comment_spent), getString(R.string.TEA_timer_comment_spent),
elapsedTime), null); elapsedTime),
null);
return model; return model;
} }
public Task startTimer() { public Task startTimer() {
timerPlugin.startTimer(model); timerPlugin.startTimer(model);
addComment(String.format("%s %s", addComment(
String.format(
"%s %s",
getString(R.string.TEA_timer_comment_started), getString(R.string.TEA_timer_comment_started),
DateUtilities.getTimeString(getActivity(), newDateTime())), DateUtilities.getTimeString(getActivity(), newDateTime())),
null); null);
return model; return model;
} }
/** /** Save task model from values in UI components */
* Save task model from values in UI components
*/
public void save() { public void save() {
List<TaskEditControlFragment> fragments = taskEditControlSetFragmentManager List<TaskEditControlFragment> fragments =
.getFragmentsInPersistOrder(getChildFragmentManager()); taskEditControlSetFragmentManager.getFragmentsInPersistOrder(getChildFragmentManager());
if (hasChanges(fragments)) { if (hasChanges(fragments)) {
boolean isNewTask = model.isNew(); boolean isNewTask = model.isNew();
if (isNewTask) { if (isNewTask) {
@ -201,9 +213,7 @@ public final class TaskEditFragment extends InjectingFragment implements
} }
if (isNewTask) { if (isNewTask) {
((TaskListActivity) getActivity()) ((TaskListActivity) getActivity()).getTaskListFragment().onTaskCreated(model.getUuid());
.getTaskListFragment()
.onTaskCreated(model.getUuid());
} }
callback.taskEditFinished(); callback.taskEditFinished();
} else { } else {
@ -260,7 +270,8 @@ public final class TaskEditFragment extends InjectingFragment implements
public void discardButtonClick() { public void discardButtonClick() {
if (hasChanges( if (hasChanges(
taskEditControlSetFragmentManager.getFragmentsInPersistOrder(getChildFragmentManager()))) { taskEditControlSetFragmentManager.getFragmentsInPersistOrder(getChildFragmentManager()))) {
dialogBuilder.newMessageDialog(R.string.discard_confirmation) dialogBuilder
.newMessageDialog(R.string.discard_confirmation)
.setPositiveButton(R.string.keep_editing, null) .setPositiveButton(R.string.keep_editing, null)
.setNegativeButton(R.string.discard, (dialog, which) -> discard()) .setNegativeButton(R.string.discard, (dialog, which) -> discard())
.show(); .show();
@ -278,8 +289,11 @@ public final class TaskEditFragment extends InjectingFragment implements
} }
private void deleteButtonClick() { private void deleteButtonClick() {
dialogBuilder.newMessageDialog(R.string.DLG_delete_this_task_question) dialogBuilder
.setPositiveButton(android.R.string.ok, (dialog, which) -> { .newMessageDialog(R.string.DLG_delete_this_task_question)
.setPositiveButton(
android.R.string.ok,
(dialog, which) -> {
timerPlugin.stopTimer(model); timerPlugin.stopTimer(model);
taskDeleter.markDeleted(model); taskDeleter.markDeleted(model);
callback.taskEditFinished(); callback.taskEditFinished();

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.activity; package com.todoroo.astrid.activity;
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastLollipop; import static com.todoroo.andlib.utility.AndroidUtilities.atLeastLollipop;
@ -73,8 +72,8 @@ import org.tasks.ui.PriorityControlSet;
import org.tasks.ui.TaskListViewModel; import org.tasks.ui.TaskListViewModel;
import timber.log.Timber; import timber.log.Timber;
public class TaskListActivity extends InjectingAppCompatActivity implements public class TaskListActivity extends InjectingAppCompatActivity
OnFilterItemClickedListener, implements OnFilterItemClickedListener,
TaskListFragment.TaskListFragmentCallbackHandler, TaskListFragment.TaskListFragmentCallbackHandler,
PriorityControlSet.OnPriorityChanged, PriorityControlSet.OnPriorityChanged,
TimerControlSet.TimerControlSetCallback, TimerControlSet.TimerControlSetCallback,
@ -85,14 +84,13 @@ public class TaskListActivity extends InjectingAppCompatActivity implements
SortDialog.SortDialogCallback, SortDialog.SortDialogCallback,
RemoteListSelectionHandler { RemoteListSelectionHandler {
/** /** For indicating the new list screen should be launched at fragment setup time */
* For indicating the new list screen should be launched at fragment setup time public static final String TOKEN_CREATE_NEW_LIST_NAME = "newListName"; // $NON-NLS-1$
*/
public static final String TOKEN_CREATE_NEW_LIST_NAME = "newListName"; //$NON-NLS-1$ public static final String OPEN_FILTER = "open_filter"; // $NON-NLS-1$
public static final String OPEN_FILTER = "open_filter"; //$NON-NLS-1$
public static final String LOAD_FILTER = "load_filter"; public static final String LOAD_FILTER = "load_filter";
public static final String OPEN_TASK = "open_task"; //$NON-NLS-1$ public static final String OPEN_TASK = "open_task"; // $NON-NLS-1$
public static final String OPEN_NEW_TASK = "open_new_task"; //$NON-NLS-1$ public static final String OPEN_NEW_TASK = "open_new_task"; // $NON-NLS-1$
private static final String FRAG_TAG_TASK_LIST = "frag_tag_task_list"; private static final String FRAG_TAG_TASK_LIST = "frag_tag_task_list";
@Inject Preferences preferences; @Inject Preferences preferences;
@Inject SubtasksHelper subtasksHelper; @Inject SubtasksHelper subtasksHelper;
@ -107,9 +105,16 @@ public class TaskListActivity extends InjectingAppCompatActivity implements
@Inject TaskDao taskDao; @Inject TaskDao taskDao;
@Inject CaldavDao caldavDao; @Inject CaldavDao caldavDao;
@Inject LocalBroadcastManager localBroadcastManager; @Inject LocalBroadcastManager localBroadcastManager;
@BindView(R.id.drawer_layout) DrawerLayout drawerLayout;
@BindView(R.id.master) FrameLayout master; @BindView(R.id.drawer_layout)
@BindView(R.id.detail) FrameLayout detail; DrawerLayout drawerLayout;
@BindView(R.id.master)
FrameLayout master;
@BindView(R.id.detail)
FrameLayout detail;
private NavigationDrawerFragment navigationDrawer; private NavigationDrawerFragment navigationDrawer;
private TaskListViewModel viewModel; private TaskListViewModel viewModel;
private int currentNightMode; private int currentNightMode;
@ -117,9 +122,7 @@ public class TaskListActivity extends InjectingAppCompatActivity implements
private Filter filter; private Filter filter;
private ActionMode actionMode = null; private ActionMode actionMode = null;
/** /** @see android.app.Activity#onCreate(Bundle) */
* @see android.app.Activity#onCreate(Bundle)
*/
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -137,7 +140,8 @@ public class TaskListActivity extends InjectingAppCompatActivity implements
navigationDrawer = getNavigationDrawerFragment(); navigationDrawer = getNavigationDrawerFragment();
navigationDrawer.setUp(drawerLayout); navigationDrawer.setUp(drawerLayout);
drawerLayout.addDrawerListener(new DrawerLayout.SimpleDrawerListener() { drawerLayout.addDrawerListener(
new DrawerLayout.SimpleDrawerListener() {
@Override @Override
public void onDrawerStateChanged(int newState) { public void onDrawerStateChanged(int newState) {
finishActionMode(); finishActionMode();
@ -162,8 +166,10 @@ public class TaskListActivity extends InjectingAppCompatActivity implements
TaskEditFragment taskEditFragment = getTaskEditFragment(); TaskEditFragment taskEditFragment = getTaskEditFragment();
if (taskEditFragment == null) { if (taskEditFragment == null) {
hideDetailFragment(); hideDetailFragment();
} else if (intent.hasExtra(OPEN_FILTER) || intent.hasExtra(LOAD_FILTER) || intent } else if (intent.hasExtra(OPEN_FILTER)
.hasExtra(OPEN_TASK) || intent.hasExtra(OPEN_NEW_TASK)) { || intent.hasExtra(LOAD_FILTER)
|| intent.hasExtra(OPEN_TASK)
|| intent.hasExtra(OPEN_NEW_TASK)) {
taskEditFragment.save(); taskEditFragment.save();
taskEditFinished(); taskEditFinished();
} else { } else {
@ -176,8 +182,8 @@ public class TaskListActivity extends InjectingAppCompatActivity implements
intent.removeExtra(OPEN_FILTER); intent.removeExtra(OPEN_FILTER);
loadTaskListFragment(filter); loadTaskListFragment(filter);
} else if (intent.hasExtra(LOAD_FILTER)) { } else if (intent.hasExtra(LOAD_FILTER)) {
Filter filter = defaultFilterProvider Filter filter =
.getFilterFromPreference(intent.getStringExtra(LOAD_FILTER)); defaultFilterProvider.getFilterFromPreference(intent.getStringExtra(LOAD_FILTER));
intent.removeExtra(LOAD_FILTER); intent.removeExtra(LOAD_FILTER);
loadTaskListFragment(filter); loadTaskListFragment(filter);
} else if (taskListFragment == null) { } else if (taskListFragment == null) {
@ -196,7 +202,8 @@ public class TaskListActivity extends InjectingAppCompatActivity implements
private void hideDetailFragment() { private void hideDetailFragment() {
if (isDoublePaneLayout()) { if (isDoublePaneLayout()) {
getSupportFragmentManager().beginTransaction() getSupportFragmentManager()
.beginTransaction()
.replace(R.id.detail, new EmptyTaskEditFragment()) .replace(R.id.detail, new EmptyTaskEditFragment())
.commit(); .commit();
} else { } else {
@ -218,7 +225,8 @@ public class TaskListActivity extends InjectingAppCompatActivity implements
navigationDrawer.setSelected(filter); navigationDrawer.setSelected(filter);
FragmentManager fragmentManager = getSupportFragmentManager(); FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction() fragmentManager
.beginTransaction()
.replace(R.id.master, taskListFragment, FRAG_TAG_TASK_LIST) .replace(R.id.master, taskListFragment, FRAG_TAG_TASK_LIST)
.commit(); .commit();
} }
@ -253,7 +261,8 @@ public class TaskListActivity extends InjectingAppCompatActivity implements
} }
private NavigationDrawerFragment getNavigationDrawerFragment() { private NavigationDrawerFragment getNavigationDrawerFragment() {
return (NavigationDrawerFragment) getSupportFragmentManager() return (NavigationDrawerFragment)
getSupportFragmentManager()
.findFragmentById(NavigationDrawerFragment.FRAGMENT_NAVIGATION_DRAWER); .findFragmentById(NavigationDrawerFragment.FRAGMENT_NAVIGATION_DRAWER);
} }
@ -422,13 +431,12 @@ public class TaskListActivity extends InjectingAppCompatActivity implements
} }
public TaskListFragment getTaskListFragment() { public TaskListFragment getTaskListFragment() {
return (TaskListFragment) getSupportFragmentManager() return (TaskListFragment) getSupportFragmentManager().findFragmentByTag(FRAG_TAG_TASK_LIST);
.findFragmentByTag(FRAG_TAG_TASK_LIST);
} }
public TaskEditFragment getTaskEditFragment() { public TaskEditFragment getTaskEditFragment() {
return (TaskEditFragment) getSupportFragmentManager() return (TaskEditFragment)
.findFragmentByTag(TaskEditFragment.TAG_TASKEDIT_FRAGMENT); getSupportFragmentManager().findFragmentByTag(TaskEditFragment.TAG_TASKEDIT_FRAGMENT);
} }
@Override @Override
@ -457,8 +465,9 @@ public class TaskListActivity extends InjectingAppCompatActivity implements
@Override @Override
public void taskEditFinished() { public void taskEditFinished() {
getSupportFragmentManager().popBackStackImmediate(TaskEditFragment.TAG_TASKEDIT_FRAGMENT, getSupportFragmentManager()
FragmentManager.POP_BACK_STACK_INCLUSIVE); .popBackStackImmediate(
TaskEditFragment.TAG_TASKEDIT_FRAGMENT, FragmentManager.POP_BACK_STACK_INCLUSIVE);
hideDetailFragment(); hideDetailFragment();
hideKeyboard(); hideKeyboard();
getTaskListFragment().loadTaskListContent(); getTaskListFragment().loadTaskListContent();
@ -467,8 +476,8 @@ public class TaskListActivity extends InjectingAppCompatActivity implements
private void hideKeyboard() { private void hideKeyboard() {
View view = getCurrentFocus(); View view = getCurrentFocus();
if (view != null) { if (view != null) {
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService( InputMethodManager inputMethodManager =
INPUT_METHOD_SERVICE); (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
} }
} }

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.activity; package com.todoroo.astrid.activity;
import static android.support.v4.content.ContextCompat.getColor; import static android.support.v4.content.ContextCompat.getColor;
@ -70,17 +69,16 @@ import org.tasks.ui.ProgressDialogAsyncTask;
import org.tasks.ui.TaskListViewModel; import org.tasks.ui.TaskListViewModel;
/** /**
* Primary activity for the Bente application. Shows a list of upcoming tasks * Primary activity for the Bente application. Shows a list of upcoming tasks and a user's coaches.
* and a user's coaches.
* *
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
*/ */
public class TaskListFragment extends InjectingFragment implements public class TaskListFragment extends InjectingFragment
SwipeRefreshLayout.OnRefreshListener, Toolbar.OnMenuItemClickListener { implements SwipeRefreshLayout.OnRefreshListener, Toolbar.OnMenuItemClickListener {
public static final String TAGS_METADATA_JOIN = "for_tags"; // $NON-NLS-1$
public static final String FILE_METADATA_JOIN = "for_actions"; // $NON-NLS-1$
private static final int VOICE_RECOGNITION_REQUEST_CODE = 1234; private static final int VOICE_RECOGNITION_REQUEST_CODE = 1234;
public static final String TAGS_METADATA_JOIN = "for_tags"; //$NON-NLS-1$
public static final String FILE_METADATA_JOIN = "for_actions"; //$NON-NLS-1$
private static final String EXTRA_FILTER = "extra_filter"; private static final String EXTRA_FILTER = "extra_filter";
private static final String FRAG_TAG_SORT_DIALOG = "frag_tag_sort_dialog"; private static final String FRAG_TAG_SORT_DIALOG = "frag_tag_sort_dialog";
@ -102,11 +100,22 @@ public class TaskListFragment extends InjectingFragment implements
@Inject ViewHolderFactory viewHolderFactory; @Inject ViewHolderFactory viewHolderFactory;
@Inject LocalBroadcastManager localBroadcastManager; @Inject LocalBroadcastManager localBroadcastManager;
@Inject Device device; @Inject Device device;
@BindView(R.id.swipe_layout) SwipeRefreshLayout swipeRefreshLayout;
@BindView(R.id.swipe_layout_empty) SwipeRefreshLayout emptyRefreshLayout; @BindView(R.id.swipe_layout)
@BindView(R.id.toolbar) Toolbar toolbar; SwipeRefreshLayout swipeRefreshLayout;
@BindView(R.id.task_list_coordinator) CoordinatorLayout coordinatorLayout;
@BindView(R.id.recycler_view) RecyclerView recyclerView; @BindView(R.id.swipe_layout_empty)
SwipeRefreshLayout emptyRefreshLayout;
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.task_list_coordinator)
CoordinatorLayout coordinatorLayout;
@BindView(R.id.recycler_view)
RecyclerView recyclerView;
private TaskListViewModel taskListViewModel; private TaskListViewModel taskListViewModel;
private TaskAdapter taskAdapter = null; private TaskAdapter taskAdapter = null;
private TaskListRecyclerAdapter recyclerAdapter; private TaskListRecyclerAdapter recyclerAdapter;
@ -134,7 +143,8 @@ public class TaskListFragment extends InjectingFragment implements
protected void setSyncOngoing(final boolean ongoing) { protected void setSyncOngoing(final boolean ongoing) {
Activity activity = getActivity(); Activity activity = getActivity();
if (activity != null) { if (activity != null) {
activity.runOnUiThread(() -> { activity.runOnUiThread(
() -> {
swipeRefreshLayout.setRefreshing(ongoing); swipeRefreshLayout.setRefreshing(ongoing);
emptyRefreshLayout.setRefreshing(ongoing); emptyRefreshLayout.setRefreshing(ongoing);
}); });
@ -164,9 +174,7 @@ public class TaskListFragment extends InjectingFragment implements
component.inject(this); component.inject(this);
} }
/** /** Called when loading up the activity */
* Called when loading up the activity
*/
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -193,8 +201,8 @@ public class TaskListFragment extends InjectingFragment implements
} }
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(
Bundle savedInstanceState) { LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View parent = inflater.inflate(R.layout.fragment_task_list, container, false); View parent = inflater.inflate(R.layout.fragment_task_list, container, false);
ButterKnife.bind(this, parent); ButterKnife.bind(this, parent);
setupRefresh(swipeRefreshLayout); setupRefresh(swipeRefreshLayout);
@ -237,13 +245,18 @@ public class TaskListFragment extends InjectingFragment implements
menu.findItem(R.id.menu_voice_add).setVisible(device.voiceInputAvailable()); menu.findItem(R.id.menu_voice_add).setVisible(device.voiceInputAvailable());
final MenuItem item = menu.findItem(R.id.menu_search); final MenuItem item = menu.findItem(R.id.menu_search);
final SearchView actionView = (SearchView) MenuItemCompat.getActionView(item); final SearchView actionView = (SearchView) MenuItemCompat.getActionView(item);
actionView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { actionView.setOnQueryTextListener(
new SearchView.OnQueryTextListener() {
@Override @Override
public boolean onQueryTextSubmit(String query) { public boolean onQueryTextSubmit(String query) {
query = query.trim(); query = query.trim();
String title = getString(R.string.FLA_search_filter, query); String title = getString(R.string.FLA_search_filter, query);
Filter savedFilter = new Filter(title, Filter savedFilter =
new QueryTemplate().where(Criterion.and( new Filter(
title,
new QueryTemplate()
.where(
Criterion.and(
Task.DELETION_DATE.eq(0), Task.DELETION_DATE.eq(0),
Criterion.or( Criterion.or(
Task.NOTES.like("%" + query + "%"), Task.NOTES.like("%" + query + "%"),
@ -265,11 +278,11 @@ public class TaskListFragment extends InjectingFragment implements
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.menu_voice_add: case R.id.menu_voice_add:
Intent recognition = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); Intent recognition = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
recognition.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, recognition.putExtra(
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
recognition.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); recognition.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1);
recognition recognition.putExtra(
.putExtra(RecognizerIntent.EXTRA_PROMPT, getString(R.string.voice_create_prompt)); RecognizerIntent.EXTRA_PROMPT, getString(R.string.voice_create_prompt));
startActivityForResult(recognition, TaskListFragment.VOICE_RECOGNITION_REQUEST_CODE); startActivityForResult(recognition, TaskListFragment.VOICE_RECOGNITION_REQUEST_CODE);
return true; return true;
case R.id.menu_sort: case R.id.menu_sort:
@ -294,7 +307,8 @@ public class TaskListFragment extends InjectingFragment implements
startActivityForResult(intent, REQUEST_EDIT_FILTER); startActivityForResult(intent, REQUEST_EDIT_FILTER);
return true; return true;
case R.id.menu_clear_completed: case R.id.menu_clear_completed:
dialogBuilder.newMessageDialog(R.string.clear_completed_tasks_confirmation) dialogBuilder
.newMessageDialog(R.string.clear_completed_tasks_confirmation)
.setPositiveButton(android.R.string.ok, (dialog, which) -> clearCompleted()) .setPositiveButton(android.R.string.ok, (dialog, which) -> clearCompleted())
.setNegativeButton(android.R.string.cancel, null) .setNegativeButton(android.R.string.cancel, null)
.show(); .show();
@ -337,7 +351,11 @@ public class TaskListFragment extends InjectingFragment implements
public void onActivityCreated(Bundle savedInstanceState) { public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
taskListViewModel.getTasks(filter, taskProperties()).observe(getActivity(), list -> { taskListViewModel
.getTasks(filter, taskProperties())
.observe(
getActivity(),
list -> {
if (list.isEmpty()) { if (list.isEmpty()) {
swipeRefreshLayout.setVisibility(View.GONE); swipeRefreshLayout.setVisibility(View.GONE);
emptyRefreshLayout.setVisibility(View.VISIBLE); emptyRefreshLayout.setVisibility(View.VISIBLE);
@ -369,7 +387,8 @@ public class TaskListFragment extends InjectingFragment implements
} }
public Snackbar makeSnackbar(String text) { public Snackbar makeSnackbar(String text) {
Snackbar snackbar = Snackbar.make(coordinatorLayout, text, 8000) Snackbar snackbar =
Snackbar.make(coordinatorLayout, text, 8000)
.setActionTextColor(getColor(context, R.color.snackbar_text_color)); .setActionTextColor(getColor(context, R.color.snackbar_text_color));
snackbar.getView().setBackgroundColor(getColor(context, R.color.snackbar_background)); snackbar.getView().setBackgroundColor(getColor(context, R.color.snackbar_background));
return snackbar; return snackbar;
@ -383,8 +402,8 @@ public class TaskListFragment extends InjectingFragment implements
} }
/** /**
* Called by the RefreshReceiver when the task list receives a refresh * Called by the RefreshReceiver when the task list receives a refresh broadcast. Subclasses
* broadcast. Subclasses should override this. * should override this.
*/ */
private void refresh() { private void refresh() {
// TODO: compare indents in diff callback, then animate this // TODO: compare indents in diff callback, then animate this
@ -413,9 +432,7 @@ public class TaskListFragment extends InjectingFragment implements
return new TaskAdapter(); return new TaskAdapter();
} }
/** /** Fill in the Task List with current items */
* Fill in the Task List with current items
*/
protected void setTaskAdapter() { protected void setTaskAdapter() {
if (filter == null) { if (filter == null) {
return; return;
@ -423,8 +440,16 @@ public class TaskListFragment extends InjectingFragment implements
// set up list adapters // set up list adapters
taskAdapter = createTaskAdapter(); taskAdapter = createTaskAdapter();
recyclerAdapter = new TaskListRecyclerAdapter(getActivity(), taskAdapter, viewHolderFactory, recyclerAdapter =
this, taskDeleter, taskDuplicator, tracker, dialogBuilder); new TaskListRecyclerAdapter(
getActivity(),
taskAdapter,
viewHolderFactory,
this,
taskDeleter,
taskDuplicator,
tracker,
dialogBuilder);
taskAdapter.setHelper(recyclerAdapter.getHelper()); taskAdapter.setHelper(recyclerAdapter.getHelper());
} }
@ -443,8 +468,7 @@ public class TaskListFragment extends InjectingFragment implements
syncAdapters.syncNow(); syncAdapters.syncNow();
} }
public void onTaskCreated(String uuid) { public void onTaskCreated(String uuid) {}
}
/* /*
* ====================================================================== * ======================================================================
@ -476,8 +500,9 @@ public class TaskListFragment extends InjectingFragment implements
List<String> match = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); List<String> match = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
if (match != null && match.size() > 0 && match.get(0).length() > 0) { if (match != null && match.size() > 0 && match.get(0).length() > 0) {
String recognizedSpeech = match.get(0); String recognizedSpeech = match.get(0);
recognizedSpeech = recognizedSpeech.substring(0, 1).toUpperCase() + recognizedSpeech =
recognizedSpeech.substring(1).toLowerCase(); recognizedSpeech.substring(0, 1).toUpperCase()
+ recognizedSpeech.substring(1).toLowerCase();
onTaskListItemClicked(addTask(recognizedSpeech)); onTaskListItemClicked(addTask(recognizedSpeech));
} }
@ -489,7 +514,10 @@ public class TaskListFragment extends InjectingFragment implements
if (FilterSettingsActivity.ACTION_FILTER_DELETED.equals(action)) { if (FilterSettingsActivity.ACTION_FILTER_DELETED.equals(action)) {
activity.onFilterItemClicked(null); activity.onFilterItemClicked(null);
} else if (FilterSettingsActivity.ACTION_FILTER_RENAMED.equals(action)) { } else if (FilterSettingsActivity.ACTION_FILTER_RENAMED.equals(action)) {
activity.getIntent().putExtra(TaskListActivity.OPEN_FILTER, activity
.getIntent()
.putExtra(
TaskListActivity.OPEN_FILTER,
(Filter) data.getParcelableExtra(FilterSettingsActivity.TOKEN_FILTER)); (Filter) data.getParcelableExtra(FilterSettingsActivity.TOKEN_FILTER));
activity.recreate(); activity.recreate();
} }
@ -509,13 +537,13 @@ public class TaskListFragment extends InjectingFragment implements
} }
protected boolean hasDraggableOption() { protected boolean hasDraggableOption() {
return BuiltInFilterExposer.isInbox(context, filter) || BuiltInFilterExposer return BuiltInFilterExposer.isInbox(context, filter)
.isTodayFilter(context, filter); || BuiltInFilterExposer.isTodayFilter(context, filter);
} }
/** /**
* Container Activity must implement this interface and we ensure that it * Container Activity must implement this interface and we ensure that it does during the
* does during the onAttach() callback * onAttach() callback
*/ */
public interface TaskListFragmentCallbackHandler { public interface TaskListFragmentCallbackHandler {

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.adapter; package com.todoroo.astrid.adapter;
import static android.support.v4.content.ContextCompat.getColor; import static android.support.v4.content.ContextCompat.getColor;
@ -71,9 +70,14 @@ public class FilterAdapter extends ArrayAdapter<FilterListItem> {
private Filter selected; private Filter selected;
@Inject @Inject
public FilterAdapter(FilterProvider filterProvider, FilterCounter filterCounter, public FilterAdapter(
FilterProvider filterProvider,
FilterCounter filterCounter,
Activity activity, Activity activity,
Theme theme, ThemeCache themeCache, Locale locale, Preferences preferences) { Theme theme,
ThemeCache themeCache,
Locale locale,
Preferences preferences) {
super(activity, 0); super(activity, 0);
this.filterProvider = filterProvider; this.filterProvider = filterProvider;
this.filterCounter = filterCounter; this.filterCounter = filterCounter;
@ -118,9 +122,7 @@ public class FilterAdapter extends ArrayAdapter<FilterListItem> {
filterCounter.refreshFilterCounts(this::notifyDataSetChanged); filterCounter.refreshFilterCounts(this::notifyDataSetChanged);
} }
/** /** Create or reuse a view */
* Create or reuse a view
*/
private View newView(View convertView, ViewGroup parent, FilterListItem.Type viewType) { private View newView(View convertView, ViewGroup parent, FilterListItem.Type viewType) {
if (convertView == null) { if (convertView == null) {
ViewHolder viewHolder = new ViewHolder(); ViewHolder viewHolder = new ViewHolder();
@ -131,11 +133,17 @@ public class FilterAdapter extends ArrayAdapter<FilterListItem> {
if (navigationDrawer) { if (navigationDrawer) {
viewHolder.name.setCheckMarkDrawable(null); viewHolder.name.setCheckMarkDrawable(null);
} else if (preLollipop()) { } else if (preLollipop()) {
ColorStateList tintList = new ColorStateList(new int[][]{ ColorStateList tintList =
new int[]{-android.R.attr.state_checked}, new int[]{android.R.attr.state_checked}}, new ColorStateList(
new int[]{ new int[][] {
ResourcesCompat.getColor(activity.getResources(), android.R.color.transparent, new int[] {-android.R.attr.state_checked},
null), theme.getThemeAccent().getAccentColor()}); new int[] {android.R.attr.state_checked}
},
new int[] {
ResourcesCompat.getColor(
activity.getResources(), android.R.color.transparent, null),
theme.getThemeAccent().getAccentColor()
});
Drawable original = ContextCompat.getDrawable(activity, R.drawable.ic_check_black_24dp); Drawable original = ContextCompat.getDrawable(activity, R.drawable.ic_check_black_24dp);
Drawable wrapped = DrawableCompat.wrap(original.mutate()); Drawable wrapped = DrawableCompat.wrap(original.mutate());
DrawableCompat.setTintList(wrapped, tintList); DrawableCompat.setTintList(wrapped, tintList);
@ -264,7 +272,8 @@ public class FilterAdapter extends ArrayAdapter<FilterListItem> {
addSubMenu(R.string.filters, filterProvider.getFilters(), false); addSubMenu(R.string.filters, filterProvider.getFilters(), false);
if (navigationDrawer) { if (navigationDrawer) {
add(new NavigationDrawerAction( add(
new NavigationDrawerAction(
activity.getResources().getString(R.string.FLA_new_filter), activity.getResources().getString(R.string.FLA_new_filter),
R.drawable.ic_add_24dp, R.drawable.ic_add_24dp,
new Intent(activity, CustomFilterActivity.class), new Intent(activity, CustomFilterActivity.class),
@ -274,7 +283,8 @@ public class FilterAdapter extends ArrayAdapter<FilterListItem> {
addSubMenu(R.string.tags, filterProvider.getTags(), false); addSubMenu(R.string.tags, filterProvider.getTags(), false);
if (navigationDrawer) { if (navigationDrawer) {
add(new NavigationDrawerAction( add(
new NavigationDrawerAction(
activity.getResources().getString(R.string.new_tag), activity.getResources().getString(R.string.new_tag),
R.drawable.ic_add_24dp, R.drawable.ic_add_24dp,
new Intent(activity, TagSettingsActivity.class), new Intent(activity, TagSettingsActivity.class),
@ -290,7 +300,8 @@ public class FilterAdapter extends ArrayAdapter<FilterListItem> {
addSubMenu(title, googleTaskFilters, true); addSubMenu(title, googleTaskFilters, true);
if (navigationDrawer) { if (navigationDrawer) {
add(new NavigationDrawerAction( add(
new NavigationDrawerAction(
activity.getResources().getString(R.string.new_list), activity.getResources().getString(R.string.new_list),
R.drawable.ic_add_24dp, R.drawable.ic_add_24dp,
new Intent(activity, GoogleTaskListSettingsActivity.class), new Intent(activity, GoogleTaskListSettingsActivity.class),
@ -302,7 +313,8 @@ public class FilterAdapter extends ArrayAdapter<FilterListItem> {
addSubMenu(R.string.CalDAV, filterProvider.getCaldavFilters(), false); addSubMenu(R.string.CalDAV, filterProvider.getCaldavFilters(), false);
if (navigationDrawer) { if (navigationDrawer) {
add(new NavigationDrawerAction( add(
new NavigationDrawerAction(
activity.getResources().getString(R.string.add_account), activity.getResources().getString(R.string.add_account),
R.drawable.ic_add_24dp, R.drawable.ic_add_24dp,
new Intent(activity, CaldavSettingsActivity.class), new Intent(activity, CaldavSettingsActivity.class),
@ -313,12 +325,14 @@ public class FilterAdapter extends ArrayAdapter<FilterListItem> {
if (navigationDrawer) { if (navigationDrawer) {
add(new NavigationDrawerSeparator()); add(new NavigationDrawerSeparator());
add(new NavigationDrawerAction( add(
new NavigationDrawerAction(
activity.getResources().getString(R.string.TLA_menu_settings), activity.getResources().getString(R.string.TLA_menu_settings),
R.drawable.ic_settings_24dp, R.drawable.ic_settings_24dp,
new Intent(activity, BasicPreferences.class), new Intent(activity, BasicPreferences.class),
REQUEST_SETTINGS)); REQUEST_SETTINGS));
add(new NavigationDrawerAction( add(
new NavigationDrawerAction(
activity.getResources().getString(R.string.help_and_feedback), activity.getResources().getString(R.string.help_and_feedback),
R.drawable.ic_help_24dp, R.drawable.ic_help_24dp,
new Intent(activity, HelpAndFeedbackActivity.class), new Intent(activity, HelpAndFeedbackActivity.class),
@ -343,7 +357,8 @@ public class FilterAdapter extends ArrayAdapter<FilterListItem> {
} }
viewHolder.icon.setImageResource(filter.icon); viewHolder.icon.setImageResource(filter.icon);
viewHolder.icon.setColorFilter(filter.tint >= 0 viewHolder.icon.setColorFilter(
filter.tint >= 0
? themeCache.getThemeColor(filter.tint).getPrimaryColor() ? themeCache.getThemeColor(filter.tint).getPrimaryColor()
: getColor(activity, R.color.text_primary)); : getColor(activity, R.color.text_primary));

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.adapter; package com.todoroo.astrid.adapter;
import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Lists.newArrayList;
@ -28,19 +27,26 @@ import org.tasks.data.TaskAttachment;
*/ */
public class TaskAdapter { public class TaskAdapter {
private static final StringProperty TAGS = new StringProperty(null, private static final StringProperty TAGS =
"group_concat(nullif(" + TaskListFragment.TAGS_METADATA_JOIN + ".tag_uid, '')" + ", ',')") new StringProperty(
null,
"group_concat(nullif("
+ TaskListFragment.TAGS_METADATA_JOIN
+ ".tag_uid, '')"
+ ", ',')")
.as("tags"); .as("tags");
private static final LongProperty FILE_ID_PROPERTY = TaskAttachment.ID private static final LongProperty FILE_ID_PROPERTY =
.cloneAs(TaskListFragment.FILE_METADATA_JOIN, "fileId"); TaskAttachment.ID.cloneAs(TaskListFragment.FILE_METADATA_JOIN, "fileId");
public static final Property<?>[] PROPERTIES = ObjectArrays.concat( public static final Property<?>[] PROPERTIES =
ObjectArrays.concat(
Task.PROPERTIES, Task.PROPERTIES,
new Property<?>[]{ new Property<?>[] {
TAGS, // Concatenated list of tags TAGS, // Concatenated list of tags
FILE_ID_PROPERTY // File id FILE_ID_PROPERTY // File id
}, Property.class); },
private AsyncPagedListDiffer<Task> helper; Property.class);
private final Set<Long> selected = new HashSet<>(); private final Set<Long> selected = new HashSet<>();
private AsyncPagedListDiffer<Task> helper;
private OnCompletedTaskListener onCompletedTaskListener = null; private OnCompletedTaskListener onCompletedTaskListener = null;
public int getCount() { public int getCount() {
@ -89,13 +95,9 @@ public class TaskAdapter {
return false; return false;
} }
public void moved(int from, int to) { public void moved(int from, int to) {}
} public void indented(int position, int delta) {}
public void indented(int position, int delta) {
}
public long getTaskId(int position) { public long getTaskId(int position) {
return getTask(position).getId(); return getTask(position).getId();

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.alarms; package com.todoroo.astrid.alarms;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
@ -91,27 +90,21 @@ public class AlarmService {
return alarmDao.getActiveAlarms(taskId); return alarmDao.getActiveAlarms(taskId);
} }
/** /** Schedules all alarms */
* Schedules all alarms
*/
public void scheduleAllAlarms() { public void scheduleAllAlarms() {
for (Alarm alarm : getActiveAlarms()) { for (Alarm alarm : getActiveAlarms()) {
scheduleAlarm(alarm); scheduleAlarm(alarm);
} }
} }
/** /** Schedules alarms for a single task */
* Schedules alarms for a single task
*/
private void scheduleAlarms(long taskId) { private void scheduleAlarms(long taskId) {
for (Alarm alarm : getActiveAlarmsForTask(taskId)) { for (Alarm alarm : getActiveAlarmsForTask(taskId)) {
scheduleAlarm(alarm); scheduleAlarm(alarm);
} }
} }
/** /** Schedules alarms for a single task */
* Schedules alarms for a single task
*/
private void scheduleAlarm(Alarm alarm) { private void scheduleAlarm(Alarm alarm) {
if (alarm == null) { if (alarm == null) {
return; return;

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.api; package com.todoroo.astrid.api;
/** /**
@ -13,23 +12,15 @@ package com.todoroo.astrid.api;
*/ */
public class AstridApiConstants { public class AstridApiConstants {
/** /** Name of Astrid's publicly readable preference store */
* Name of Astrid's publicly readable preference store
*/
public static final String PUBLIC_PREFS = "public"; public static final String PUBLIC_PREFS = "public";
/** /** Extras name for task id */
* Extras name for task id
*/
public static final String EXTRAS_TASK_ID = "task_id"; public static final String EXTRAS_TASK_ID = "task_id";
/** /** Extras name for old task due date */
* Extras name for old task due date
*/
public static final String EXTRAS_OLD_DUE_DATE = "oldDueDate"; public static final String EXTRAS_OLD_DUE_DATE = "oldDueDate";
/** /** Extras name for new task due date */
* Extras name for new task due date
*/
public static final String EXTRAS_NEW_DUE_DATE = "newDueDate"; public static final String EXTRAS_NEW_DUE_DATE = "newDueDate";
} }

@ -15,14 +15,11 @@ import org.tasks.data.CaldavTask;
public class CaldavFilter extends Filter { public class CaldavFilter extends Filter {
/** /** Parcelable Creator Object */
* Parcelable Creator Object public static final Creator<CaldavFilter> CREATOR =
*/ new Creator<CaldavFilter>() {
public static final Creator<CaldavFilter> CREATOR = new Creator<CaldavFilter>() {
/** /** {@inheritDoc} */
* {@inheritDoc}
*/
@Override @Override
public CaldavFilter createFromParcel(Parcel source) { public CaldavFilter createFromParcel(Parcel source) {
CaldavFilter item = new CaldavFilter(); CaldavFilter item = new CaldavFilter();
@ -30,15 +27,13 @@ public class CaldavFilter extends Filter {
return item; return item;
} }
/** /** {@inheritDoc} */
* {@inheritDoc}
*/
@Override @Override
public CaldavFilter[] newArray(int size) { public CaldavFilter[] newArray(int size) {
return new CaldavFilter[size]; return new CaldavFilter[size];
} }
}; };
private static final int TAG = R.drawable.ic_cloud_black_24dp; private static final int TAG = R.drawable.ic_cloud_black_24dp;
private CaldavAccount account; private CaldavAccount account;
@ -56,7 +51,8 @@ public class CaldavFilter extends Filter {
private static QueryTemplate queryTemplate(CaldavAccount caldavAccount) { private static QueryTemplate queryTemplate(CaldavAccount caldavAccount) {
return new QueryTemplate() return new QueryTemplate()
.join(Join.left(CaldavTask.TABLE, Task.ID.eq(Field.field("caldav_tasks.task")))) .join(Join.left(CaldavTask.TABLE, Task.ID.eq(Field.field("caldav_tasks.task"))))
.where(Criterion.and( .where(
Criterion.and(
TaskDao.TaskCriteria.activeAndVisible(), TaskDao.TaskCriteria.activeAndVisible(),
Field.field("account").eq(caldavAccount.getUuid()))); Field.field("account").eq(caldavAccount.getUuid())));
} }
@ -71,9 +67,7 @@ public class CaldavFilter extends Filter {
return account.getUuid(); return account.getUuid();
} }
/** /** {@inheritDoc} */
* {@inheritDoc}
*/
@Override @Override
public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags); super.writeToParcel(dest, flags);

@ -8,32 +8,28 @@ import java.util.Map;
public class CustomFilter extends Filter { public class CustomFilter extends Filter {
/** /** Parcelable Creator Object */
* Parcelable Creator Object public static final Parcelable.Creator<CustomFilter> CREATOR =
*/ new Parcelable.Creator<CustomFilter>() {
public static final Parcelable.Creator<CustomFilter> CREATOR = new Parcelable.Creator<CustomFilter>() {
/** /** {@inheritDoc} */
* {@inheritDoc}
*/
@Override @Override
public CustomFilter createFromParcel(Parcel source) { public CustomFilter createFromParcel(Parcel source) {
return new CustomFilter(source); return new CustomFilter(source);
} }
/** /** {@inheritDoc} */
* {@inheritDoc}
*/
@Override @Override
public CustomFilter[] newArray(int size) { public CustomFilter[] newArray(int size) {
return new CustomFilter[size]; return new CustomFilter[size];
} }
}; };
private long id; private long id;
private String criterion; private String criterion;
public CustomFilter(String listingTitle, String sql, Map<String, Object> values, long id, public CustomFilter(
String criterion) { String listingTitle, String sql, Map<String, Object> values, long id, String criterion) {
super(listingTitle, sql, values); super(listingTitle, sql, values);
this.id = id; this.id = id;
this.criterion = criterion; this.criterion = criterion;
@ -59,9 +55,7 @@ public class CustomFilter extends Filter {
return id; return id;
} }
/** /** {@inheritDoc} */
* {@inheritDoc}
*/
@Override @Override
public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags); super.writeToParcel(dest, flags);

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.api; package com.todoroo.astrid.api;
import android.graphics.Bitmap; import android.graphics.Bitmap;
@ -13,59 +12,51 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* CustomFilterCriteria allow users to build a custom filter by chaining * CustomFilterCriteria allow users to build a custom filter by chaining together criteria
* together criteria
* *
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
*/ */
abstract public class CustomFilterCriterion implements Parcelable { public abstract class CustomFilterCriterion implements Parcelable {
/** /**
* Values to apply to a task when quick-adding a task from a filter * Values to apply to a task when quick-adding a task from a filter created from this criterion. ?
* created from this criterion. ? will be replaced with the entry value. * will be replaced with the entry value. For example, when a user views tasks tagged 'ABC', the
* For example, when a user views tasks tagged 'ABC', the * tasks they create should also be tagged 'ABC'. If set to null, no additional values will be
* tasks they create should also be tagged 'ABC'. If set to null, no * stored for a task.
* additional values will be stored for a task.
*/ */
public final Map<String, Object> valuesForNewTasks = new HashMap<>(); public final Map<String, Object> valuesForNewTasks = new HashMap<>();
/** /**
* Criteria Identifier. This identifier allows saved filters to be reloaded. * Criteria Identifier. This identifier allows saved filters to be reloaded.
* <p> *
* e.g "duedate" * <p>e.g "duedate"
*/ */
public String identifier; public String identifier;
/** /**
* Criteria Title. If the title contains ?, this is replaced by the entry * Criteria Title. If the title contains ?, this is replaced by the entry label string selected.
* label string selected. *
* <p> * <p>e.g "Due: ?"
* e.g "Due: ?"
*/ */
public String text; public String text;
/** /**
* Criterion SQL. This query should return task id's. If this contains * Criterion SQL. This query should return task id's. If this contains ?, it will be replaced by
* ?, it will be replaced by the entry value * the entry value
* <p> *
* Examples: * <p>Examples:
*
* <ul> * <ul>
* <li><code>SELECT _id FROM tasks WHERE dueDate <= ?</code> * <li><code>SELECT _id FROM tasks WHERE dueDate <= ?</code>
* <li><code>SELECT task FROM metadata WHERE value = '?'</code> * <li><code>SELECT task FROM metadata WHERE value = '?'</code>
* </ul> * </ul>
*/ */
public String sql; public String sql;
/** /** Criteria name. This is displayed when users are selecting a criteria */
* Criteria name. This is displayed when users are selecting a criteria
*/
public String name; public String name;
/** /** Icon for this criteria. Can be null for no bitmap */
* Icon for this criteria. Can be null for no bitmap
*/
Bitmap icon; Bitmap icon;
// --- parcelable utilities // --- parcelable utilities
/** /** Utility method to write to parcel */
* Utility method to write to parcel
*/
void writeToParcel(Parcel dest) { void writeToParcel(Parcel dest) {
dest.writeString(identifier); dest.writeString(identifier);
dest.writeString(text); dest.writeString(text);
@ -75,9 +66,7 @@ abstract public class CustomFilterCriterion implements Parcelable {
dest.writeString(name); dest.writeString(name);
} }
/** /** Utility method to read from parcel */
* Utility method to read from parcel
*/
void readFromParcel(Parcel source) { void readFromParcel(Parcel source) {
identifier = source.readString(); identifier = source.readString();
text = source.readString(); text = source.readString();

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.api; package com.todoroo.astrid.api;
import android.os.Parcel; import android.os.Parcel;
@ -14,25 +13,20 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* A <code>FilterListFilter</code> allows users to display tasks that have * A <code>FilterListFilter</code> allows users to display tasks that have something in common.
* something in common. *
* <p> * <p>A plug-in can expose new <code>FilterListFilter</code>s to the system by responding to the
* A plug-in can expose new <code>FilterListFilter</code>s to the system by * <code>com.todoroo.astrid.GET_FILTERS</code> broadcast intent.
* responding to the <code>com.todoroo.astrid.GET_FILTERS</code> broadcast
* intent.
* *
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
*/ */
public class Filter extends FilterListItem { public class Filter extends FilterListItem {
/** /** Parcelable Creator Object */
* Parcelable Creator Object public static final Parcelable.Creator<Filter> CREATOR =
*/ new Parcelable.Creator<Filter>() {
public static final Parcelable.Creator<Filter> CREATOR = new Parcelable.Creator<Filter>() {
/** /** {@inheritDoc} */
* {@inheritDoc}
*/
@Override @Override
public Filter createFromParcel(Parcel source) { public Filter createFromParcel(Parcel source) {
Filter item = new Filter(); Filter item = new Filter();
@ -40,28 +34,25 @@ public class Filter extends FilterListItem {
return item; return item;
} }
/** /** {@inheritDoc} */
* {@inheritDoc}
*/
@Override @Override
public Filter[] newArray(int size) { public Filter[] newArray(int size) {
return new Filter[size]; return new Filter[size];
} }
}; };
/** /**
* Values to apply to a task when quick-adding a task from this filter. * Values to apply to a task when quick-adding a task from this filter. For example, when a user
* For example, when a user views tasks tagged 'ABC', the * views tasks tagged 'ABC', the tasks they create should also be tagged 'ABC'. If set to null, no
* tasks they create should also be tagged 'ABC'. If set to null, no
* additional values will be stored for a task. Can use {@link PermaSql} * additional values will be stored for a task. Can use {@link PermaSql}
*/ */
final public Map<String, Object> valuesForNewTasks = new HashMap<>(); public final Map<String, Object> valuesForNewTasks = new HashMap<>();
/** /**
* {@link PermaSql} query for this filter. The query will be appended to the select * {@link PermaSql} query for this filter. The query will be appended to the select statement
* statement after "<code>SELECT fields FROM table %s</code>". It is * after "<code>SELECT fields FROM table %s</code>". It is recommended that you use a {@link
* recommended that you use a {@link QueryTemplate} to construct your * QueryTemplate} to construct your query.
* query. *
* <p> * <p>Examples:
* Examples: *
* <ul> * <ul>
* <li><code>"WHERE completionDate = 0"</code> * <li><code>"WHERE completionDate = 0"</code>
* <li><code>"INNER JOIN " + * <li><code>"INNER JOIN " +
@ -72,8 +63,8 @@ public class Filter extends FilterListItem {
*/ */
String sqlQuery; String sqlQuery;
/** /**
* Field for holding a modified sqlQuery based on sqlQuery. Useful for adjusting * Field for holding a modified sqlQuery based on sqlQuery. Useful for adjusting query for
* query for sort/subtasks without breaking the equality checking based on sqlQuery. * sort/subtasks without breaking the equality checking based on sqlQuery.
*/ */
private String filterOverride; private String filterOverride;
@ -87,10 +78,9 @@ public class Filter extends FilterListItem {
* @param listingTitle Title of this item as displayed on the lists page, e.g. Inbox * @param listingTitle Title of this item as displayed on the lists page, e.g. Inbox
* @param sqlQuery SQL query for this list (see {@link #sqlQuery} for examples). * @param sqlQuery SQL query for this list (see {@link #sqlQuery} for examples).
*/ */
public Filter(String listingTitle, QueryTemplate sqlQuery, public Filter(
Map<String, Object> valuesForNewTasks) { String listingTitle, QueryTemplate sqlQuery, Map<String, Object> valuesForNewTasks) {
this(listingTitle, sqlQuery == null ? null : sqlQuery.toString(), this(listingTitle, sqlQuery == null ? null : sqlQuery.toString(), valuesForNewTasks);
valuesForNewTasks);
} }
/** /**
@ -108,9 +98,7 @@ public class Filter extends FilterListItem {
} }
} }
/** /** Utility constructor */
* Utility constructor
*/
Filter() { Filter() {
// do nothing // do nothing
} }
@ -132,8 +120,7 @@ public class Filter extends FilterListItem {
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = 1; int result = 1;
result = prime * result result = prime * result + ((sqlQuery == null) ? 0 : sqlQuery.hashCode());
+ ((sqlQuery == null) ? 0 : sqlQuery.hashCode());
result = prime * result + ((listingTitle == null) ? 0 : listingTitle.hashCode()); result = prime * result + ((listingTitle == null) ? 0 : listingTitle.hashCode());
return result; return result;
} }
@ -172,9 +159,7 @@ public class Filter extends FilterListItem {
return Type.ITEM; return Type.ITEM;
} }
/** /** {@inheritDoc} */
* {@inheritDoc}
*/
@Override @Override
public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags); super.writeToParcel(dest, flags);
@ -197,10 +182,15 @@ public class Filter extends FilterListItem {
@Override @Override
public String toString() { public String toString() {
return "Filter{" + return "Filter{"
"sqlQuery='" + sqlQuery + '\'' + + "sqlQuery='"
", filterOverride='" + filterOverride + '\'' + + sqlQuery
", valuesForNewTasks=" + valuesForNewTasks + + '\''
'}'; + ", filterOverride='"
+ filterOverride
+ '\''
+ ", valuesForNewTasks="
+ valuesForNewTasks
+ '}';
} }
} }

@ -1,9 +1,8 @@
/** /**
* Copyright (c) 2012 Todoroo Inc * Copyright (c) 2012 Todoroo Inc
* *
* See the file "LICENSE" for the full license governing this code. * <p>See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.api; package com.todoroo.astrid.api;
import android.content.Intent; import android.content.Intent;
@ -15,12 +14,11 @@ import android.os.Parcelable;
* *
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
*/ */
abstract public class FilterListItem implements Parcelable { public abstract class FilterListItem implements Parcelable {
/** /** Title of this item displayed on the Filters page */
* Title of this item displayed on the Filters page
*/
public String listingTitle = null; public String listingTitle = null;
public int icon = 0; public int icon = 0;
public int tint = -1; public int tint = -1;
@ -31,9 +29,7 @@ abstract public class FilterListItem implements Parcelable {
return 0; return 0;
} }
/** /** {@inheritDoc} */
* {@inheritDoc}
*/
@Override @Override
public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(Parcel dest, int flags) {
dest.writeString(listingTitle); dest.writeString(listingTitle);
@ -45,9 +41,7 @@ abstract public class FilterListItem implements Parcelable {
// --- parcelable helpers // --- parcelable helpers
/** /** Utility method to read FilterListItem properties from a parcel. */
* Utility method to read FilterListItem properties from a parcel.
*/
protected void readFromParcel(Parcel source) { protected void readFromParcel(Parcel source) {
listingTitle = source.readString(); listingTitle = source.readString();
icon = source.readInt(); icon = source.readInt();
@ -58,9 +52,7 @@ abstract public class FilterListItem implements Parcelable {
@Override @Override
public String toString() { public String toString() {
return "FilterListItem{" + return "FilterListItem{" + "listingTitle='" + listingTitle + '\'' + '}';
"listingTitle='" + listingTitle + '\'' +
'}';
} }
public enum Type { public enum Type {

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save