Applying intellij-java-google-style

pull/645/merge
Alex Baker 6 years ago
parent d1bdd60a9c
commit da10291b04

@ -1,11 +1,11 @@
package org.tasks; package org.tasks;
import javax.inject.Inject;
import org.tasks.caldav.CaldavAccountManager; import org.tasks.caldav.CaldavAccountManager;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
import javax.inject.Inject;
public class FlavorSetup { public class FlavorSetup {
private final CaldavAccountManager caldavAccountManager; private final CaldavAccountManager caldavAccountManager;
private final Preferences preferences; private final Preferences preferences;
@ -16,6 +16,7 @@ public class FlavorSetup {
} }
public void setup() { public void setup() {
caldavAccountManager.setBackgroundSynchronization(preferences.getBoolean(R.string.p_background_sync, true)); caldavAccountManager
.setBackgroundSynchronization(preferences.getBoolean(R.string.p_background_sync, true));
} }
} }

@ -1,21 +1,17 @@
package org.tasks.analytics; package org.tasks.analytics;
import android.content.Context; import android.content.Context;
import com.google.android.gms.analytics.ExceptionParser; import com.google.android.gms.analytics.ExceptionParser;
import com.google.android.gms.analytics.ExceptionReporter; import com.google.android.gms.analytics.ExceptionReporter;
import com.google.android.gms.analytics.GoogleAnalytics; import com.google.android.gms.analytics.GoogleAnalytics;
import com.google.android.gms.analytics.HitBuilders; import com.google.android.gms.analytics.HitBuilders;
import com.google.android.gms.analytics.StandardExceptionParser; import com.google.android.gms.analytics.StandardExceptionParser;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import javax.inject.Inject;
import org.tasks.BuildConfig; import org.tasks.BuildConfig;
import org.tasks.R; import org.tasks.R;
import org.tasks.injection.ApplicationScope; import org.tasks.injection.ApplicationScope;
import org.tasks.injection.ForApplication; import org.tasks.injection.ForApplication;
import javax.inject.Inject;
import timber.log.Timber; import timber.log.Timber;
@ApplicationScope @ApplicationScope
@ -32,7 +28,8 @@ 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, null); final StandardExceptionParser standardExceptionParser = new StandardExceptionParser(context,
null);
exceptionParser = (thread, throwable) -> { exceptionParser = (thread, throwable) -> {
StringBuilder stack = new StringBuilder() StringBuilder stack = new StringBuilder()
.append(standardExceptionParser.getDescription(thread, throwable)) .append(standardExceptionParser.getDescription(thread, throwable))

@ -2,7 +2,6 @@ package org.tasks.billing;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import javax.inject.Inject; import javax.inject.Inject;
public class PurchaseHelper { public class PurchaseHelper {
@ -18,7 +17,8 @@ public class PurchaseHelper {
return false; return false;
} }
public void handleActivityResult(PurchaseHelperCallback callback, int requestCode, int resultCode, Intent data) { public void handleActivityResult(PurchaseHelperCallback callback, int requestCode, int resultCode,
Intent data) {
} }

@ -1,10 +1,8 @@
package org.tasks.gtasks; package org.tasks.gtasks;
import android.app.Activity; import android.app.Activity;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential; import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.todoroo.astrid.gtasks.auth.GtasksLoginActivity; import com.todoroo.astrid.gtasks.auth.GtasksLoginActivity;
import javax.inject.Inject; import javax.inject.Inject;
public class PlayServices { public class PlayServices {
@ -34,7 +32,8 @@ public class PlayServices {
return false; return false;
} }
public void getAuthToken(GtasksLoginActivity gtasksLoginActivity, String a, GtasksLoginActivity.AuthResultHandler authResultHandler) { public void getAuthToken(GtasksLoginActivity gtasksLoginActivity, String a,
GtasksLoginActivity.AuthResultHandler authResultHandler) {
} }
} }

@ -1,10 +1,8 @@
package org.tasks.location; package org.tasks.location;
import org.tasks.data.Location;
import java.util.List; import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
import org.tasks.data.Location;
@SuppressWarnings("EmptyMethod") @SuppressWarnings("EmptyMethod")
public class GeofenceApi { public class GeofenceApi {

@ -3,11 +3,11 @@ package org.tasks.location;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import org.tasks.data.Location; import org.tasks.data.Location;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
public class PlacePicker { public class PlacePicker {
public static Intent getIntent(Activity activity) { public static Intent getIntent(Activity activity) {
return null; return null;
} }

@ -3,26 +3,25 @@
* *
* See the file "LICENSE" for the full license governing this code. * 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 junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.tasks.R;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import org.junit.Test;
import static android.support.test.InstrumentationRegistry.getTargetContext; import org.junit.runner.RunWith;
import static junit.framework.Assert.assertEquals; import org.tasks.R;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
/** /**
* Tests translations for consistency with the default values. You must * Tests translations for consistency with the default values. You must
@ -30,21 +29,16 @@ import static junit.framework.Assert.assertTrue;
* 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 {
public interface Callback<T> {
void apply(T entry);
}
/** /**
* 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) {
callback.apply(getResourcesForLocale(locale)); callback.apply(getResourcesForLocale(locale));
} }
} }
@ -56,65 +50,6 @@ public class TranslationTests {
return new Resources(resources.getAssets(), resources.getDisplayMetrics(), configuration); return new Resources(resources.getAssets(), resources.getDisplayMetrics(), configuration);
} }
private static final class FormatStringData {
private static final char[] scratch = new char[10];
/** format characters */
public final char[] characters;
/** the original string */
public final String string;
public FormatStringData(String string) {
this.string = string;
int pos = -1;
int count = 0;
while(true) {
pos = string.indexOf('%', ++pos);
if(pos++ == -1)
break;
if(pos >= string.length())
scratch[count++] = '\0';
else
scratch[count++] = string.charAt(pos);
}
characters = new char[count];
for(int i = 0; i < count; i++) {
characters[i] = scratch[i];
}
}
/** test that the characters match */
public boolean matches(FormatStringData other) {
if(characters.length != other.characters.length)
return false;
outer: for(int i = 0; i < characters.length; i++) {
if(Character.isDigit(characters[i])) {
for(int j = 0; j < other.characters.length; j++)
if(characters[i] == other.characters[j])
break outer;
return false;
} else if(characters[i] != other.characters[i])
return false;
}
return true;
}
@Override
public String toString() {
StringBuilder value = new StringBuilder("[");
for(int i = 0; i < characters.length; i++) {
value.append(characters[i]);
if(i < characters.length - 1)
value.append(',');
}
value.append("]: '").append(string).append('\'');
return value.toString();
}
}
/** /**
* Internal test of format string parser * Internal test of format string parser
*/ */
@ -160,7 +95,7 @@ public class TranslationTests {
final StringBuilder failures = new StringBuilder(); final StringBuilder failures = new StringBuilder();
for(int i = 0; i < strings.length; i++) { for (int i = 0; i < strings.length; i++) {
try { try {
String string = resources.getString(strings[i]); String string = resources.getString(strings[i]);
formatStrings[i] = new FormatStringData(string); formatStrings[i] = new FormatStringData(string);
@ -173,15 +108,15 @@ public class TranslationTests {
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 {
switch(strings[i]) { switch (strings[i]) {
case R.string.abc_shareactionprovider_share_with_application: case R.string.abc_shareactionprovider_share_with_application:
continue; continue;
} }
String string = r.getString(strings[i]); String string = r.getString(strings[i]);
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(String.format("%s (%s): %s != %s\n",
name, locale.toString(), newFS, formatStrings[i])); name, locale.toString(), newFS, formatStrings[i]));
@ -202,7 +137,7 @@ public class TranslationTests {
*/ */
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(String.format("%s: %s did not contain: %s\n",
@ -235,10 +170,11 @@ public class TranslationTests {
private int errorCount(StringBuilder failures) { private int errorCount(StringBuilder failures) {
int count = 0; int count = 0;
int pos = -1; int pos = -1;
while(true) { while (true) {
pos = failures.indexOf("\n", pos + 1); pos = failures.indexOf("\n", pos + 1);
if(pos == -1) if (pos == -1) {
return count; return count;
}
count++; count++;
} }
} }
@ -257,8 +193,88 @@ public class TranslationTests {
} }
} }
int[] idsAsIntArray = new int[ids.size()]; int[] idsAsIntArray = new int[ids.size()];
for(int i = 0; i < ids.size(); i++) for (int i = 0; i < ids.size(); i++) {
idsAsIntArray[i] = ids.get(i); idsAsIntArray[i] = ids.get(i);
}
return idsAsIntArray; return idsAsIntArray;
} }
public interface Callback<T> {
void apply(T entry);
}
private static final class FormatStringData {
private static final char[] scratch = new char[10];
/**
* format characters
*/
public final char[] characters;
/**
* the original string
*/
public final String string;
public FormatStringData(String string) {
this.string = string;
int pos = -1;
int count = 0;
while (true) {
pos = string.indexOf('%', ++pos);
if (pos++ == -1) {
break;
}
if (pos >= string.length()) {
scratch[count++] = '\0';
} else {
scratch[count++] = string.charAt(pos);
}
}
characters = new char[count];
for (int i = 0; i < count; i++) {
characters[i] = scratch[i];
}
}
/**
* test that the characters match
*/
public boolean matches(FormatStringData other) {
if (characters.length != other.characters.length) {
return false;
}
outer:
for (int i = 0; i < characters.length; i++) {
if (Character.isDigit(characters[i])) {
for (int j = 0; j < other.characters.length; j++) {
if (characters[i] == other.characters[j]) {
break outer;
}
}
return false;
} else if (characters[i] != other.characters[i]) {
return false;
}
}
return true;
}
@Override
public String toString() {
StringBuilder value = new StringBuilder("[");
for (int i = 0; i < characters.length; i++) {
value.append(characters[i]);
if (i < characters.length - 1) {
value.append(',');
}
}
value.append("]: '").append(string).append('\'');
return value.toString();
}
}
} }

@ -3,20 +3,8 @@
* *
* See the file "LICENSE" for the full license governing this code. * See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.utility;
import android.content.res.Configuration; package com.todoroo.andlib.utility;
import android.support.test.runner.AndroidJUnit4;
import android.util.DisplayMetrics;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.tasks.Snippet;
import org.tasks.time.DateTime;
import java.util.Locale;
import static android.support.test.InstrumentationRegistry.getTargetContext; import static android.support.test.InstrumentationRegistry.getTargetContext;
import static com.todoroo.andlib.utility.DateUtilities.addCalendarMonthsToUnixtime; import static com.todoroo.andlib.utility.DateUtilities.addCalendarMonthsToUnixtime;
@ -31,6 +19,17 @@ import static org.tasks.Freeze.freezeAt;
import static org.tasks.date.DateTimeUtils.newDate; import static org.tasks.date.DateTimeUtils.newDate;
import static org.tasks.date.DateTimeUtils.newDateTime; import static org.tasks.date.DateTimeUtils.newDateTime;
import android.content.res.Configuration;
import android.support.test.runner.AndroidJUnit4;
import android.util.DisplayMetrics;
import java.util.Locale;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.tasks.Snippet;
import org.tasks.time.DateTime;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class DateUtilitiesTest { public class DateUtilitiesTest {
@ -58,7 +57,7 @@ public class DateUtilitiesTest {
public void forEachLocale(Runnable r) { public void forEachLocale(Runnable r) {
Locale[] locales = Locale.getAvailableLocales(); Locale[] locales = Locale.getAvailableLocales();
for(Locale locale : locales) { for (Locale locale : locales) {
setLocale(locale); setLocale(locale);
r.run(); r.run();
@ -217,87 +216,101 @@ public class DateUtilitiesTest {
@Test @Test
public void testAddMonthsToTimestamp() { public void testAddMonthsToTimestamp() {
assertEquals(newDate(2014, 1, 1).getMillis(), addCalendarMonthsToUnixtime(newDate(2013, 12, 1).getMillis(), 1)); assertEquals(newDate(2014, 1, 1).getMillis(),
assertEquals(newDate(2014, 12, 31).getMillis(), addCalendarMonthsToUnixtime(newDate(2013, 12, 31).getMillis(), 12)); addCalendarMonthsToUnixtime(newDate(2013, 12, 1).getMillis(), 1));
assertEquals(newDate(2014, 12, 31).getMillis(),
addCalendarMonthsToUnixtime(newDate(2013, 12, 31).getMillis(), 12));
} }
@Test @Test
public void testAddMonthsWithLessDays() { public void testAddMonthsWithLessDays() {
assertEquals(newDate(2014, 3, 3).getMillis(), addCalendarMonthsToUnixtime(newDate(2013, 12, 31).getMillis(), 2)); assertEquals(newDate(2014, 3, 3).getMillis(),
addCalendarMonthsToUnixtime(newDate(2013, 12, 31).getMillis(), 2));
} }
@Test @Test
public void testAddMonthsWithMoreDays() { public void testAddMonthsWithMoreDays() {
assertEquals(newDate(2014, 1, 30).getMillis(), addCalendarMonthsToUnixtime(newDate(2013, 11, 30).getMillis(), 2)); assertEquals(newDate(2014, 1, 30).getMillis(),
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)).thawAfter(() ->
assertEquals("Jan 14", DateUtilities.getRelativeDateStringWithTime(getTargetContext(), 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)).thawAfter(() ->
assertEquals("Jan 14 '18", DateUtilities.getRelativeDateStringWithTime(getTargetContext(), 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)).thawAfter(() ->
assertEquals("14 Jan.", DateUtilities.getRelativeDateStringWithTime(getTargetContext(), 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)).thawAfter(() ->
assertEquals("14 Jan. '18", DateUtilities.getRelativeDateStringWithTime(getTargetContext(), 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)).thawAfter(() ->
assertEquals("1월 14일", DateUtilities.getRelativeDateStringWithTime(getTargetContext(), 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)).thawAfter(() ->
assertEquals("18년 1월 14일", DateUtilities.getRelativeDateStringWithTime(getTargetContext(), 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)).thawAfter(() ->
assertEquals("1月 14日", DateUtilities.getRelativeDateStringWithTime(getTargetContext(), 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)).thawAfter(() ->
assertEquals("18年 1月 14日", DateUtilities.getRelativeDateStringWithTime(getTargetContext(), 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)).thawAfter(() ->
assertEquals("1月 14日", DateUtilities.getRelativeDateStringWithTime(getTargetContext(), 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)).thawAfter(() ->
assertEquals("18年 1月 14日", DateUtilities.getRelativeDateStringWithTime(getTargetContext(), new DateTime(2018, 1, 14).getMillis()))); assertEquals("18年 1月 14日", DateUtilities.getRelativeDateStringWithTime(getTargetContext(),
new DateTime(2018, 1, 14).getMillis())));
} }
} }

@ -1,26 +1,24 @@
package com.todoroo.andlib.utility; package com.todoroo.andlib.utility;
import android.support.test.runner.AndroidJUnit4; import static android.support.test.InstrumentationRegistry.getTargetContext;
import static com.todoroo.andlib.utility.DateUtilities.getRelativeDay;
import static junit.framework.Assert.assertEquals;
import static org.tasks.Freeze.freezeAt;
import static org.tasks.Freeze.thaw;
import android.support.test.runner.AndroidJUnit4;
import java.util.Locale;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.tasks.time.DateTime; import org.tasks.time.DateTime;
import java.util.Locale;
import static android.support.test.InstrumentationRegistry.getTargetContext;
import static com.todoroo.andlib.utility.DateUtilities.getRelativeDay;
import static junit.framework.Assert.assertEquals;
import static org.tasks.Freeze.freezeAt;
import static org.tasks.Freeze.thaw;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class RelativeDayTest { public class RelativeDayTest {
private static Locale defaultLocale;
private static final DateTime now = new DateTime(2013, 12, 31, 11, 9, 42, 357); private static final DateTime now = new DateTime(2013, 12, 31, 11, 9, 42, 357);
private static Locale defaultLocale;
@Before @Before
public void setUp() { public void setUp() {

@ -1,10 +1,16 @@
package com.todoroo.astrid.alarms; package com.todoroo.astrid.alarms;
import android.support.test.runner.AndroidJUnit4; import static com.natpryce.makeiteasy.MakeItEasy.with;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.tasks.makers.TaskMaker.REMINDER_LAST;
import static org.tasks.makers.TaskMaker.newTask;
import android.support.test.runner.AndroidJUnit4;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import javax.inject.Inject;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -18,15 +24,6 @@ import org.tasks.jobs.AlarmJob;
import org.tasks.jobs.JobQueue; import org.tasks.jobs.JobQueue;
import org.tasks.time.DateTime; import org.tasks.time.DateTime;
import javax.inject.Inject;
import static com.natpryce.makeiteasy.MakeItEasy.with;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.tasks.makers.TaskMaker.REMINDER_LAST;
import static org.tasks.makers.TaskMaker.newTask;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class AlarmJobServiceTest extends InjectingTestCase { public class AlarmJobServiceTest extends InjectingTestCase {

@ -3,26 +3,22 @@
* *
* See the file "LICENSE" for the full license governing this code. * See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.dao; package com.todoroo.astrid.dao;
import android.support.test.runner.AndroidJUnit4; import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotSame;
import static junit.framework.Assert.assertNull;
import com.todoroo.andlib.sql.Query; import android.support.test.runner.AndroidJUnit4;
import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import javax.inject.Inject;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.tasks.injection.InjectingTestCase; import org.tasks.injection.InjectingTestCase;
import org.tasks.injection.TestComponent; import org.tasks.injection.TestComponent;
import javax.inject.Inject;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotSame;
import static junit.framework.Assert.assertNull;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class TaskDaoTests extends InjectingTestCase { public class TaskDaoTests extends InjectingTestCase {

@ -1,17 +1,5 @@
package com.todoroo.astrid.data; package com.todoroo.astrid.data;
import android.support.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.tasks.Snippet;
import org.tasks.time.DateTime;
import java.util.ArrayList;
import java.util.TreeSet;
import static com.todoroo.astrid.data.Task.URGENCY_DAY_AFTER; import static com.todoroo.astrid.data.Task.URGENCY_DAY_AFTER;
import static com.todoroo.astrid.data.Task.URGENCY_IN_TWO_WEEKS; import static com.todoroo.astrid.data.Task.URGENCY_IN_TWO_WEEKS;
import static com.todoroo.astrid.data.Task.URGENCY_NEXT_MONTH; import static com.todoroo.astrid.data.Task.URGENCY_NEXT_MONTH;
@ -31,6 +19,16 @@ import static org.tasks.Freeze.thaw;
import static org.tasks.date.DateTimeUtils.newDateTime; import static org.tasks.date.DateTimeUtils.newDateTime;
import static org.tasks.time.DateTimeUtils.currentTimeMillis; import static org.tasks.time.DateTimeUtils.currentTimeMillis;
import android.support.test.runner.AndroidJUnit4;
import java.util.ArrayList;
import java.util.TreeSet;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.tasks.Snippet;
import org.tasks.time.DateTime;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class TaskTest { public class TaskTest {

@ -1,22 +1,19 @@
package com.todoroo.astrid.model; package com.todoroo.astrid.model;
import android.support.test.runner.AndroidJUnit4; import static junit.framework.Assert.assertEquals;
import static org.tasks.Freeze.freezeClock;
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
import android.support.test.runner.AndroidJUnit4;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import javax.inject.Inject;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.tasks.Snippet; import org.tasks.Snippet;
import org.tasks.injection.InjectingTestCase; import org.tasks.injection.InjectingTestCase;
import org.tasks.injection.TestComponent; import org.tasks.injection.TestComponent;
import javax.inject.Inject;
import static junit.framework.Assert.assertEquals;
import static org.tasks.Freeze.freezeClock;
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class TaskTest extends InjectingTestCase { public class TaskTest extends InjectingTestCase {

@ -1,29 +1,5 @@
package com.todoroo.astrid.reminders; package com.todoroo.astrid.reminders;
import android.support.test.runner.AndroidJUnit4;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.tasks.R;
import org.tasks.Snippet;
import org.tasks.injection.InjectingTestCase;
import org.tasks.injection.TestComponent;
import org.tasks.jobs.JobQueue;
import org.tasks.jobs.Reminder;
import org.tasks.preferences.Preferences;
import org.tasks.reminders.Random;
import org.tasks.time.DateTime;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import static com.natpryce.makeiteasy.MakeItEasy.with; import static com.natpryce.makeiteasy.MakeItEasy.with;
import static com.todoroo.andlib.utility.DateUtilities.ONE_HOUR; import static com.todoroo.andlib.utility.DateUtilities.ONE_HOUR;
import static com.todoroo.andlib.utility.DateUtilities.ONE_WEEK; import static com.todoroo.andlib.utility.DateUtilities.ONE_WEEK;
@ -48,6 +24,26 @@ import static org.tasks.makers.TaskMaker.REMINDER_LAST;
import static org.tasks.makers.TaskMaker.SNOOZE_TIME; import static org.tasks.makers.TaskMaker.SNOOZE_TIME;
import static org.tasks.makers.TaskMaker.newTask; import static org.tasks.makers.TaskMaker.newTask;
import android.support.test.runner.AndroidJUnit4;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.tasks.R;
import org.tasks.Snippet;
import org.tasks.injection.InjectingTestCase;
import org.tasks.injection.TestComponent;
import org.tasks.jobs.JobQueue;
import org.tasks.jobs.Reminder;
import org.tasks.preferences.Preferences;
import org.tasks.reminders.Random;
import org.tasks.time.DateTime;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class ReminderServiceTest extends InjectingTestCase { public class ReminderServiceTest extends InjectingTestCase {
@ -129,7 +125,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).add(new Reminder(1, now.startOfDay().withHourOfDay(18).getMillis(), ReminderService.TYPE_DUE)); order.verify(jobs).add(
new Reminder(1, now.startOfDay().withHourOfDay(18).getMillis(), ReminderService.TYPE_DUE));
} }
@Test @Test
@ -218,7 +215,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).add(new Reminder(1L, now.minusDays(1).getMillis() + 584206592, ReminderService.TYPE_RANDOM)); order.verify(jobs).add(
new Reminder(1L, now.minusDays(1).getMillis() + 584206592, ReminderService.TYPE_RANDOM));
}}); }});
} }
@ -237,7 +235,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).add(new Reminder(1L, now.minusDays(1).getMillis() + 584206592, ReminderService.TYPE_RANDOM)); order.verify(jobs).add(
new Reminder(1L, now.minusDays(1).getMillis() + 584206592, ReminderService.TYPE_RANDOM));
}}); }});
} }
@ -256,7 +255,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).add(new Reminder(1L, now.getMillis() + 10148400, ReminderService.TYPE_RANDOM)); order.verify(jobs)
.add(new Reminder(1L, now.getMillis() + 10148400, ReminderService.TYPE_RANDOM));
}}); }});
} }
@ -272,7 +272,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).add(new Reminder(1L, new DateTime(2017, 9, 23, 15, 30, 1, 0).getMillis(), ReminderService.TYPE_OVERDUE)); order.verify(jobs).add(new Reminder(1L, new DateTime(2017, 9, 23, 15, 30, 1, 0).getMillis(),
ReminderService.TYPE_OVERDUE));
} }
@Test @Test
@ -287,7 +288,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).add(new Reminder(1L, new DateTime(2017, 9, 24, 15, 30, 1, 0).getMillis(), ReminderService.TYPE_OVERDUE)); order.verify(jobs).add(new Reminder(1L, new DateTime(2017, 9, 24, 15, 30, 1, 0).getMillis(),
ReminderService.TYPE_OVERDUE));
} }
@Test @Test
@ -302,7 +304,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).add(new Reminder(1L, new DateTime(2017, 9, 25, 12, 30, 1, 0).getMillis(), ReminderService.TYPE_OVERDUE)); order.verify(jobs).add(new Reminder(1L, new DateTime(2017, 9, 25, 12, 30, 1, 0).getMillis(),
ReminderService.TYPE_OVERDUE));
} }
@Test @Test
@ -318,7 +321,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).add(new Reminder(1L, new DateTime(2017, 9, 23, 15, 0, 0, 0).getMillis(), ReminderService.TYPE_OVERDUE)); order.verify(jobs).add(new Reminder(1L, new DateTime(2017, 9, 23, 15, 0, 0, 0).getMillis(),
ReminderService.TYPE_OVERDUE));
} }
@Test @Test
@ -333,7 +337,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).add(new Reminder(1L, new DateTime(2017, 9, 24, 15, 30, 1, 0).getMillis(), ReminderService.TYPE_OVERDUE)); order.verify(jobs).add(new Reminder(1L, new DateTime(2017, 9, 24, 15, 30, 1, 0).getMillis(),
ReminderService.TYPE_OVERDUE));
} }
@Test @Test
@ -348,7 +353,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).add(new Reminder(1L, new DateTime(2017, 9, 23, 15, 30, 1, 0).getMillis(), ReminderService.TYPE_OVERDUE)); order.verify(jobs).add(new Reminder(1L, new DateTime(2017, 9, 23, 15, 30, 1, 0).getMillis(),
ReminderService.TYPE_OVERDUE));
} }
@Test @Test
@ -365,6 +371,7 @@ 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 Reminder(1, now.plusMonths(12).getMillis(), ReminderService.TYPE_SNOOZE)); order.verify(jobs)
.add(new Reminder(1, now.plusMonths(12).getMillis(), ReminderService.TYPE_SNOOZE));
} }
} }

@ -3,29 +3,27 @@
* *
* See the file "LICENSE" for the full license governing this code. * See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.repeats; package com.todoroo.astrid.repeats;
import android.support.test.runner.AndroidJUnit4; import static junit.framework.Assert.assertEquals;
import static org.tasks.date.DateTimeUtils.newDateTime;
import android.support.test.runner.AndroidJUnit4;
import com.google.ical.values.Frequency; import com.google.ical.values.Frequency;
import com.google.ical.values.RRule; import com.google.ical.values.RRule;
import com.google.ical.values.Weekday; import com.google.ical.values.Weekday;
import com.google.ical.values.WeekdayNum; import com.google.ical.values.WeekdayNum;
import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.tasks.time.DateTime; import org.tasks.time.DateTime;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import static junit.framework.Assert.assertEquals;
import static org.tasks.date.DateTimeUtils.newDateTime;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class AdvancedRepeatTest { public class AdvancedRepeatTest {
@ -38,6 +36,13 @@ public class AdvancedRepeatTest {
private long nextDueDate; private long nextDueDate;
private RRule rrule; private RRule rrule;
public static void assertDateTimeEquals(long date, long other) {
assertEquals("Expected: " + newDateTime(date) + ", Actual: " + newDateTime(other),
date, other);
}
// --- date with time tests
@Before @Before
public void setUp() { public void setUp() {
task = new Task(); task = new Task();
@ -45,14 +50,13 @@ public class AdvancedRepeatTest {
rrule = new RRule(); rrule = new RRule();
} }
// --- date with time tests
@Test @Test
public void testDueDateSpecificTime() throws ParseException { public void testDueDateSpecificTime() throws ParseException {
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, new DateTime(2010, 8, 1, 10, 4, 0).getMillis()); long dayWithTime = 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;
@ -60,12 +64,15 @@ public class AdvancedRepeatTest {
assertDateTimeEquals(nextDayWithTime, nextDueDate); assertDateTimeEquals(nextDayWithTime, nextDueDate);
} }
// --- due date tests
@Test @Test
public void testCompletionDateSpecificTime() throws ParseException { public void testCompletionDateSpecificTime() throws ParseException {
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, new DateTime(2010, 8, 1, 10, 4, 0).getMillis()); long dayWithTime = 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 = newDateTime()
@ -80,9 +87,9 @@ public class AdvancedRepeatTest {
assertDateTimeEquals(nextDayWithTimeLong, nextDueDate); assertDateTimeEquals(nextDayWithTimeLong, nextDueDate);
} }
// --- due date tests /**
* 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);
@ -100,7 +107,9 @@ 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);
@ -130,7 +139,9 @@ 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 {
@ -149,7 +160,11 @@ public class AdvancedRepeatTest {
assertDueDate(nextDueDate, THIS, Calendar.MONDAY); assertDueDate(nextDueDate, THIS, Calendar.MONDAY);
} }
/** test multiple days per week, multiple intervals - DUE DATE */ // --- completion tests
/**
* 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);
@ -167,12 +182,12 @@ public class AdvancedRepeatTest {
assertDueDate(nextDueDate, NEXT, Calendar.MONDAY); assertDueDate(nextDueDate, NEXT, Calendar.MONDAY);
} }
// --- completion tests /**
* 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()) {
buildRRule(1, Frequency.WEEKLY, wday); buildRRule(1, Frequency.WEEKLY, wday);
computeNextDueDate(true); computeNextDueDate(true);
long expected = getDate(DateUtilities.now() + DateUtilities.ONE_DAY, THIS, wday.javaDayNum); long expected = getDate(DateUtilities.now() + DateUtilities.ONE_DAY, THIS, wday.javaDayNum);
@ -180,10 +195,11 @@ public class AdvancedRepeatTest {
assertEquals(expected, nextDueDate); assertEquals(expected, nextDueDate);
} }
for(Weekday wday1 : Weekday.values()) { for (Weekday wday1 : Weekday.values()) {
for(Weekday wday2 : Weekday.values()) { for (Weekday wday2 : Weekday.values()) {
if(wday1 == wday2) if (wday1 == wday2) {
continue; continue;
}
buildRRule(1, Frequency.WEEKLY, wday1, wday2); buildRRule(1, Frequency.WEEKLY, wday1, wday2);
long nextOne = getDate(DateUtilities.now() + DateUtilities.ONE_DAY, THIS, wday1.javaDayNum); long nextOne = getDate(DateUtilities.now() + DateUtilities.ONE_DAY, THIS, wday1.javaDayNum);
@ -195,10 +211,14 @@ public class AdvancedRepeatTest {
} }
} }
/** test multiple days per week, multiple intervals - COMPLETE DATE */ // --- helpers
/**
* 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()) {
buildRRule(2, Frequency.WEEKLY, wday); buildRRule(2, Frequency.WEEKLY, wday);
computeNextDueDate(true); computeNextDueDate(true);
long expected = getDate(DateUtilities.now() + DateUtilities.ONE_DAY, NEXT, wday.javaDayNum); long expected = getDate(DateUtilities.now() + DateUtilities.ONE_DAY, NEXT, wday.javaDayNum);
@ -206,10 +226,11 @@ public class AdvancedRepeatTest {
assertEquals(expected, nextDueDate); assertEquals(expected, nextDueDate);
} }
for(Weekday wday1 : Weekday.values()) { for (Weekday wday1 : Weekday.values()) {
for(Weekday wday2 : Weekday.values()) { for (Weekday wday2 : Weekday.values()) {
if(wday1 == wday2) if (wday1 == wday2) {
continue; continue;
}
buildRRule(2, Frequency.WEEKLY, wday1, wday2); buildRRule(2, Frequency.WEEKLY, wday1, wday2);
long nextOne = getDate(DateUtilities.now() + DateUtilities.ONE_DAY, NEXT, wday1.javaDayNum); long nextOne = getDate(DateUtilities.now() + DateUtilities.ONE_DAY, NEXT, wday1.javaDayNum);
@ -221,9 +242,7 @@ public class AdvancedRepeatTest {
} }
} }
// --- helpers private void computeNextDueDate(boolean fromComplete) throws ParseException {
private void computeNextDueDate(boolean fromComplete) throws ParseException{
nextDueDate = RepeatTaskHelper.computeNextDueDate(task, rrule.toIcal(), fromComplete); nextDueDate = RepeatTaskHelper.computeNextDueDate(task, rrule.toIcal(), fromComplete);
} }
@ -238,15 +257,11 @@ public class AdvancedRepeatTest {
assertEquals(expected, actual); assertEquals(expected, actual);
} }
public static void assertDateTimeEquals(long date, long other) {
assertEquals("Expected: " + newDateTime(date) + ", Actual: " + newDateTime(other),
date, other);
}
private void setRRuleDays(RRule rrule, Weekday... weekdays) { private void setRRuleDays(RRule rrule, Weekday... weekdays) {
ArrayList<WeekdayNum> days = new ArrayList<>(); ArrayList<WeekdayNum> days = new ArrayList<>();
for(Weekday wd : weekdays) for (Weekday wd : weekdays) {
days.add(new WeekdayNum(0, wd)); days.add(new WeekdayNum(0, wd));
}
rrule.setByDay(days); rrule.setByDay(days);
} }
@ -261,7 +276,7 @@ public class AdvancedRepeatTest {
c.setTimeInMillis(start); c.setTimeInMillis(start);
int direction = which > 0 ? 1 : -1; int direction = which > 0 ? 1 : -1;
while(c.get(Calendar.DAY_OF_WEEK) != dayOfWeek) { while (c.get(Calendar.DAY_OF_WEEK) != dayOfWeek) {
c.add(Calendar.DAY_OF_MONTH, direction); c.add(Calendar.DAY_OF_MONTH, direction);
} }
c.add(Calendar.DAY_OF_MONTH, (Math.abs(which) - 1) * direction * 7); c.add(Calendar.DAY_OF_MONTH, (Math.abs(which) - 1) * direction * 7);

@ -1,23 +1,20 @@
package com.todoroo.astrid.repeats; package com.todoroo.astrid.repeats;
import android.support.test.runner.AndroidJUnit4; import static com.todoroo.astrid.repeats.RepeatTaskHelper.computeNextDueDate;
import static java.util.Arrays.asList;
import static junit.framework.Assert.assertEquals;
import android.support.test.runner.AndroidJUnit4;
import com.google.ical.values.Frequency; import com.google.ical.values.Frequency;
import com.google.ical.values.RRule; import com.google.ical.values.RRule;
import com.google.ical.values.Weekday; import com.google.ical.values.Weekday;
import com.google.ical.values.WeekdayNum; import com.google.ical.values.WeekdayNum;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import java.text.ParseException;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.tasks.time.DateTime; import org.tasks.time.DateTime;
import java.text.ParseException;
import static com.todoroo.astrid.repeats.RepeatTaskHelper.computeNextDueDate;
import static java.util.Arrays.asList;
import static junit.framework.Assert.assertEquals;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class NewRepeatTests { public class NewRepeatTests {
@ -69,7 +66,9 @@ 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 {
@ -182,7 +181,8 @@ 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), new WeekdayNum(0, Weekday.WE)); Task task = 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,7 +191,8 @@ 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, new WeekdayNum(0, Weekday.MO), new WeekdayNum(0, Weekday.WE)); Task task = 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));
} }
@ -200,17 +201,20 @@ 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, new WeekdayNum(0, Weekday.MO), new WeekdayNum(0, Weekday.WE)); Task task = 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, new DateTime(year, month, day, hour, minute).getMillis())); return new DateTime(Task.createDueDate(Task.URGENCY_SPECIFIC_DAY_TIME,
new DateTime(year, month, day, hour, minute).getMillis()));
} }
private DateTime calculateNextDueDate(Task task) throws ParseException { private DateTime calculateNextDueDate(Task task) throws ParseException {
return new DateTime(computeNextDueDate(task, task.sanitizedRecurrence(), task.repeatAfterCompletion())); return new DateTime(
computeNextDueDate(task, task.sanitizedRecurrence(), task.repeatAfterCompletion()));
} }
private Task newFromDue(Frequency frequency, int interval, DateTime dueDateTime) { private Task newFromDue(Frequency frequency, int interval, DateTime dueDateTime) {
@ -227,7 +231,8 @@ public class NewRepeatTests {
}}; }};
} }
private Task newFromCompleted(Frequency frequency, int interval, DateTime dueDateTime, DateTime completionDate) { private Task newFromCompleted(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());
@ -235,7 +240,8 @@ public class NewRepeatTests {
}}; }};
} }
private Task newWeeklyFromCompleted(int interval, DateTime dueDateTime, DateTime completionDate, WeekdayNum... weekdays) { private Task newWeeklyFromCompleted(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());
@ -243,7 +249,8 @@ public class NewRepeatTests {
}}; }};
} }
private String getRecurrenceRule(Frequency frequency, int interval, boolean fromCompletion, WeekdayNum... weekdays) { private String getRecurrenceRule(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);

@ -1,14 +1,26 @@
package com.todoroo.astrid.repeats; package com.todoroo.astrid.repeats;
import static com.natpryce.makeiteasy.MakeItEasy.with;
import static junit.framework.Assert.assertEquals;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.tasks.makers.TaskMaker.AFTER_COMPLETE;
import static org.tasks.makers.TaskMaker.COMPLETION_TIME;
import static org.tasks.makers.TaskMaker.DUE_TIME;
import static org.tasks.makers.TaskMaker.ID;
import static org.tasks.makers.TaskMaker.RRULE;
import static org.tasks.makers.TaskMaker.newTask;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
import com.google.ical.values.RRule; import com.google.ical.values.RRule;
import com.todoroo.astrid.alarms.AlarmService; import com.todoroo.astrid.alarms.AlarmService;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gcal.GCalHelper; import com.todoroo.astrid.gcal.GCalHelper;
import java.text.ParseException;
import javax.inject.Inject;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -19,22 +31,6 @@ import org.tasks.injection.InjectingTestCase;
import org.tasks.injection.TestComponent; import org.tasks.injection.TestComponent;
import org.tasks.time.DateTime; import org.tasks.time.DateTime;
import java.text.ParseException;
import javax.inject.Inject;
import static com.natpryce.makeiteasy.MakeItEasy.with;
import static junit.framework.Assert.assertEquals;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.tasks.makers.TaskMaker.AFTER_COMPLETE;
import static org.tasks.makers.TaskMaker.COMPLETION_TIME;
import static org.tasks.makers.TaskMaker.DUE_TIME;
import static org.tasks.makers.TaskMaker.ID;
import static org.tasks.makers.TaskMaker.RRULE;
import static org.tasks.makers.TaskMaker.newTask;
@SuppressLint("NewApi") @SuppressLint("NewApi")
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class RepeatTaskHelperTest extends InjectingTestCase { public class RepeatTaskHelperTest extends InjectingTestCase {
@ -196,7 +192,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).broadcastRepeat(1, oldDueDate.getMillis(), newDueDate.getMillis()); mocks.verify(localBroadcastManager)
.broadcastRepeat(1, oldDueDate.getMillis(), newDueDate.getMillis());
} }
@Override @Override

@ -3,31 +3,30 @@
* *
* See the file "LICENSE" for the full license governing this code. * See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.service; package com.todoroo.astrid.service;
import android.support.test.runner.AndroidJUnit4; import static junit.framework.Assert.assertEquals;
import android.support.test.runner.AndroidJUnit4;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.tags.TagService; import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.utility.TitleParser; import com.todoroo.astrid.utility.TitleParser;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.tasks.injection.InjectingTestCase;
import org.tasks.injection.TestComponent;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
import org.junit.Test;
import static junit.framework.Assert.assertEquals; import org.junit.runner.RunWith;
import org.tasks.injection.InjectingTestCase;
import org.tasks.injection.TestComponent;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class QuickAddMarkupTest extends InjectingTestCase { public class QuickAddMarkupTest extends InjectingTestCase {
private final ArrayList<String> tags = new ArrayList<>();
@Inject TagService tagService; @Inject TagService tagService;
private Task task;
@Override @Override
protected void inject(TestComponent component) { protected void inject(TestComponent component) {
@ -64,6 +63,8 @@ public class QuickAddMarkupTest extends InjectingTestCase {
assertTagsAre(); assertTagsAre();
} }
// --- helpers
@Test @Test
public void testImportances() { public void testImportances() {
whenTitleIs("eat !1"); whenTitleIs("eat !1");
@ -86,11 +87,6 @@ public class QuickAddMarkupTest extends InjectingTestCase {
assertImportanceIs(Task.IMPORTANCE_MUST_DO); assertImportanceIs(Task.IMPORTANCE_MUST_DO);
} }
// --- helpers
private Task task;
private final ArrayList<String> tags = new ArrayList<>();
private void assertTagsAre(String... expectedTags) { private void assertTagsAre(String... expectedTags) {
List<String> expected = Arrays.asList(expectedTags); List<String> expected = Arrays.asList(expectedTags);
assertEquals(expected.toString(), tags.toString()); assertEquals(expected.toString(), tags.toString());
@ -108,6 +104,6 @@ public class QuickAddMarkupTest extends InjectingTestCase {
} }
private void assertImportanceIs(int importance) { private void assertImportanceIs(int importance) {
assertEquals(importance, (int)task.getImportance()); assertEquals(importance, (int) task.getImportance());
} }
} }

@ -3,16 +3,24 @@
* <p> * <p>
* See the file "LICENSE" for the full license governing this code. * See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.service; package com.todoroo.astrid.service;
import android.support.test.runner.AndroidJUnit4; import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotSame;
import static junit.framework.Assert.assertTrue;
import static org.tasks.date.DateTimeUtils.newDateTime;
import android.support.test.runner.AndroidJUnit4;
import com.google.ical.values.Frequency; import com.google.ical.values.Frequency;
import com.google.ical.values.RRule; import com.google.ical.values.RRule;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.tags.TagService; import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.utility.TitleParser; import com.todoroo.astrid.utility.TitleParser;
import java.util.ArrayList;
import java.util.Calendar;
import javax.inject.Inject;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.tasks.R; import org.tasks.R;
@ -21,17 +29,6 @@ import org.tasks.injection.TestComponent;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
import org.tasks.time.DateTime; import org.tasks.time.DateTime;
import java.util.ArrayList;
import java.util.Calendar;
import javax.inject.Inject;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotSame;
import static junit.framework.Assert.assertTrue;
import static org.tasks.date.DateTimeUtils.newDateTime;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class TitleParserTest extends InjectingTestCase { public class TitleParserTest extends InjectingTestCase {
@ -50,7 +47,10 @@ public class TitleParserTest extends InjectingTestCase {
component.inject(this); component.inject(this);
} }
/** test that completing a task w/ no regular expressions creates a simple task with no date, no repeat, no lists*/ /**
* test that completing a task w/ no regular expressions creates a simple task with no date, no
* repeat, no lists
*/
@Test @Test
public void testNoRegexes() throws Exception { public void testNoRegexes() throws Exception {
Task task = taskCreator.basicQuickAddTask("Jog"); Task task = taskCreator.basicQuickAddTask("Jog");
@ -60,7 +60,9 @@ 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 = {
@ -222,10 +224,11 @@ public class TitleParserTest extends InjectingTestCase {
//----------------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() throws Exception { public void testPriority0() throws Exception {
String[] acceptedStrings = { String[] acceptedStrings = {
@ -260,18 +263,22 @@ public class TitleParserTest extends InjectingTestCase {
}; };
Task task; Task task;
for (String acceptedStringAtEnd : acceptedStringsAtEnd) { for (String acceptedStringAtEnd : acceptedStringsAtEnd) {
task = taskCreator.basicQuickAddTask("Jog " + acceptedStringAtEnd); //test at end of task. should set importance. task = 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(acceptedStringAtEnd + " jog"); //test at beginning of task. should not set importance. task = 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("Jog " + acceptedStringAnywhere); //test at end of task. should set importance. task = 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(acceptedStringAnywhere + " jog"); //test at beginning of task. should set importance. task = 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);
} }
} }
@ -345,10 +352,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() throws Exception { public void testDailyWithNoDueDate() throws Exception {
String title = "Jog daily"; String title = "Jog daily";
@ -377,7 +385,9 @@ public class TitleParserTest extends InjectingTestCase {
} }
/** 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() throws Exception { public void testWeeklyWithNoDueDate() throws Exception {
String title = "Jog weekly"; String title = "Jog weekly";
@ -405,7 +415,9 @@ 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() throws Exception { public void testMonthlyFromNoDueDate() throws Exception {
String title = "Jog monthly"; String title = "Jog monthly";
@ -483,10 +495,11 @@ 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() throws Exception { public void testTagsPound() throws Exception {
String[] acceptedStrings = { String[] acceptedStrings = {
@ -502,11 +515,15 @@ public class TitleParserTest extends InjectingTestCase {
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);
assertTrue("test pound at failed for string: " + acceptedString + " for tags: " + tags.toString(), tags.contains(tag)); assertTrue(
"test pound at failed for string: " + acceptedString + " for tags: " + tags.toString(),
tags.contains(tag));
} }
} }
/** tests all words using priority 0 */ /**
* tests all words using priority 0
*/
@Test @Test
public void testTagsAt() throws Exception { public void testTagsAt() throws Exception {
String[] acceptedStrings = { String[] acceptedStrings = {
@ -522,7 +539,9 @@ public class TitleParserTest extends InjectingTestCase {
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);
assertTrue("testTagsAt failed for string: " + acceptedString + " for tags: " + tags.toString(), tags.contains(tag)); assertTrue(
"testTagsAt failed for string: " + acceptedString + " for tags: " + tags.toString(),
tags.contains(tag));
} }
} }
} }

@ -1,22 +1,22 @@
package com.todoroo.astrid.subtasks; package com.todoroo.astrid.subtasks;
import android.support.test.runner.AndroidJUnit4; import static junit.framework.Assert.assertEquals;
import android.support.test.runner.AndroidJUnit4;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import org.tasks.data.TaskListMetadata; import javax.inject.Inject;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.tasks.data.TaskListMetadata;
import org.tasks.injection.TestComponent; import org.tasks.injection.TestComponent;
import javax.inject.Inject;
import static junit.framework.Assert.assertEquals;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
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 String EXPECTED_REMOTE = "[\"-1\", [\"6\", \"4\", [\"3\", \"1\"]], \"2\", \"5\"]"
.replaceAll("\\s", "");
@Inject TaskDao taskDao; @Inject TaskDao taskDao;
@Override @Override
@ -25,7 +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, SubtasksHelper.convertTreeToRemoteIds(taskDao, DEFAULT_SERIALIZED_TREE)); updater.initializeFromSerializedTree(m, filter,
SubtasksHelper.convertTreeToRemoteIds(taskDao, DEFAULT_SERIALIZED_TREE));
} }
private void createTask(String title, String uuid) { private void createTask(String title, String uuid) {
@ -44,7 +45,7 @@ public class SubtasksHelperTest extends SubtasksTestCase {
createTask("F", "5"); // Local id 6 createTask("F", "5"); // Local id 6
} }
private static final String[] EXPECTED_ORDER = { "-1", "1", "2", "3", "4", "5", "6" }; // Default order: "[-1, [1, 2, [3, 4]], 5, 6]"
@Test @Test
public void testOrderedIdArray() { public void testOrderedIdArray() {
@ -55,12 +56,10 @@ public class SubtasksHelperTest extends SubtasksTestCase {
} }
} }
// Default order: "[-1, [1, 2, [3, 4]], 5, 6]"
private static String EXPECTED_REMOTE = "[\"-1\", [\"6\", \"4\", [\"3\", \"1\"]], \"2\", \"5\"]".replaceAll("\\s", "");
@Test @Test
public void testLocalToRemoteIdMapping() { public void testLocalToRemoteIdMapping() {
String mapped = SubtasksHelper.convertTreeToRemoteIds(taskDao, DEFAULT_SERIALIZED_TREE).replaceAll("\\s", ""); String mapped = SubtasksHelper.convertTreeToRemoteIds(taskDao, DEFAULT_SERIALIZED_TREE)
.replaceAll("\\s", "");
assertEquals(EXPECTED_REMOTE, mapped); assertEquals(EXPECTED_REMOTE, mapped);
} }

@ -1,16 +1,13 @@
package com.todoroo.astrid.subtasks; package com.todoroo.astrid.subtasks;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import org.tasks.data.TaskListMetadata; import javax.inject.Inject;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.tasks.data.TaskListMetadata;
import javax.inject.Inject;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class SubtasksMovingTest extends SubtasksTestCase { public class SubtasksMovingTest extends SubtasksTestCase {
@ -19,13 +16,14 @@ public class SubtasksMovingTest extends SubtasksTestCase {
private Task A, B, C, D, E, F; private Task A, B, C, D, E, F;
// @Override // @Override
protected void disabled_setUp() { protected void disabled_setUp() {
super.setUp(); super.setUp();
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, SubtasksHelper.convertTreeToRemoteIds(taskDao, DEFAULT_SERIALIZED_TREE)); updater.initializeFromSerializedTree(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);

@ -1,36 +1,27 @@
package com.todoroo.astrid.subtasks; package com.todoroo.astrid.subtasks;
import static android.support.test.InstrumentationRegistry.getTargetContext;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import com.todoroo.astrid.api.Filter; import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.core.BuiltInFilterExposer; import com.todoroo.astrid.core.BuiltInFilterExposer;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import org.tasks.data.TaskListMetadataDao;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.subtasks.SubtasksFilterUpdater.Node; import com.todoroo.astrid.subtasks.SubtasksFilterUpdater.Node;
import javax.inject.Inject;
import org.tasks.data.TaskListMetadataDao;
import org.tasks.injection.InjectingTestCase; import org.tasks.injection.InjectingTestCase;
import org.tasks.injection.TestComponent; import org.tasks.injection.TestComponent;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
import javax.inject.Inject;
import static android.support.test.InstrumentationRegistry.getTargetContext;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
/** /**
* Contains useful methods common to all subtasks tests * Contains useful methods common to all subtasks tests
* @author Sam
* *
* @author Sam
*/ */
public class SubtasksTestCase extends InjectingTestCase { public class SubtasksTestCase extends InjectingTestCase {
@Inject TaskListMetadataDao taskListMetadataDao;
@Inject TaskDao taskDao;
@Inject Preferences preferences;
protected SubtasksFilterUpdater updater;
protected Filter filter;
/* Starting State: /* Starting State:
* *
* A * A
@ -40,7 +31,13 @@ public class SubtasksTestCase extends InjectingTestCase {
* E * E
* F * F
*/ */
public static final String DEFAULT_SERIALIZED_TREE = "[-1, [1, 2, [3, 4]], 5, 6]".replaceAll("\\s", ""); public static final String DEFAULT_SERIALIZED_TREE = "[-1, [1, 2, [3, 4]], 5, 6]"
.replaceAll("\\s", "");
protected SubtasksFilterUpdater updater;
protected Filter filter;
@Inject TaskListMetadataDao taskListMetadataDao;
@Inject TaskDao taskDao;
@Inject Preferences preferences;
@Override @Override
public void setUp() { public void setUp() {

@ -1,17 +1,17 @@
package com.todoroo.astrid.sync; package com.todoroo.astrid.sync;
import org.tasks.data.TagDataDao;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import org.tasks.data.TagData;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import javax.inject.Inject;
import org.tasks.data.TagData;
import org.tasks.data.TagDataDao;
import org.tasks.injection.InjectingTestCase; import org.tasks.injection.InjectingTestCase;
import org.tasks.injection.TestComponent; import org.tasks.injection.TestComponent;
import javax.inject.Inject;
public class NewSyncTestCase extends InjectingTestCase { public class NewSyncTestCase extends InjectingTestCase {
public static final String SYNC_TASK_TITLE = "new title";
public static final int SYNC_TASK_IMPORTANCE = Task.IMPORTANCE_MUST_DO;
@Inject TaskDao taskDao; @Inject TaskDao taskDao;
@Inject TagDataDao tagDataDao; @Inject TagDataDao tagDataDao;
@ -24,9 +24,6 @@ public class NewSyncTestCase extends InjectingTestCase {
return task; return task;
} }
public static final String SYNC_TASK_TITLE = "new title";
public static final int SYNC_TASK_IMPORTANCE = Task.IMPORTANCE_MUST_DO;
protected Task createTask() { protected Task createTask() {
return createTask(SYNC_TASK_TITLE); return createTask(SYNC_TASK_TITLE);
} }

@ -1,14 +1,12 @@
package com.todoroo.astrid.sync; package com.todoroo.astrid.sync;
import android.support.test.runner.AndroidJUnit4; import static junit.framework.Assert.assertFalse;
import org.tasks.data.TagData; import android.support.test.runner.AndroidJUnit4;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.tasks.data.TagData;
import static junit.framework.Assert.assertFalse;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class SyncModelTest extends NewSyncTestCase { public class SyncModelTest extends NewSyncTestCase {

@ -1,10 +1,10 @@
package org.tasks; package org.tasks;
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
import org.tasks.time.DateTime; import org.tasks.time.DateTime;
import org.tasks.time.DateTimeUtils; import org.tasks.time.DateTimeUtils;
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
public class Freeze { public class Freeze {
public static Freeze freezeClock() { public static Freeze freezeClock() {

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

@ -3,6 +3,7 @@ package org.tasks;
import android.content.Context; import android.content.Context;
public class TestUtilities { public class TestUtilities {
private static boolean mockitoInitialized; private static boolean mockitoInitialized;
public static void initializeMockito(Context context) { public static void initializeMockito(Context context) {

@ -1,19 +1,17 @@
package org.tasks.date; package org.tasks.date;
import android.support.test.runner.AndroidJUnit4; import static junit.framework.Assert.assertEquals;
import static org.tasks.Freeze.freezeAt;
import static org.tasks.date.DateTimeUtils.newDateUtc;
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
import android.support.test.runner.AndroidJUnit4;
import java.util.TimeZone;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.tasks.Snippet; import org.tasks.Snippet;
import org.tasks.time.DateTime; import org.tasks.time.DateTime;
import java.util.TimeZone;
import static junit.framework.Assert.assertEquals;
import static org.tasks.Freeze.freezeAt;
import static org.tasks.date.DateTimeUtils.newDateUtc;
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class DateTimeUtilsTest { public class DateTimeUtilsTest {
@ -29,7 +27,8 @@ public class DateTimeUtilsTest {
@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(), utc.getHourOfDay(), utc.getMinuteOfHour(), utc.getSecondOfMinute()); DateTime actual = newDateUtc(utc.getYear(), utc.getMonthOfYear(), utc.getDayOfMonth(),
utc.getHourOfDay(), utc.getMinuteOfHour(), utc.getSecondOfMinute());
assertEquals(utc.getMillis(), actual.getMillis()); assertEquals(utc.getMillis(), actual.getMillis());
} }

@ -1,10 +1,10 @@
package org.tasks.injection; package org.tasks.injection;
import org.junit.Before;
import static android.support.test.InstrumentationRegistry.getTargetContext; import static android.support.test.InstrumentationRegistry.getTargetContext;
import static org.tasks.TestUtilities.initializeMockito; import static org.tasks.TestUtilities.initializeMockito;
import org.junit.Before;
public abstract class InjectingTestCase { public abstract class InjectingTestCase {
protected TestComponent component; protected TestComponent component;

@ -2,27 +2,28 @@ package org.tasks.injection;
import android.arch.persistence.room.Room; import android.arch.persistence.room.Room;
import android.content.Context; import android.content.Context;
import com.todoroo.astrid.dao.Database; import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import dagger.Module;
import dagger.Provides;
import org.tasks.data.AlarmDao; import org.tasks.data.AlarmDao;
import org.tasks.data.CaldavDao;
import org.tasks.data.FilterDao;
import org.tasks.data.GoogleTaskDao; import org.tasks.data.GoogleTaskDao;
import org.tasks.data.GoogleTaskListDao; import org.tasks.data.GoogleTaskListDao;
import org.tasks.data.LocationDao; import org.tasks.data.LocationDao;
import org.tasks.data.TagDao; import org.tasks.data.TagDao;
import org.tasks.data.TagDataDao; import org.tasks.data.TagDataDao;
import org.tasks.data.TaskAttachmentDao;
import org.tasks.data.TaskListMetadataDao; import org.tasks.data.TaskListMetadataDao;
import org.tasks.data.UserActivityDao; import org.tasks.data.UserActivityDao;
import org.tasks.notifications.NotificationDao; import org.tasks.notifications.NotificationDao;
import org.tasks.preferences.PermissionChecker; import org.tasks.preferences.PermissionChecker;
import org.tasks.preferences.PermissivePermissionChecker; import org.tasks.preferences.PermissivePermissionChecker;
import dagger.Module;
import dagger.Provides;
@Module @Module
public class TestModule { public class TestModule {
private Context context; private Context context;
public TestModule(Context context) { public TestModule(Context context) {
@ -89,6 +90,21 @@ public class TestModule {
return taskDao; return taskDao;
} }
@Provides
public CaldavDao getCaldavDao(Database database) {
return database.getCaldavDao();
}
@Provides
public FilterDao getFilterDao(Database database) {
return database.getFilterDao();
}
@Provides
public TaskAttachmentDao getTaskAttachmentDao(Database database) {
return database.getTaskAttachmentDao();
}
@ApplicationScope @ApplicationScope
@Provides @Provides
@ForApplication @ForApplication

@ -3,38 +3,35 @@
* *
* See the file "LICENSE" for the full license governing this code. * See the file "LICENSE" for the full license governing this code.
*/ */
package org.tasks.jobs; package org.tasks.jobs;
import android.support.test.runner.AndroidJUnit4; import static android.support.test.InstrumentationRegistry.getTargetContext;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.tasks.date.DateTimeUtils.newDateTime;
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
import android.support.test.runner.AndroidJUnit4;
import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.andlib.utility.AndroidUtilities;
import org.tasks.backup.TasksJsonExporter;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import java.io.File;
import java.io.IOException;
import javax.inject.Inject;
import org.junit.After; import org.junit.After;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.tasks.R; import org.tasks.R;
import org.tasks.backup.TasksJsonExporter;
import org.tasks.injection.InjectingTestCase; import org.tasks.injection.InjectingTestCase;
import org.tasks.injection.TestComponent; import org.tasks.injection.TestComponent;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
import org.tasks.scheduling.AlarmManager; import org.tasks.scheduling.AlarmManager;
import java.io.File;
import java.io.IOException;
import javax.inject.Inject;
import static android.support.test.InstrumentationRegistry.getTargetContext;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.tasks.date.DateTimeUtils.newDateTime;
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class BackupServiceTests extends InjectingTestCase { public class BackupServiceTests extends InjectingTestCase {
@ -56,10 +53,14 @@ public class BackupServiceTests extends InjectingTestCase {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
if (!(temporaryDirectory.delete())) if (!(temporaryDirectory.delete())) {
throw new RuntimeException("Could not delete temp file: " + temporaryDirectory.getAbsolutePath()); throw new RuntimeException(
if (!(temporaryDirectory.mkdir())) "Could not delete temp file: " + temporaryDirectory.getAbsolutePath());
throw new RuntimeException("Could not create temp directory: " + temporaryDirectory.getAbsolutePath()); }
if (!(temporaryDirectory.mkdir())) {
throw new RuntimeException(
"Could not create temp directory: " + temporaryDirectory.getAbsolutePath());
}
preferences.setString(R.string.p_backup_dir, temporaryDirectory.getAbsolutePath()); preferences.setString(R.string.p_backup_dir, temporaryDirectory.getAbsolutePath());
@ -77,8 +78,9 @@ public class BackupServiceTests extends InjectingTestCase {
@After @After
public void tearDown() { public void tearDown() {
if (temporaryDirectory != null) { if (temporaryDirectory != null) {
for (File file : temporaryDirectory.listFiles()) for (File file : temporaryDirectory.listFiles()) {
file.delete(); file.delete();
}
temporaryDirectory.delete(); temporaryDirectory.delete();
} }
} }
@ -91,7 +93,8 @@ public class BackupServiceTests extends InjectingTestCase {
preferences.setLong(TasksJsonExporter.PREF_BACKUP_LAST_DATE, 0); preferences.setLong(TasksJsonExporter.PREF_BACKUP_LAST_DATE, 0);
// create a backup // create a backup
BackupJob service = new BackupJob(getTargetContext(), new JobManager(getTargetContext(), mock(AlarmManager.class)), xmlExporter, preferences); BackupJob service = new BackupJob(getTargetContext(),
new JobManager(getTargetContext(), mock(AlarmManager.class)), xmlExporter, preferences);
service.startBackup(getTargetContext()); service.startBackup(getTargetContext());
AndroidUtilities.sleepDeep(BACKUP_WAIT_TIME); AndroidUtilities.sleepDeep(BACKUP_WAIT_TIME);
@ -129,7 +132,8 @@ public class BackupServiceTests extends InjectingTestCase {
assertEquals(11, files.length); assertEquals(11, files.length);
// backup // backup
BackupJob service = new BackupJob(getTargetContext(), new JobManager(getTargetContext(), mock(AlarmManager.class)), xmlExporter, preferences); BackupJob service = new BackupJob(getTargetContext(),
new JobManager(getTargetContext(), mock(AlarmManager.class)), xmlExporter, preferences);
service.startBackup(getTargetContext()); service.startBackup(getTargetContext());
AndroidUtilities.sleepDeep(BACKUP_WAIT_TIME); AndroidUtilities.sleepDeep(BACKUP_WAIT_TIME);

@ -1,20 +1,5 @@
package org.tasks.jobs; package org.tasks.jobs;
import android.support.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.tasks.Freeze;
import org.tasks.Snippet;
import org.tasks.preferences.Preferences;
import org.tasks.time.DateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static com.google.common.collect.Sets.newHashSet; import static com.google.common.collect.Sets.newHashSet;
import static com.todoroo.astrid.reminders.ReminderService.TYPE_DUE; import static com.todoroo.astrid.reminders.ReminderService.TYPE_DUE;
import static com.todoroo.astrid.reminders.ReminderService.TYPE_SNOOZE; import static com.todoroo.astrid.reminders.ReminderService.TYPE_SNOOZE;
@ -30,6 +15,19 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static org.tasks.time.DateTimeUtils.currentTimeMillis; import static org.tasks.time.DateTimeUtils.currentTimeMillis;
import android.support.test.runner.AndroidJUnit4;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.tasks.Freeze;
import org.tasks.Snippet;
import org.tasks.preferences.Preferences;
import org.tasks.time.DateTime;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class JobQueueTest { public class JobQueueTest {
@ -310,7 +308,8 @@ public class JobQueueTest {
Freeze.freezeAt(now).thawAfter(new Snippet() {{ Freeze.freezeAt(now).thawAfter(new Snippet() {{
List<? extends JobQueueEntry> overdueJobs = queue.getOverdueJobs(); List<? extends JobQueueEntry> overdueJobs = queue.getOverdueJobs();
assertEquals( assertEquals(
asList(new Reminder(1, due.getMillis(), TYPE_DUE), new Reminder(2, snooze.getMillis(), TYPE_SNOOZE)), asList(new Reminder(1, due.getMillis(), TYPE_DUE),
new Reminder(2, snooze.getMillis(), TYPE_SNOOZE)),
overdueJobs); overdueJobs);
queue.remove(overdueJobs); queue.remove(overdueJobs);
assertEquals( assertEquals(

@ -1,14 +1,13 @@
package org.tasks.makers; package org.tasks.makers;
import static com.natpryce.makeiteasy.Property.newProperty;
import static org.tasks.makers.Maker.make;
import com.natpryce.makeiteasy.Instantiator; import com.natpryce.makeiteasy.Instantiator;
import com.natpryce.makeiteasy.Property; import com.natpryce.makeiteasy.Property;
import com.natpryce.makeiteasy.PropertyValue; import com.natpryce.makeiteasy.PropertyValue;
import org.tasks.data.GoogleTaskList; import org.tasks.data.GoogleTaskList;
import static com.natpryce.makeiteasy.Property.newProperty;
import static org.tasks.makers.Maker.make;
public class GtaskListMaker { public class GtaskListMaker {
public static final Property<GoogleTaskList, Long> ID = newProperty(); public static final Property<GoogleTaskList, Long> ID = newProperty();
@ -17,11 +16,6 @@ public class GtaskListMaker {
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();
public static final Property<GoogleTaskList, Integer> COLOR = newProperty(); public static final Property<GoogleTaskList, Integer> COLOR = newProperty();
public static GoogleTaskList newGtaskList(PropertyValue<? super GoogleTaskList, ?>... properties) {
return make(instantiator, properties);
}
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));
@ -31,4 +25,9 @@ public class GtaskListMaker {
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(
PropertyValue<? super GoogleTaskList, ?>... properties) {
return make(instantiator, properties);
}
} }

@ -1,13 +1,15 @@
package org.tasks.makers; package org.tasks.makers;
import static com.natpryce.makeiteasy.MakeItEasy.a;
import com.natpryce.makeiteasy.Instantiator; import com.natpryce.makeiteasy.Instantiator;
import com.natpryce.makeiteasy.PropertyValue; import com.natpryce.makeiteasy.PropertyValue;
import static com.natpryce.makeiteasy.MakeItEasy.a;
public class Maker { public class Maker {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T> T make(Instantiator<T> instantiator, PropertyValue<? super T, ?>... properties) { public static <T> T make(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));
} }
} }

@ -1,18 +1,17 @@
package org.tasks.makers; package org.tasks.makers;
import static com.natpryce.makeiteasy.Property.newProperty;
import static org.tasks.date.DateTimeUtils.newDateTime;
import static org.tasks.makers.Maker.make;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.ical.values.RRule; import com.google.ical.values.RRule;
import com.natpryce.makeiteasy.Instantiator; import com.natpryce.makeiteasy.Instantiator;
import com.natpryce.makeiteasy.Property; import com.natpryce.makeiteasy.Property;
import com.natpryce.makeiteasy.PropertyValue; import com.natpryce.makeiteasy.PropertyValue;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import org.tasks.time.DateTime; import org.tasks.time.DateTime;
import static com.natpryce.makeiteasy.Property.newProperty;
import static org.tasks.date.DateTimeUtils.newDateTime;
import static org.tasks.makers.Maker.make;
public class TaskMaker { public class TaskMaker {
public static Property<Task, Long> ID = newProperty(); public static Property<Task, Long> ID = newProperty();
@ -30,12 +29,6 @@ public class TaskMaker {
public static Property<Task, DateTime> SNOOZE_TIME = newProperty(); public static Property<Task, DateTime> SNOOZE_TIME = newProperty();
public static Property<Task, RRule> RRULE = newProperty(); public static Property<Task, RRule> RRULE = newProperty();
public static Property<Task, Boolean> AFTER_COMPLETE = newProperty(); public static Property<Task, Boolean> AFTER_COMPLETE = newProperty();
@SafeVarargs
public static Task newTask(PropertyValue<? super Task, ?>... properties) {
return make(instantiator, properties);
}
private static final Instantiator<Task> instantiator = lookup -> { private static final Instantiator<Task> instantiator = lookup -> {
Task task = new Task(); Task task = new Task();
@ -109,4 +102,9 @@ public class TaskMaker {
return task; return task;
}; };
@SafeVarargs
public static Task newTask(PropertyValue<? super Task, ?>... properties) {
return make(instantiator, properties);
}
} }

@ -1,10 +1,10 @@
package org.tasks.preferences; package org.tasks.preferences;
import android.content.Context; import android.content.Context;
import org.tasks.injection.ForApplication; import org.tasks.injection.ForApplication;
public class PermissivePermissionChecker extends PermissionChecker { public class PermissivePermissionChecker extends PermissionChecker {
public PermissivePermissionChecker(@ForApplication Context context) { public PermissivePermissionChecker(@ForApplication Context context) {
super(context); super(context);
} }

@ -1,19 +1,17 @@
package org.tasks.preferences; package org.tasks.preferences;
import static android.support.test.InstrumentationRegistry.getTargetContext;
import static junit.framework.Assert.assertEquals;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
import java.util.concurrent.TimeUnit;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.tasks.R; import org.tasks.R;
import org.tasks.time.DateTime; import org.tasks.time.DateTime;
import java.util.concurrent.TimeUnit;
import static android.support.test.InstrumentationRegistry.getTargetContext;
import static junit.framework.Assert.assertEquals;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class PreferenceTests { public class PreferenceTests {

@ -1,18 +1,15 @@
package org.tasks.repeats; package org.tasks.repeats;
import android.support.test.runner.AndroidJUnit4; import static android.support.test.InstrumentationRegistry.getTargetContext;
import static junit.framework.Assert.assertEquals;
import android.support.test.runner.AndroidJUnit4;
import com.google.ical.values.RRule; import com.google.ical.values.RRule;
import java.text.ParseException;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.tasks.locale.Locale; import org.tasks.locale.Locale;
import java.text.ParseException;
import static android.support.test.InstrumentationRegistry.getTargetContext;
import static junit.framework.Assert.assertEquals;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class RepeatRuleToStringTest { public class RepeatRuleToStringTest {
@ -28,17 +25,20 @@ public class RepeatRuleToStringTest {
@Test @Test
public void weeklyByDay() { public void weeklyByDay() {
assertEquals("Repeats weekly on Mon, Tue, Wed, Thu, Fri", toString("RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR")); assertEquals("Repeats weekly on Mon, Tue, Wed, Thu, Fri",
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", toString("RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=FR,TH,WE,TU,MO")); assertEquals("Repeats weekly on Fri, Thu, Wed, Tue, Mon",
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.", toString("de", "RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=SA,SU")); assertEquals("Wiederhole wöchentlich am Sa., So.",
toString("de", "RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=SA,SU"));
} }
private String toString(String rrule) { private String toString(String rrule) {

@ -1,21 +1,20 @@
package org.tasks.time; package org.tasks.time;
import android.support.test.runner.AndroidJUnit4; import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import android.support.test.runner.AndroidJUnit4;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.tasks.Freeze; import org.tasks.Freeze;
import org.tasks.Snippet; import org.tasks.Snippet;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class DateTimeTest { public class DateTimeTest {
@Test @Test
public void testGetMillisOfDay() { public void testGetMillisOfDay() {
assertEquals(7248412, new DateTime(2015, 10, 6, 2, 0, 48, 412).getMillisOfDay()); assertEquals(7248412, new DateTime(2015, 10, 6, 2, 0, 48, 412).getMillisOfDay());
@ -33,7 +32,9 @@ 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, new DateTime(2015, 10, 31, 2, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(2)).getHourOfDay()); assertEquals(2,
new DateTime(2015, 10, 31, 2, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(2))
.getHourOfDay());
} finally { } finally {
TimeZone.setDefault(def); TimeZone.setDefault(def);
} }
@ -44,7 +45,9 @@ 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, new DateTime(2015, 11, 2, 2, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(2)).getHourOfDay()); assertEquals(2,
new DateTime(2015, 11, 2, 2, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(2))
.getHourOfDay());
} finally { } finally {
TimeZone.setDefault(def); TimeZone.setDefault(def);
} }
@ -55,14 +58,24 @@ 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, new DateTime(2015, 3, 8, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(1)).getHourOfDay()); assertEquals(1,
assertEquals(3, new DateTime(2015, 3, 8, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(2)).getHourOfDay()); new DateTime(2015, 3, 8, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(1))
assertEquals(3, new DateTime(2015, 3, 8, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(3)).getHourOfDay()); .getHourOfDay());
assertEquals(4, new DateTime(2015, 3, 8, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(4)).getHourOfDay()); assertEquals(3,
new DateTime(2015, 3, 8, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(2))
.getHourOfDay());
assertEquals(3,
new DateTime(2015, 3, 8, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(3))
.getHourOfDay());
assertEquals(4,
new DateTime(2015, 3, 8, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(4))
.getHourOfDay());
assertEquals( assertEquals(
new DateTime(2015, 3, 8, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(2)).getMillis(), 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(3)).getMillis()); .getMillis(),
new DateTime(2015, 3, 8, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(3))
.getMillis());
} finally { } finally {
TimeZone.setDefault(def); TimeZone.setDefault(def);
} }
@ -73,9 +86,15 @@ 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, new DateTime(2015, 11, 1, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(1)).getHourOfDay()); assertEquals(1,
assertEquals(2, new DateTime(2015, 11, 1, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(2)).getHourOfDay()); new DateTime(2015, 11, 1, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(1))
assertEquals(3, new DateTime(2015, 11, 1, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(3)).getHourOfDay()); .getHourOfDay());
assertEquals(2,
new DateTime(2015, 11, 1, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(2))
.getHourOfDay());
assertEquals(3,
new DateTime(2015, 11, 1, 0, 0, 0).withMillisOfDay((int) TimeUnit.HOURS.toMillis(3))
.getHourOfDay());
} finally { } finally {
TimeZone.setDefault(def); TimeZone.setDefault(def);
} }

@ -13,14 +13,13 @@ import com.todoroo.astrid.service.TitleParserTest;
import com.todoroo.astrid.subtasks.SubtasksHelperTest; import com.todoroo.astrid.subtasks.SubtasksHelperTest;
import com.todoroo.astrid.subtasks.SubtasksTestCase; import com.todoroo.astrid.subtasks.SubtasksTestCase;
import com.todoroo.astrid.sync.NewSyncTestCase; import com.todoroo.astrid.sync.NewSyncTestCase;
import org.tasks.jobs.BackupServiceTests;
import dagger.Component; import dagger.Component;
import org.tasks.jobs.BackupServiceTests;
@ApplicationScope @ApplicationScope
@Component(modules = TestModule.class) @Component(modules = TestModule.class)
public interface TestComponent { public interface TestComponent {
Database getDatabase(); Database getDatabase();
void inject(ReminderServiceTest reminderServiceTest); void inject(ReminderServiceTest reminderServiceTest);
@ -47,5 +46,6 @@ public interface TestComponent {
void inject(BackupServiceTests backupServiceTests); void inject(BackupServiceTests backupServiceTests);
NotificationTests.NotificationTestsComponent plus(NotificationTests.NotificationTestsModule notificationTestsModule); NotificationTests.NotificationTestsComponent plus(
NotificationTests.NotificationTestsModule notificationTestsModule);
} }

@ -13,14 +13,13 @@ import com.todoroo.astrid.service.TitleParserTest;
import com.todoroo.astrid.subtasks.SubtasksHelperTest; import com.todoroo.astrid.subtasks.SubtasksHelperTest;
import com.todoroo.astrid.subtasks.SubtasksTestCase; import com.todoroo.astrid.subtasks.SubtasksTestCase;
import com.todoroo.astrid.sync.NewSyncTestCase; import com.todoroo.astrid.sync.NewSyncTestCase;
import org.tasks.jobs.BackupServiceTests;
import dagger.Component; import dagger.Component;
import org.tasks.jobs.BackupServiceTests;
@ApplicationScope @ApplicationScope
@Component(modules = TestModule.class) @Component(modules = TestModule.class)
public interface TestComponent { public interface TestComponent {
Database getDatabase(); Database getDatabase();
void inject(ReminderServiceTest reminderServiceTest); void inject(ReminderServiceTest reminderServiceTest);
@ -47,5 +46,6 @@ public interface TestComponent {
void inject(BackupServiceTests backupServiceTests); void inject(BackupServiceTests backupServiceTests);
NotificationTests.NotificationTestsComponent plus(NotificationTests.NotificationTestsModule notificationTestsModule); NotificationTests.NotificationTestsComponent plus(
NotificationTests.NotificationTestsModule notificationTestsModule);
} }

@ -3,14 +3,19 @@
* *
* See the file "LICENSE" for the full license governing this code. * See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.gtasks; package com.todoroo.astrid.gtasks;
import android.support.test.runner.AndroidJUnit4; import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import android.support.test.runner.AndroidJUnit4;
import com.google.api.services.tasks.model.TaskList; import com.google.api.services.tasks.model.TaskList;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.tasks.data.GoogleTask; import org.tasks.data.GoogleTask;
@ -19,14 +24,6 @@ import org.tasks.data.GoogleTaskList;
import org.tasks.injection.InjectingTestCase; import org.tasks.injection.InjectingTestCase;
import org.tasks.injection.TestComponent; import org.tasks.injection.TestComponent;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
@SuppressWarnings("nls") @SuppressWarnings("nls")
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class GtasksIndentActionTest extends InjectingTestCase { public class GtasksIndentActionTest extends InjectingTestCase {

@ -1,12 +1,24 @@
package com.todoroo.astrid.gtasks; package com.todoroo.astrid.gtasks;
import android.support.test.runner.AndroidJUnit4; import static com.natpryce.makeiteasy.MakeItEasy.with;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNull;
import static org.tasks.makers.GtaskListMaker.ID;
import static org.tasks.makers.GtaskListMaker.LAST_SYNC;
import static org.tasks.makers.GtaskListMaker.NAME;
import static org.tasks.makers.GtaskListMaker.REMOTE_ID;
import static org.tasks.makers.GtaskListMaker.newGtaskList;
import static org.tasks.makers.RemoteGtaskListMaker.newRemoteList;
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
import android.support.test.runner.AndroidJUnit4;
import com.google.api.client.util.DateTime; import com.google.api.client.util.DateTime;
import com.google.api.services.tasks.model.TaskList; import com.google.api.services.tasks.model.TaskList;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.service.TaskDeleter; import com.todoroo.astrid.service.TaskDeleter;
import javax.inject.Inject;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.tasks.LocalBroadcastManager; import org.tasks.LocalBroadcastManager;
@ -17,21 +29,6 @@ import org.tasks.injection.InjectingTestCase;
import org.tasks.injection.TestComponent; import org.tasks.injection.TestComponent;
import org.tasks.makers.RemoteGtaskListMaker; import org.tasks.makers.RemoteGtaskListMaker;
import javax.inject.Inject;
import static com.natpryce.makeiteasy.MakeItEasy.with;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNull;
import static org.tasks.makers.GtaskListMaker.ID;
import static org.tasks.makers.GtaskListMaker.LAST_SYNC;
import static org.tasks.makers.GtaskListMaker.NAME;
import static org.tasks.makers.GtaskListMaker.REMOTE_ID;
import static org.tasks.makers.GtaskListMaker.newGtaskList;
import static org.tasks.makers.RemoteGtaskListMaker.newRemoteList;
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class GtasksListServiceTest extends InjectingTestCase { public class GtasksListServiceTest extends InjectingTestCase {
@ -117,7 +114,8 @@ public class GtasksListServiceTest extends InjectingTestCase {
@Test @Test
public void testNewListNeedsUpdate() { public void testNewListNeedsUpdate() {
TaskList taskList = new TaskList().setId("1").setTitle("Default").setUpdated(new DateTime(currentTimeMillis())); TaskList taskList = new TaskList().setId("1").setTitle("Default")
.setUpdated(new DateTime(currentTimeMillis()));
setLists(taskList); setLists(taskList);

@ -3,14 +3,21 @@
* *
* See the file "LICENSE" for the full license governing this code. * 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 junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import android.content.Context; import android.content.Context;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import dagger.Module;
import dagger.Provides;
import dagger.Subcomponent;
import javax.inject.Inject;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.tasks.data.GoogleTask; import org.tasks.data.GoogleTask;
@ -19,60 +26,15 @@ import org.tasks.injection.InjectingTestCase;
import org.tasks.injection.TestComponent; import org.tasks.injection.TestComponent;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
import javax.inject.Inject;
import dagger.Module;
import dagger.Provides;
import dagger.Subcomponent;
import static android.support.test.InstrumentationRegistry.getTargetContext;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
@SuppressWarnings("nls") @SuppressWarnings("nls")
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class GtasksMetadataServiceTest extends InjectingTestCase { public class GtasksMetadataServiceTest extends InjectingTestCase {
@Module
public class GtasksMetadataServiceTestModule {
private final GtasksTestPreferenceService service;
public GtasksMetadataServiceTestModule(Context context) {
service = new GtasksTestPreferenceService(new Preferences(context, null));
}
@Provides
public GtasksTestPreferenceService getGtasksTestPreferenceService() {
return service;
}
@Provides
public GtasksPreferenceService getGtasksPreferenceService() {
return service;
}
}
@Subcomponent(modules = GtasksMetadataServiceTest.GtasksMetadataServiceTestModule.class)
public interface GtasksMetadataServiceTestComponent {
void inject(GtasksMetadataServiceTest gtasksMetadataServiceTest);
}
@Inject GtasksTestPreferenceService preferences;
@Inject TaskDao taskDao; @Inject TaskDao taskDao;
@Inject GoogleTaskDao googleTaskDao; @Inject GoogleTaskDao googleTaskDao;
private Task task; private Task task;
private GoogleTask metadata; private GoogleTask metadata;
@Override
public void setUp() {
super.setUp();
if (preferences.getDefaultList() == null) {
preferences.setDefaultList("list");
}
}
@Override @Override
protected void inject(TestComponent component) { protected void inject(TestComponent component) {
component component
@ -98,8 +60,6 @@ public class GtasksMetadataServiceTest extends InjectingTestCase {
thenExpectNoMetadataFound(); thenExpectNoMetadataFound();
} }
// --- helpers
private void thenExpectNoMetadataFound() { private void thenExpectNoMetadataFound() {
assertNull(metadata); assertNull(metadata);
} }
@ -108,6 +68,8 @@ public class GtasksMetadataServiceTest extends InjectingTestCase {
assertNotNull(metadata); assertNotNull(metadata);
} }
// --- helpers
private void whenSearchForMetadata() { private void whenSearchForMetadata() {
metadata = googleTaskDao.getByTaskId(task.getId()); metadata = googleTaskDao.getByTaskId(task.getId());
} }
@ -135,4 +97,30 @@ public class GtasksMetadataServiceTest extends InjectingTestCase {
taskDao.createNew(task); taskDao.createNew(task);
return task; return task;
} }
@Subcomponent(modules = GtasksMetadataServiceTest.GtasksMetadataServiceTestModule.class)
public interface GtasksMetadataServiceTestComponent {
void inject(GtasksMetadataServiceTest gtasksMetadataServiceTest);
}
@Module
public class GtasksMetadataServiceTestModule {
private final GtasksTestPreferenceService service;
public GtasksMetadataServiceTestModule(Context context) {
service = new GtasksTestPreferenceService(new Preferences(context, null));
}
@Provides
public GtasksTestPreferenceService getGtasksTestPreferenceService() {
return service;
}
@Provides
public GtasksPreferenceService getGtasksPreferenceService() {
return service;
}
}
} }

@ -3,14 +3,19 @@
* *
* See the file "LICENSE" for the full license governing this code. * See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.gtasks; package com.todoroo.astrid.gtasks;
import android.support.test.runner.AndroidJUnit4; import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import android.support.test.runner.AndroidJUnit4;
import com.google.api.services.tasks.model.TaskList; import com.google.api.services.tasks.model.TaskList;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -20,14 +25,6 @@ import org.tasks.data.GoogleTaskList;
import org.tasks.injection.InjectingTestCase; import org.tasks.injection.InjectingTestCase;
import org.tasks.injection.TestComponent; import org.tasks.injection.TestComponent;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
@SuppressWarnings("nls") @SuppressWarnings("nls")
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class GtasksTaskListUpdaterTest extends InjectingTestCase { public class GtasksTaskListUpdaterTest extends InjectingTestCase {
@ -98,7 +95,6 @@ public class GtasksTaskListUpdaterTest extends InjectingTestCase {
thenExpectMetadataIndentAndOrder(newTask, 5, 0); thenExpectMetadataIndentAndOrder(newTask, 5, 0);
} }
// --- helpers // --- helpers
private void thenExpectMetadataIndentAndOrder(Task task, long order, int indent) { private void thenExpectMetadataIndentAndOrder(Task task, long order, int indent) {
@ -111,30 +107,33 @@ public class GtasksTaskListUpdaterTest extends InjectingTestCase {
private void thenExpectMetadataParent(Task task, Task expectedParent) { private void thenExpectMetadataParent(Task task, Task expectedParent) {
GoogleTask metadata = googleTaskDao.getByTaskId(task.getId()); GoogleTask metadata = googleTaskDao.getByTaskId(task.getId());
long parent = metadata.getParent(); long parent = metadata.getParent();
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("Task " + task.getTitle() + " parent " +
expectedParent.getTitle(), expectedParent.getId(), parent); expectedParent.getTitle(), expectedParent.getId(), parent);
} }
}
private void thenExpectSibling(Task task, Task expectedSibling) { private void thenExpectSibling(Task task, Task expectedSibling) {
long sibling = gtasksTaskListUpdater.siblings.get(task.getId()); long sibling = gtasksTaskListUpdater.siblings.get(task.getId());
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("Task " + task.getTitle() + " sibling " +
expectedSibling.getTitle(), expectedSibling.getId(), sibling); expectedSibling.getTitle(), expectedSibling.getId(), sibling);
} }
}
private void thenExpectParent(Task task, Task expectedParent) { private void thenExpectParent(Task task, Task expectedParent) {
long parent = gtasksTaskListUpdater.parents.get(task.getId()); long parent = gtasksTaskListUpdater.parents.get(task.getId());
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("Task " + task.getTitle() + " parent " +
expectedParent.getTitle(), expectedParent.getId(), parent); expectedParent.getTitle(), expectedParent.getId(), parent);
} }
}
@Override @Override
public void setUp() { public void setUp() {
@ -158,7 +157,7 @@ public class GtasksTaskListUpdaterTest extends InjectingTestCase {
} }
void createParentSiblingMaps() { void createParentSiblingMaps() {
for(GoogleTaskList list : gtasksListService.getLists()) { for (GoogleTaskList list : gtasksListService.getLists()) {
gtasksTaskListUpdater.updateParentSiblingMapsFor(list); gtasksTaskListUpdater.updateParentSiblingMapsFor(list);
} }
} }
@ -171,7 +170,7 @@ public class GtasksTaskListUpdaterTest extends InjectingTestCase {
* 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),
@ -186,10 +185,10 @@ public class GtasksTaskListUpdaterTest extends InjectingTestCase {
task.setTitle(title); task.setTitle(title);
taskDao.createNew(task); taskDao.createNew(task);
GoogleTask metadata = new GoogleTask(task.getId(), "1"); GoogleTask metadata = new GoogleTask(task.getId(), "1");
if(order != VALUE_UNSET) { if (order != VALUE_UNSET) {
metadata.setOrder(order); metadata.setOrder(order);
} }
if(indent != VALUE_UNSET) { if (indent != VALUE_UNSET) {
metadata.setIndent(indent); metadata.setIndent(indent);
} }
googleTaskDao.insert(metadata); googleTaskDao.insert(metadata);

@ -3,14 +3,19 @@
* *
* See the file "LICENSE" for the full license governing this code. * See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.astrid.gtasks; package com.todoroo.astrid.gtasks;
import android.support.test.runner.AndroidJUnit4; import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import android.support.test.runner.AndroidJUnit4;
import com.google.api.services.tasks.model.TaskList; import com.google.api.services.tasks.model.TaskList;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.tasks.data.GoogleTask; import org.tasks.data.GoogleTask;
@ -19,14 +24,6 @@ import org.tasks.data.GoogleTaskList;
import org.tasks.injection.InjectingTestCase; import org.tasks.injection.InjectingTestCase;
import org.tasks.injection.TestComponent; import org.tasks.injection.TestComponent;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
@SuppressWarnings("nls") @SuppressWarnings("nls")
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class GtasksTaskMovingTest extends InjectingTestCase { public class GtasksTaskMovingTest extends InjectingTestCase {
@ -246,10 +243,11 @@ public class GtasksTaskMovingTest extends InjectingTestCase {
thenExpectMetadataOrderAndIndent(F, 5, 0); thenExpectMetadataOrderAndIndent(F, 5, 0);
} }
// --- 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());
} }
@ -302,10 +300,10 @@ public class GtasksTaskMovingTest extends InjectingTestCase {
task.setTitle(title); task.setTitle(title);
taskDao.createNew(task); taskDao.createNew(task);
GoogleTask metadata = new GoogleTask(task.getId(), "1"); GoogleTask metadata = new GoogleTask(task.getId(), "1");
if(order != VALUE_UNSET) { if (order != VALUE_UNSET) {
metadata.setOrder(order); metadata.setOrder(order);
} }
if(indent != VALUE_UNSET) { if (indent != VALUE_UNSET) {
metadata.setIndent(indent); metadata.setIndent(indent);
} }
googleTaskDao.insert(metadata); googleTaskDao.insert(metadata);

@ -3,6 +3,7 @@
* *
* See the file "LICENSE" for the full license governing this code. * 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;

@ -1,17 +1,5 @@
package com.todoroo.astrid.gtasks.api; package com.todoroo.astrid.gtasks.api;
import android.support.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.tasks.time.DateTime;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import static com.todoroo.astrid.gtasks.api.GtasksApiUtilities.gtasksCompletedTimeToUnixTime; import static com.todoroo.astrid.gtasks.api.GtasksApiUtilities.gtasksCompletedTimeToUnixTime;
import static com.todoroo.astrid.gtasks.api.GtasksApiUtilities.gtasksDueTimeToUnixTime; import static com.todoroo.astrid.gtasks.api.GtasksApiUtilities.gtasksDueTimeToUnixTime;
import static com.todoroo.astrid.gtasks.api.GtasksApiUtilities.unixTimeToGtasksCompletionTime; import static com.todoroo.astrid.gtasks.api.GtasksApiUtilities.unixTimeToGtasksCompletionTime;
@ -19,6 +7,16 @@ import static com.todoroo.astrid.gtasks.api.GtasksApiUtilities.unixTimeToGtasksD
import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertNull;
import android.support.test.runner.AndroidJUnit4;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.tasks.time.DateTime;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class GtasksApiUtilitiesTest { public class GtasksApiUtilitiesTest {
@ -63,7 +61,8 @@ public class GtasksApiUtilitiesTest {
public void testConvertGoogleDueDateToUnixTime() { public void testConvertGoogleDueDateToUnixTime() {
com.google.api.client.util.DateTime googleDueDate = com.google.api.client.util.DateTime googleDueDate =
new com.google.api.client.util.DateTime( new com.google.api.client.util.DateTime(
new Date(new DateTime(2014, 1, 8, 0, 0, 0, 0).getMillis()), TimeZone.getTimeZone("GMT")); new Date(new DateTime(2014, 1, 8, 0, 0, 0, 0).getMillis()),
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(),

@ -1,13 +1,5 @@
package org.tasks.gtasks; package org.tasks.gtasks;
import android.support.test.runner.AndroidJUnit4;
import com.todoroo.astrid.data.Task;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.tasks.time.DateTime;
import static com.natpryce.makeiteasy.MakeItEasy.with; import static com.natpryce.makeiteasy.MakeItEasy.with;
import static com.todoroo.astrid.data.Task.HIDE_UNTIL_DUE; import static com.todoroo.astrid.data.Task.HIDE_UNTIL_DUE;
import static com.todoroo.astrid.data.Task.HIDE_UNTIL_DUE_TIME; import static com.todoroo.astrid.data.Task.HIDE_UNTIL_DUE_TIME;
@ -18,6 +10,12 @@ import static org.tasks.makers.TaskMaker.DUE_TIME;
import static org.tasks.makers.TaskMaker.HIDE_TYPE; import static org.tasks.makers.TaskMaker.HIDE_TYPE;
import static org.tasks.makers.TaskMaker.newTask; import static org.tasks.makers.TaskMaker.newTask;
import android.support.test.runner.AndroidJUnit4;
import com.todoroo.astrid.data.Task;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.tasks.time.DateTime;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class GoogleTaskSyncAdapterTest { public class GoogleTaskSyncAdapterTest {
@ -45,7 +43,8 @@ public class GoogleTaskSyncAdapterTest {
@Test @Test
public void testDueDateAdjustHideBackwards() { public void testDueDateAdjustHideBackwards() {
Task local = newTask(with(DUE_DATE, new DateTime(2016, 3, 12)), with(HIDE_TYPE, HIDE_UNTIL_DUE)); Task local = 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);
@ -56,7 +55,8 @@ public class GoogleTaskSyncAdapterTest {
@Test @Test
public void testDueDateAdjustHideForwards() { public void testDueDateAdjustHideForwards() {
Task local = newTask(with(DUE_DATE, new DateTime(2016, 3, 12)), with(HIDE_TYPE, HIDE_UNTIL_DUE)); Task local = 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);
@ -91,7 +91,8 @@ public class GoogleTaskSyncAdapterTest {
@Test @Test
public void testDueDateClearHide() { public void testDueDateClearHide() {
Task local = newTask(with(DUE_DATE, new DateTime(2016, 3, 12)), with(HIDE_TYPE, HIDE_UNTIL_DUE)); Task local = newTask(with(DUE_DATE, new DateTime(2016, 3, 12)),
with(HIDE_TYPE, HIDE_UNTIL_DUE));
mergeDates(newTask().getDueDate(), local); mergeDates(newTask().getDueDate(), local);

@ -15,16 +15,15 @@ import com.todoroo.astrid.service.TitleParserTest;
import com.todoroo.astrid.subtasks.SubtasksHelperTest; import com.todoroo.astrid.subtasks.SubtasksHelperTest;
import com.todoroo.astrid.subtasks.SubtasksTestCase; import com.todoroo.astrid.subtasks.SubtasksTestCase;
import com.todoroo.astrid.sync.NewSyncTestCase; import com.todoroo.astrid.sync.NewSyncTestCase;
import org.tasks.jobs.BackupServiceTests;
import dagger.Component; import dagger.Component;
import org.tasks.jobs.BackupServiceTests;
@ApplicationScope @ApplicationScope
@Component(modules = TestModule.class) @Component(modules = TestModule.class)
public interface TestComponent { public interface TestComponent {
GtasksMetadataServiceTest.GtasksMetadataServiceTestComponent plus(GtasksMetadataServiceTest.GtasksMetadataServiceTestModule gtasksMetadataServiceTestModule); GtasksMetadataServiceTest.GtasksMetadataServiceTestComponent plus(
GtasksMetadataServiceTest.GtasksMetadataServiceTestModule gtasksMetadataServiceTestModule);
void inject(GtasksIndentActionTest gtasksIndentActionTest); void inject(GtasksIndentActionTest gtasksIndentActionTest);

@ -1,25 +1,25 @@
package org.tasks.makers; package org.tasks.makers;
import static com.natpryce.makeiteasy.Property.newProperty;
import static org.tasks.makers.Maker.make;
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
import com.google.api.client.util.DateTime; import com.google.api.client.util.DateTime;
import com.google.api.services.tasks.model.TaskList; import com.google.api.services.tasks.model.TaskList;
import com.natpryce.makeiteasy.Instantiator; import com.natpryce.makeiteasy.Instantiator;
import com.natpryce.makeiteasy.Property; import com.natpryce.makeiteasy.Property;
import com.natpryce.makeiteasy.PropertyValue; import com.natpryce.makeiteasy.PropertyValue;
import static com.natpryce.makeiteasy.Property.newProperty;
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
import static org.tasks.makers.Maker.make;
public class RemoteGtaskListMaker { 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();
public static TaskList newRemoteList(PropertyValue<? super TaskList, ?>... properties) {
return make(instantiator, properties);
}
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()));
public static TaskList newRemoteList(PropertyValue<? super TaskList, ?>... properties) {
return make(instantiator, properties);
}
} }

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

@ -3,19 +3,16 @@ package org.tasks;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import android.os.StrictMode; import android.os.StrictMode;
import com.facebook.stetho.Stetho; import com.facebook.stetho.Stetho;
import com.facebook.stetho.timber.StethoTree; import com.facebook.stetho.timber.StethoTree;
import com.squareup.leakcanary.LeakCanary; import com.squareup.leakcanary.LeakCanary;
import javax.inject.Inject;
import org.tasks.injection.ForApplication; import org.tasks.injection.ForApplication;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
import javax.inject.Inject;
import timber.log.Timber; import timber.log.Timber;
public class BuildSetup { public class BuildSetup {
private final Context context; private final Context context;
private final Preferences preferences; private final Preferences preferences;

@ -1,11 +1,11 @@
package org.tasks; package org.tasks;
import javax.inject.Inject;
import org.tasks.caldav.CaldavAccountManager; import org.tasks.caldav.CaldavAccountManager;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
import javax.inject.Inject;
public class FlavorSetup { public class FlavorSetup {
private final CaldavAccountManager caldavAccountManager; private final CaldavAccountManager caldavAccountManager;
private final Preferences preferences; private final Preferences preferences;
@ -16,6 +16,7 @@ public class FlavorSetup {
} }
public void setup() { public void setup() {
caldavAccountManager.setBackgroundSynchronization(preferences.getBoolean(R.string.p_background_sync, true)); caldavAccountManager
.setBackgroundSynchronization(preferences.getBoolean(R.string.p_background_sync, true));
} }
} }

@ -1,7 +1,6 @@
package org.tasks.analytics; package org.tasks.analytics;
import javax.inject.Inject; import javax.inject.Inject;
import timber.log.Timber; import timber.log.Timber;
public class Tracker { public class Tracker {

@ -2,12 +2,11 @@ package org.tasks.billing;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import org.tasks.preferences.Preferences;
import javax.inject.Inject; import javax.inject.Inject;
import org.tasks.preferences.Preferences;
public class PurchaseHelper { public class PurchaseHelper {
private Preferences preferences; private Preferences preferences;
@Inject @Inject
@ -23,7 +22,8 @@ public class PurchaseHelper {
return true; return true;
} }
public void handleActivityResult(PurchaseHelperCallback callback, int requestCode, int resultCode, Intent data) { public void handleActivityResult(PurchaseHelperCallback callback, int requestCode, int resultCode,
Intent data) {
} }

@ -1,10 +1,8 @@
package org.tasks.gtasks; package org.tasks.gtasks;
import android.app.Activity; import android.app.Activity;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential; import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.todoroo.astrid.gtasks.auth.GtasksLoginActivity; import com.todoroo.astrid.gtasks.auth.GtasksLoginActivity;
import javax.inject.Inject; import javax.inject.Inject;
public class PlayServices { public class PlayServices {
@ -34,7 +32,8 @@ public class PlayServices {
return false; return false;
} }
public void getAuthToken(GtasksLoginActivity gtasksLoginActivity, String a, GtasksLoginActivity.AuthResultHandler authResultHandler) { public void getAuthToken(GtasksLoginActivity gtasksLoginActivity, String a,
GtasksLoginActivity.AuthResultHandler authResultHandler) {
} }
} }

@ -1,10 +1,8 @@
package org.tasks.location; package org.tasks.location;
import org.tasks.data.Location;
import java.util.List; import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
import org.tasks.data.Location;
@SuppressWarnings("EmptyMethod") @SuppressWarnings("EmptyMethod")
public class GeofenceApi { public class GeofenceApi {

@ -3,11 +3,11 @@ package org.tasks.location;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import org.tasks.data.Location; import org.tasks.data.Location;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
public class PlacePicker { public class PlacePicker {
public static Intent getIntent(Activity activity) { public static Intent getIntent(Activity activity) {
return null; return null;
} }

@ -33,18 +33,11 @@ import android.content.Intent;
* has been acquired.</p> * has been acquired.</p>
*/ */
public class IabBroadcastReceiver extends BroadcastReceiver { public class IabBroadcastReceiver extends BroadcastReceiver {
/**
* Listener interface for received broadcast messages.
*/
public interface IabBroadcastListener {
void receivedBroadcast();
}
/** /**
* 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) {
@ -57,4 +50,12 @@ public class IabBroadcastReceiver extends BroadcastReceiver {
mListener.receivedBroadcast(); mListener.receivedBroadcast();
} }
} }
/**
* Listener interface for received broadcast messages.
*/
public interface IabBroadcastListener {
void receivedBroadcast();
}
} }

@ -23,22 +23,30 @@ package com.android.vending.billing;
*/ */
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
public class IabException extends Exception { public class IabException extends Exception {
IabResult mResult; IabResult mResult;
public IabException(IabResult r) { public IabException(IabResult r) {
this(r, null); this(r, null);
} }
public IabException(int response, String message) { public IabException(int response, String message) {
this(new IabResult(response, message)); this(new IabResult(response, message));
} }
public IabException(IabResult r, Exception cause) { public IabException(IabResult r, Exception cause) {
super(r.getMessage(), cause); super(r.getMessage(), cause);
mResult = r; mResult = r;
} }
public IabException(int response, String message, Exception cause) { public IabException(int response, String message, Exception cause) {
this(new IabResult(response, message), cause); this(new IabResult(response, message), cause);
} }
/** Returns the IAB result (error) that this exception signals. */ /**
public IabResult getResult() { return mResult; } * Returns the IAB result (error) that this exception signals.
*/
public IabResult getResult() {
return mResult;
}
} }

@ -30,12 +30,10 @@ import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import org.json.JSONException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import org.json.JSONException;
/** /**
@ -66,54 +64,11 @@ import java.util.concurrent.Executor;
* Also, notice that you can only call one asynchronous operation at a time; * Also, notice that you can only call one asynchronous operation at a time;
* attempting to start a second asynchronous operation while the first one * attempting to start a second asynchronous operation while the first one
* has 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")
public class IabHelper { public class IabHelper {
private final Executor executor;
// Is debug logging enabled?
boolean mDebugLog = false;
String mDebugTag = "IabHelper";
// Is setup done?
boolean mSetupDone = false;
// Has this object been disposed of? (If so, we should ignore callbacks, etc)
boolean mDisposed = false;
// Are subscriptions supported?
boolean mSubscriptionsSupported = false;
// Is subscription update supported?
boolean mSubscriptionUpdateSupported = false;
// Is an asynchronous operation in progress?
// (only one at a time can be in progress)
boolean mAsyncInProgress = false;
// (for logging/debugging)
// if mAsyncInProgress == true, what asynchronous operation is in progress?
String mAsyncOperation = "";
// Context we were passed during initialization
Context mContext;
// Connection to the service
IInAppBillingService mService;
ServiceConnection mServiceConn;
// The request code used to launch purchase flow
int mRequestCode;
// The item type of the current purchase flow
String mPurchasingItemType;
// Public key for verifying signature, in base64 encoding
String mSignatureBase64 = null;
// Billing response codes // Billing response codes
public static final int BILLING_RESPONSE_RESULT_OK = 0; public static final int BILLING_RESPONSE_RESULT_OK = 0;
public static final int BILLING_RESPONSE_RESULT_USER_CANCELED = 1; public static final int BILLING_RESPONSE_RESULT_USER_CANCELED = 1;
@ -124,7 +79,6 @@ public class IabHelper {
public static final int BILLING_RESPONSE_RESULT_ERROR = 6; public static final int BILLING_RESPONSE_RESULT_ERROR = 6;
public static final int BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED = 7; public static final int BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED = 7;
public static final int BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED = 8; public static final int BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED = 8;
// IAB Helper error codes // IAB Helper error codes
public static final int IABHELPER_ERROR_BASE = -1000; public static final int IABHELPER_ERROR_BASE = -1000;
public static final int IABHELPER_REMOTE_EXCEPTION = -1001; public static final int IABHELPER_REMOTE_EXCEPTION = -1001;
@ -138,7 +92,6 @@ public class IabHelper {
public static final int IABHELPER_SUBSCRIPTIONS_NOT_AVAILABLE = -1009; public static final int IABHELPER_SUBSCRIPTIONS_NOT_AVAILABLE = -1009;
public static final int IABHELPER_INVALID_CONSUMPTION = -1010; public static final int IABHELPER_INVALID_CONSUMPTION = -1010;
public static final int IABHELPER_SUBSCRIPTION_UPDATE_NOT_AVAILABLE = -1011; public static final int IABHELPER_SUBSCRIPTION_UPDATE_NOT_AVAILABLE = -1011;
// Keys for the responses from InAppBillingService // Keys for the responses from InAppBillingService
public static final String RESPONSE_CODE = "RESPONSE_CODE"; public static final String RESPONSE_CODE = "RESPONSE_CODE";
public static final String RESPONSE_GET_SKU_DETAILS_LIST = "DETAILS_LIST"; public static final String RESPONSE_GET_SKU_DETAILS_LIST = "DETAILS_LIST";
@ -149,14 +102,44 @@ public class IabHelper {
public static final String RESPONSE_INAPP_PURCHASE_DATA_LIST = "INAPP_PURCHASE_DATA_LIST"; public static final String RESPONSE_INAPP_PURCHASE_DATA_LIST = "INAPP_PURCHASE_DATA_LIST";
public static final String RESPONSE_INAPP_SIGNATURE_LIST = "INAPP_DATA_SIGNATURE_LIST"; public static final String RESPONSE_INAPP_SIGNATURE_LIST = "INAPP_DATA_SIGNATURE_LIST";
public static final String INAPP_CONTINUATION_TOKEN = "INAPP_CONTINUATION_TOKEN"; public static final String INAPP_CONTINUATION_TOKEN = "INAPP_CONTINUATION_TOKEN";
// Item types // Item types
public static final String ITEM_TYPE_INAPP = "inapp"; public static final String ITEM_TYPE_INAPP = "inapp";
public static final String ITEM_TYPE_SUBS = "subs"; public static final String ITEM_TYPE_SUBS = "subs";
// some fields on the getSkuDetails response bundle // some fields on the getSkuDetails response bundle
public static final String GET_SKU_DETAILS_ITEM_LIST = "ITEM_ID_LIST"; public static final String GET_SKU_DETAILS_ITEM_LIST = "ITEM_ID_LIST";
public static final String GET_SKU_DETAILS_ITEM_TYPE_LIST = "ITEM_TYPE_LIST"; public static final String GET_SKU_DETAILS_ITEM_TYPE_LIST = "ITEM_TYPE_LIST";
private final Executor executor;
// Is debug logging enabled?
boolean mDebugLog = false;
String mDebugTag = "IabHelper";
// Is setup done?
boolean mSetupDone = false;
// Has this object been disposed of? (If so, we should ignore callbacks, etc)
boolean mDisposed = false;
// Are subscriptions supported?
boolean mSubscriptionsSupported = false;
// Is subscription update supported?
boolean mSubscriptionUpdateSupported = false;
// Is an asynchronous operation in progress?
// (only one at a time can be in progress)
boolean mAsyncInProgress = false;
// (for logging/debugging)
// if mAsyncInProgress == true, what asynchronous operation is in progress?
String mAsyncOperation = "";
// Context we were passed during initialization
Context mContext;
// Connection to the service
IInAppBillingService mService;
ServiceConnection mServiceConn;
// The request code used to launch purchase flow
int mRequestCode;
// The item type of the current purchase flow
String mPurchasingItemType;
// Public key for verifying signature, in base64 encoding
String mSignatureBase64 = null;
// The listener registered on launchPurchaseFlow, which we have to call back when
// the purchase finishes
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
@ -164,10 +147,10 @@ public class IabHelper {
* block and is safe to call from a UI thread. * block and 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. * @param base64PublicKey Your application's public key, encoded in base64. This is used for
* This is used for verification of purchase signatures. You can find your app's base64-encoded * verification of purchase signatures. You can find your app's base64-encoded public key in your
* public key in your application's page on Google Play Developer Console. Note that this * application's page on Google Play Developer Console. Note that this is NOT your "developer
* is NOT your "developer public key". * public key".
*/ */
public IabHelper(Context ctx, String base64PublicKey, Executor executor) { public IabHelper(Context ctx, String base64PublicKey, Executor executor) {
mContext = ctx.getApplicationContext(); mContext = ctx.getApplicationContext();
@ -176,6 +159,43 @@ public class IabHelper {
logDebug("IAB helper created."); logDebug("IAB helper created.");
} }
/**
* Returns a human-readable description for the given response code.
*
* @param code The response code
* @return A human-readable string explaining the result code. It also includes the result code
* numerically.
*/
public static String getResponseDesc(int code) {
String[] iab_msgs = ("0:OK/1:User Canceled/2:Unknown/" +
"3:Billing Unavailable/4:Item unavailable/" +
"5:Developer Error/6:Error/7:Item Already Owned/" +
"8:Item not owned").split("/");
String[] iabhelper_msgs = ("0:OK/-1001:Remote exception during initialization/" +
"-1002:Bad response received/" +
"-1003:Purchase signature verification failed/" +
"-1004:Send intent failed/" +
"-1005:User cancelled/" +
"-1006:Unknown purchase response/" +
"-1007:Missing token/" +
"-1008:Unknown error/" +
"-1009:Subscriptions not available/" +
"-1010:Invalid consumption attempt").split("/");
if (code <= IABHELPER_ERROR_BASE) {
int index = IABHELPER_ERROR_BASE - code;
if (index >= 0 && index < iabhelper_msgs.length) {
return iabhelper_msgs[index];
} else {
return String.valueOf(code) + ":Unknown IAB Helper Error";
}
} else if (code < 0 || code >= iab_msgs.length) {
return String.valueOf(code) + ":Unknown";
} else {
return iab_msgs[code];
}
}
/** /**
* Enables or disable debug logging through LogCat. * Enables or disable debug logging through LogCat.
*/ */
@ -190,19 +210,6 @@ public class IabHelper {
mDebugLog = enable; mDebugLog = enable;
} }
/**
* Callback for setup process. This listener's {@link #onIabSetupFinished} method is called
* when the setup process is complete.
*/
public interface OnIabSetupFinishedListener {
/**
* Called to notify that setup is complete.
*
* @param result The result of the setup process.
*/
void onIabSetupFinished(IabResult result);
}
/** /**
* 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 notified through the listener when the setup process is complete. * You will be notified through the listener when the setup process is complete.
@ -213,7 +220,9 @@ public class IabHelper {
public void startSetup(final OnIabSetupFinishedListener listener) { public void startSetup(final OnIabSetupFinishedListener listener) {
// If already set up, can't do it again. // If already set up, can't do it again.
checkNotDisposed(); checkNotDisposed();
if (mSetupDone) throw new IllegalStateException("IAB helper is already set up."); if (mSetupDone) {
throw new IllegalStateException("IAB helper is already set up.");
}
// Connection to IAB service // Connection to IAB service
logDebug("Starting in-app billing setup."); logDebug("Starting in-app billing setup.");
@ -226,7 +235,9 @@ public class IabHelper {
@Override @Override
public void onServiceConnected(ComponentName name, IBinder service) { public void onServiceConnected(ComponentName name, IBinder service) {
if (mDisposed) return; if (mDisposed) {
return;
}
logDebug("Billing service connected."); logDebug("Billing service connected.");
mService = IInAppBillingService.Stub.asInterface(service); mService = IInAppBillingService.Stub.asInterface(service);
String packageName = mContext.getPackageName(); String packageName = mContext.getPackageName();
@ -236,8 +247,10 @@ public class IabHelper {
// check for in-app billing v3 support // check for in-app billing v3 support
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) listener.onIabSetupFinished(new IabResult(response, if (listener != null) {
listener.onIabSetupFinished(new IabResult(response,
"Error checking for billing v3 support.")); "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
mSubscriptionsSupported = false; mSubscriptionsSupported = false;
@ -274,8 +287,7 @@ 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."));
@ -285,19 +297,20 @@ public class IabHelper {
} }
if (listener != null) { if (listener != null) {
listener.onIabSetupFinished(new IabResult(BILLING_RESPONSE_RESULT_OK, "Setup successful.")); listener
.onIabSetupFinished(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().queryIntentServices(serviceIntent, 0); List<ResolveInfo> intentServices = 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);
} } else {
else {
// no service available to handle that Intent // no service available to handle that Intent
if (listener != null) { if (listener != null) {
listener.onIabSetupFinished( listener.onIabSetupFinished(
@ -318,7 +331,9 @@ public class IabHelper {
mSetupDone = false; mSetupDone = false;
if (mServiceConn != null) { if (mServiceConn != null) {
logDebug("Unbinding from service."); logDebug("Unbinding from service.");
if (mContext != null && mService != null) mContext.unbindService(mServiceConn); if (mContext != null && mService != null) {
mContext.unbindService(mServiceConn);
}
} }
mDisposed = true; mDisposed = true;
mContext = null; mContext = null;
@ -328,37 +343,21 @@ public class IabHelper {
} }
private void checkNotDisposed() { private void checkNotDisposed() {
if (mDisposed) throw new IllegalStateException("IabHelper was disposed of, so it cannot be used."); if (mDisposed) {
throw new IllegalStateException("IabHelper was disposed of, so it cannot be used.");
} }
/** Returns whether subscriptions are supported. */
public boolean subscriptionsSupported() {
checkNotDisposed();
return mSubscriptionsSupported;
} }
/**
* Callback that notifies when a purchase is finished.
*/
public interface OnIabPurchaseFinishedListener {
/** /**
* Called to notify that an in-app purchase finished. If the purchase was successful, * Returns whether subscriptions are supported.
* then the sku parameter specifies which item was purchased. If the purchase failed,
* the sku and extraData parameters may or may not be null, depending on how far the purchase
* process went.
*
* @param result The result of the purchase.
* @param info The purchase information (null if purchase failed)
*/ */
void onIabPurchaseFinished(IabResult result, Purchase info); public boolean subscriptionsSupported() {
checkNotDisposed();
return mSubscriptionsSupported;
} }
// The listener registered on launchPurchaseFlow, which we have to call back when public void launchPurchaseFlow(Activity act, String sku, int requestCode,
// the purchase finishes OnIabPurchaseFinishedListener listener) {
OnIabPurchaseFinishedListener mPurchaseListener;
public void launchPurchaseFlow(Activity act, String sku, int requestCode, OnIabPurchaseFinishedListener listener) {
launchPurchaseFlow(act, sku, requestCode, listener, ""); launchPurchaseFlow(act, sku, requestCode, listener, "");
} }
@ -390,12 +389,12 @@ public class IabHelper {
* @param itemType indicates if it's a product or a subscription (ITEM_TYPE_INAPP or * @param itemType indicates if it's a product or a subscription (ITEM_TYPE_INAPP or
* ITEM_TYPE_SUBS) * ITEM_TYPE_SUBS)
* @param oldSkus A list of SKUs which the new SKU is replacing or null if there are none * @param oldSkus A list of SKUs which the new SKU is replacing or null if there are none
* @param requestCode A request code (to differentiate from other responses -- as in * @param requestCode A request code (to differentiate from other responses -- as in {@link
* {@link android.app.Activity#startActivityForResult}). * android.app.Activity#startActivityForResult}).
* @param listener The listener to notify when the purchase process finishes * @param listener The listener to notify when the purchase process finishes
* @param extraData Extra data (developer payload), which will be returned with the purchase * @param extraData Extra data (developer payload), which will be returned with the purchase data
* data when the purchase completes. This extra data will be permanently bound to that * when the purchase completes. This extra data will be permanently bound to that purchase and
* 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(Activity act, String sku, String itemType, List<String> oldSkus,
int requestCode, OnIabPurchaseFinishedListener listener, String extraData) { int requestCode, OnIabPurchaseFinishedListener listener, String extraData) {
@ -408,7 +407,9 @@ public class IabHelper {
IabResult r = new IabResult(IABHELPER_SUBSCRIPTIONS_NOT_AVAILABLE, IabResult r = new IabResult(IABHELPER_SUBSCRIPTIONS_NOT_AVAILABLE,
"Subscriptions are not available."); "Subscriptions are not available.");
flagEndAsync(); flagEndAsync();
if (listener != null) listener.onIabPurchaseFinished(r, null); if (listener != null) {
listener.onIabPurchaseFinished(r, null);
}
return; return;
} }
@ -425,7 +426,9 @@ public class IabHelper {
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) listener.onIabPurchaseFinished(r, null); if (listener != null) {
listener.onIabPurchaseFinished(r, null);
}
return; return;
} }
buyIntentBundle = mService.getBuyIntentToReplaceSkus(5, mContext.getPackageName(), buyIntentBundle = mService.getBuyIntentToReplaceSkus(5, mContext.getPackageName(),
@ -436,7 +439,9 @@ public class IabHelper {
logError("Unable to buy item, Error response: " + getResponseDesc(response)); logError("Unable to buy item, Error response: " + getResponseDesc(response));
flagEndAsync(); flagEndAsync();
result = new IabResult(response, "Unable to buy item"); result = new IabResult(response, "Unable to buy item");
if (listener != null) listener.onIabPurchaseFinished(result, null); if (listener != null) {
listener.onIabPurchaseFinished(result, null);
}
return; return;
} }
@ -449,22 +454,25 @@ public class IabHelper {
requestCode, new Intent(), requestCode, new Intent(),
Integer.valueOf(0), Integer.valueOf(0), 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);
e.printStackTrace(); e.printStackTrace();
flagEndAsync(); flagEndAsync();
result = new IabResult(IABHELPER_SEND_INTENT_FAILED, "Failed to send intent."); result = new IabResult(IABHELPER_SEND_INTENT_FAILED, "Failed to send intent.");
if (listener != null) listener.onIabPurchaseFinished(result, null); if (listener != null) {
listener.onIabPurchaseFinished(result, null);
} }
catch (RemoteException e) { } catch (RemoteException e) {
logError("RemoteException while launching purchase flow for sku " + sku); logError("RemoteException while launching purchase flow for sku " + sku);
e.printStackTrace(); e.printStackTrace();
flagEndAsync(); flagEndAsync();
result = new IabResult(IABHELPER_REMOTE_EXCEPTION, "Remote exception while starting purchase flow"); result = new IabResult(IABHELPER_REMOTE_EXCEPTION,
if (listener != null) listener.onIabPurchaseFinished(result, null); "Remote exception while starting purchase flow");
if (listener != null) {
listener.onIabPurchaseFinished(result, null);
}
} }
} }
@ -477,13 +485,14 @@ public class IabHelper {
* @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.
* @param data The data (Intent) as you received it. * @param data The data (Intent) as you received it.
* @return Returns true if the result was related to a purchase flow and was handled; * @return Returns true if the result was related to a purchase flow and was handled; false if the
* false if the result was not related to a purchase, in which case you should * result was not related to a purchase, in which case you should handle it normally.
* handle it normally.
*/ */
public boolean handleActivityResult(int requestCode, int resultCode, Intent data) { public boolean handleActivityResult(int requestCode, int resultCode, Intent data) {
IabResult result; IabResult result;
if (requestCode != mRequestCode) return false; if (requestCode != mRequestCode) {
return false;
}
checkNotDisposed(); checkNotDisposed();
checkSetupDone("handleActivityResult"); checkSetupDone("handleActivityResult");
@ -494,7 +503,9 @@ public class IabHelper {
if (data == null) { if (data == null) {
logError("Null data in IAB activity result."); logError("Null data in IAB activity result.");
result = new IabResult(IABHELPER_BAD_RESPONSE, "Null data in IAB result"); result = new IabResult(IABHELPER_BAD_RESPONSE, "Null data in IAB result");
if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null); if (mPurchaseListener != null) {
mPurchaseListener.onIabPurchaseFinished(result, null);
}
return true; return true;
} }
@ -512,8 +523,11 @@ 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, "IAB returned null purchaseData or dataSignature"); result = new IabResult(IABHELPER_UNKNOWN_ERROR,
if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null); "IAB returned null purchaseData or dataSignature");
if (mPurchaseListener != null) {
mPurchaseListener.onIabPurchaseFinished(result, null);
}
return true; return true;
} }
@ -525,61 +539,69 @@ 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, "Signature verification failed for sku " + sku); result = new IabResult(IABHELPER_VERIFICATION_FAILED,
if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, purchase); "Signature verification failed for sku " + sku);
if (mPurchaseListener != null) {
mPurchaseListener.onIabPurchaseFinished(result, purchase);
}
return true; return true;
} }
logDebug("Purchase signature successfully verified."); logDebug("Purchase signature successfully verified.");
} } catch (JSONException e) {
catch (JSONException e) {
logError("Failed to parse purchase data."); logError("Failed to parse purchase data.");
e.printStackTrace(); e.printStackTrace();
result = new IabResult(IABHELPER_BAD_RESPONSE, "Failed to parse purchase data."); result = new IabResult(IABHELPER_BAD_RESPONSE, "Failed to parse purchase data.");
if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null); if (mPurchaseListener != null) {
mPurchaseListener.onIabPurchaseFinished(result, null);
}
return true; return true;
} }
if (mPurchaseListener != null) { if (mPurchaseListener != null) {
mPurchaseListener.onIabPurchaseFinished(new IabResult(BILLING_RESPONSE_RESULT_OK, "Success"), purchase); mPurchaseListener
.onIabPurchaseFinished(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(responseCode)); logDebug("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);
} }
} } else if (resultCode == Activity.RESULT_CANCELED) {
else if (resultCode == Activity.RESULT_CANCELED) {
logDebug("Purchase canceled - Response: " + getResponseDesc(responseCode)); logDebug("Purchase canceled - Response: " + getResponseDesc(responseCode));
result = new IabResult(IABHELPER_USER_CANCELLED, "User canceled."); result = new IabResult(IABHELPER_USER_CANCELLED, "User canceled.");
if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null); if (mPurchaseListener != null) {
mPurchaseListener.onIabPurchaseFinished(result, null);
} }
else { } else {
logError("Purchase failed. Result code: " + Integer.toString(resultCode) logError("Purchase failed. Result code: " + Integer.toString(resultCode)
+ ". Response: " + getResponseDesc(responseCode)); + ". 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) mPurchaseListener.onIabPurchaseFinished(result, null); if (mPurchaseListener != null) {
mPurchaseListener.onIabPurchaseFinished(result, null);
}
} }
return true; return true;
} }
public Inventory queryInventory(boolean querySkuDetails, List<String> moreSkus) throws IabException { public Inventory queryInventory(boolean querySkuDetails, List<String> moreSkus)
throws IabException {
return queryInventory(querySkuDetails, moreSkus, null); return queryInventory(querySkuDetails, moreSkus, null);
} }
/** /**
* Queries the inventory. This will query all owned items from the server, as well as * Queries the inventory. This will query all owned items from the server, as well as information
* information on additional skus, if specified. This method may block or take long to execute. * on additional skus, if specified. This method may block or take long to execute. Do not call
* Do not call from a UI thread. For that, use the non-blocking version {@link #queryInventoryAsync}. * from a UI thread. For that, use the non-blocking version {@link #queryInventoryAsync}.
* *
* @param querySkuDetails if true, SKU details (price, description, etc) will be queried as well * @param querySkuDetails if true, SKU details (price, description, etc) will be queried as well
* as purchase information. * as purchase information.
* @param moreItemSkus additional PRODUCT skus to query information on, regardless of ownership. * @param moreItemSkus additional PRODUCT skus to query information on, regardless of ownership.
* Ignored if null or if querySkuDetails is false. * Ignored if null or if querySkuDetails is false.
* @param moreSubsSkus additional SUBSCRIPTIONS skus to query information on, regardless of ownership. * @param moreSubsSkus additional SUBSCRIPTIONS skus to query information on, regardless of
* 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(boolean querySkuDetails, List<String> moreItemSkus,
@ -610,35 +632,22 @@ 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, "Error refreshing inventory (querying prices of subscriptions)."); throw new IabException(r,
"Error refreshing inventory (querying prices of subscriptions).");
} }
} }
} }
return inv; return inv;
} catch (RemoteException e) {
throw new IabException(IABHELPER_REMOTE_EXCEPTION,
"Remote exception while refreshing inventory.", e);
} catch (JSONException e) {
throw new IabException(IABHELPER_BAD_RESPONSE,
"Error parsing JSON response while refreshing inventory.", e);
} }
catch (RemoteException e) {
throw new IabException(IABHELPER_REMOTE_EXCEPTION, "Remote exception while refreshing inventory.", e);
}
catch (JSONException e) {
throw new IabException(IABHELPER_BAD_RESPONSE, "Error parsing JSON response while refreshing inventory.", e);
}
}
/**
* Listener that notifies when an inventory query operation completes.
*/
public interface QueryInventoryFinishedListener {
/**
* Called to notify that an inventory query operation completed.
*
* @param result The result of the operation.
* @param inv The inventory.
*/
void onQueryInventoryFinished(IabResult result, Inventory inv);
} }
/** /**
* Asynchronous wrapper for inventory query. This will perform an inventory * Asynchronous wrapper for inventory query. This will perform an inventory
* query as described in {@link #queryInventory}, but will do so asynchronously * query as described in {@link #queryInventory}, but will do so asynchronously
@ -660,8 +669,7 @@ public class IabHelper {
Inventory inv = null; Inventory inv = null;
try { try {
inv = queryInventory(querySkuDetails, moreSkus); inv = queryInventory(querySkuDetails, moreSkus);
} } catch (IabException ex) {
catch (IabException ex) {
result = ex.getResult(); result = ex.getResult();
} }
@ -679,11 +687,11 @@ public class IabHelper {
queryInventoryAsync(true, null, listener); queryInventoryAsync(true, null, listener);
} }
public void queryInventoryAsync(boolean querySkuDetails, QueryInventoryFinishedListener listener) { public void queryInventoryAsync(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 result of consumption, the user will no longer own it. * that's owned, and as a result of consumption, the user will no longer own it.
@ -706,7 +714,7 @@ public class IabHelper {
String token = itemInfo.getToken(); String token = itemInfo.getToken();
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(IABHELPER_MISSING_TOKEN, "PurchaseInfo is missing token for sku: "
+ sku + " " + itemInfo); + sku + " " + itemInfo);
} }
@ -715,42 +723,14 @@ public class IabHelper {
int response = mService.consumePurchase(3, mContext.getPackageName(), token); int response = mService.consumePurchase(3, mContext.getPackageName(), token);
if (response == BILLING_RESPONSE_RESULT_OK) { if (response == BILLING_RESPONSE_RESULT_OK) {
logDebug("Successfully consumed sku: " + sku); logDebug("Successfully consumed sku: " + sku);
} } else {
else {
logDebug("Error consuming consuming sku " + sku + ". " + getResponseDesc(response)); logDebug("Error consuming consuming sku " + sku + ". " + getResponseDesc(response));
throw new IabException(response, "Error consuming sku " + sku); throw new IabException(response, "Error consuming sku " + sku);
} }
} catch (RemoteException e) {
throw new IabException(IABHELPER_REMOTE_EXCEPTION,
"Remote exception while consuming. PurchaseInfo: " + itemInfo, e);
} }
catch (RemoteException e) {
throw new IabException(IABHELPER_REMOTE_EXCEPTION, "Remote exception while consuming. PurchaseInfo: " + itemInfo, e);
}
}
/**
* Callback that notifies when a consumption operation finishes.
*/
public interface OnConsumeFinishedListener {
/**
* Called to notify that a consumption has finished.
*
* @param purchase The purchase that was (or was to be) consumed.
* @param result The result of the consumption operation.
*/
void onConsumeFinished(Purchase purchase, IabResult result);
}
/**
* Callback that notifies when a multi-item consumption operation finishes.
*/
public interface OnConsumeMultiFinishedListener {
/**
* Called to notify that a consumption of multiple items has finished.
*
* @param purchases The purchases that were (or were to be) consumed.
* @param results The results of each consumption operation, corresponding to each
* sku.
*/
void onConsumeMultiFinished(List<Purchase> purchases, List<IabResult> results);
} }
/** /**
@ -771,6 +751,7 @@ public class IabHelper {
/** /**
* Same as {@link #consumeAsync}, but for multiple items at once. * Same as {@link #consumeAsync}, but for multiple items at once.
*
* @param purchases The list of PurchaseInfo objects representing the purchases to consume. * @param purchases The list of PurchaseInfo objects representing the purchases to consume.
* @param listener The listener to notify when the consumption operation finishes. * @param listener The listener to notify when the consumption operation finishes.
*/ */
@ -780,46 +761,12 @@ public class IabHelper {
consumeAsyncInternal(purchases, null, listener); consumeAsyncInternal(purchases, null, listener);
} }
/**
* Returns a human-readable description for the given response code.
*
* @param code The response code
* @return A human-readable string explaining the result code.
* It also includes the result code numerically.
*/
public static String getResponseDesc(int code) {
String[] iab_msgs = ("0:OK/1:User Canceled/2:Unknown/" +
"3:Billing Unavailable/4:Item unavailable/" +
"5:Developer Error/6:Error/7:Item Already Owned/" +
"8:Item not owned").split("/");
String[] iabhelper_msgs = ("0:OK/-1001:Remote exception during initialization/" +
"-1002:Bad response received/" +
"-1003:Purchase signature verification failed/" +
"-1004:Send intent failed/" +
"-1005:User cancelled/" +
"-1006:Unknown purchase response/" +
"-1007:Missing token/" +
"-1008:Unknown error/" +
"-1009:Subscriptions not available/" +
"-1010:Invalid consumption attempt").split("/");
if (code <= IABHELPER_ERROR_BASE) {
int index = IABHELPER_ERROR_BASE - code;
if (index >= 0 && index < iabhelper_msgs.length) return iabhelper_msgs[index];
else return String.valueOf(code) + ":Unknown IAB Helper Error";
}
else if (code < 0 || code >= iab_msgs.length)
return String.valueOf(code) + ":Unknown";
else
return iab_msgs[code];
}
// Checks that setup was done; if not, throws an exception. // Checks that setup was done; if not, throws an exception.
void checkSetupDone(String operation) { void checkSetupDone(String operation) {
if (!mSetupDone) { if (!mSetupDone) {
logError("Illegal state for operation (" + operation + "): IAB helper is not set up."); logError("Illegal state for operation (" + operation + "): IAB helper is not set up.");
throw new IllegalStateException("IAB helper is not set up. Can't perform operation: " + operation); throw new IllegalStateException(
"IAB helper is not set up. Can't perform operation: " + operation);
} }
} }
@ -829,13 +776,15 @@ public class IabHelper {
if (o == null) { if (o == null) {
logDebug("Bundle with null response code, assuming OK (known issue)"); logDebug("Bundle with null response code, assuming OK (known issue)");
return BILLING_RESPONSE_RESULT_OK; return BILLING_RESPONSE_RESULT_OK;
} } else if (o instanceof Integer) {
else if (o instanceof Integer) return ((Integer)o).intValue(); return ((Integer) o).intValue();
else if (o instanceof Long) return (int)((Long)o).longValue(); } else if (o instanceof Long) {
else { return (int) ((Long) o).longValue();
} else {
logError("Unexpected type for bundle response code."); logError("Unexpected type for bundle response code.");
logError(o.getClass().getName()); logError(o.getClass().getName());
throw new RuntimeException("Unexpected type for bundle response code: " + o.getClass().getName()); throw new RuntimeException(
"Unexpected type for bundle response code: " + o.getClass().getName());
} }
} }
@ -845,19 +794,23 @@ public class IabHelper {
if (o == null) { if (o == null) {
logError("Intent with no response code, assuming OK (known issue)"); logError("Intent with no response code, assuming OK (known issue)");
return BILLING_RESPONSE_RESULT_OK; return BILLING_RESPONSE_RESULT_OK;
} } else if (o instanceof Integer) {
else if (o instanceof Integer) return ((Integer)o).intValue(); return ((Integer) o).intValue();
else if (o instanceof Long) return (int)((Long)o).longValue(); } else if (o instanceof Long) {
else { return (int) ((Long) o).longValue();
} else {
logError("Unexpected type for intent response code."); logError("Unexpected type for intent response code.");
logError(o.getClass().getName()); logError(o.getClass().getName());
throw new RuntimeException("Unexpected type for intent response code: " + o.getClass().getName()); throw new RuntimeException(
"Unexpected type for intent response code: " + o.getClass().getName());
} }
} }
void flagStartAsync(String operation) { void flagStartAsync(String operation) {
if (mAsyncInProgress) throw new IllegalStateException("Can't start async operation (" + if (mAsyncInProgress) {
throw new IllegalStateException("Can't start async operation (" +
operation + ") because another async operation(" + mAsyncOperation + ") is in progress."); operation + ") because another async operation(" + mAsyncOperation + ") is in progress.");
}
mAsyncOperation = operation; mAsyncOperation = operation;
mAsyncInProgress = true; mAsyncInProgress = true;
logDebug("Starting async operation: " + operation); logDebug("Starting async operation: " + operation);
@ -869,7 +822,6 @@ public class IabHelper {
mAsyncInProgress = false; mAsyncInProgress = false;
} }
int queryPurchases(Inventory inv, String itemType) throws JSONException, RemoteException { int queryPurchases(Inventory inv, String itemType) throws JSONException, RemoteException {
// Query purchases // Query purchases
logDebug("Querying owned items, item type: " + itemType); logDebug("Querying owned items, item type: " + itemType);
@ -917,8 +869,7 @@ public class IabHelper {
// Record ownership and token // Record ownership and token
inv.addPurchase(purchase); inv.addPurchase(purchase);
} } else {
else {
logWarn("Purchase signature verification **FAILED**. Not adding item."); logWarn("Purchase signature verification **FAILED**. Not adding item.");
logDebug(" Purchase data: " + purchaseData); logDebug(" Purchase data: " + purchaseData);
logDebug(" Signature: " + signature); logDebug(" Signature: " + signature);
@ -1011,9 +962,9 @@ public class IabHelper {
for (Purchase purchase : purchases) { for (Purchase purchase : purchases) {
try { try {
consume(purchase); consume(purchase);
results.add(new IabResult(BILLING_RESPONSE_RESULT_OK, "Successful consume of sku " + purchase.getSku())); results.add(new IabResult(BILLING_RESPONSE_RESULT_OK,
} "Successful consume of sku " + purchase.getSku()));
catch (IabException ex) { } catch (IabException ex) {
results.add(ex.getResult()); results.add(ex.getResult());
} }
} }
@ -1029,7 +980,9 @@ public class IabHelper {
} }
void logDebug(String msg) { void logDebug(String msg) {
if (mDebugLog) Log.d(mDebugTag, msg); if (mDebugLog) {
Log.d(mDebugTag, msg);
}
} }
void logError(String msg) { void logError(String msg) {
@ -1039,4 +992,77 @@ public class IabHelper {
void logWarn(String msg) { void logWarn(String msg) {
Log.w(mDebugTag, "In-app billing warning: " + msg); Log.w(mDebugTag, "In-app billing warning: " + msg);
} }
/**
* Callback for setup process. This listener's {@link #onIabSetupFinished} method is called
* when the setup process is complete.
*/
public interface OnIabSetupFinishedListener {
/**
* Called to notify that setup is complete.
*
* @param result The result of the setup process.
*/
void onIabSetupFinished(IabResult result);
}
/**
* Callback that notifies when a purchase is finished.
*/
public interface OnIabPurchaseFinishedListener {
/**
* Called to notify that an in-app purchase finished. If the purchase was successful,
* then the sku parameter specifies which item was purchased. If the purchase failed,
* the sku and extraData parameters may or may not be null, depending on how far the purchase
* process went.
*
* @param result The result of the purchase.
* @param info The purchase information (null if purchase failed)
*/
void onIabPurchaseFinished(IabResult result, Purchase info);
}
/**
* Listener that notifies when an inventory query operation completes.
*/
public interface QueryInventoryFinishedListener {
/**
* Called to notify that an inventory query operation completed.
*
* @param result The result of the operation.
* @param inv The inventory.
*/
void onQueryInventoryFinished(IabResult result, Inventory inv);
}
/**
* Callback that notifies when a consumption operation finishes.
*/
public interface OnConsumeFinishedListener {
/**
* Called to notify that a consumption has finished.
*
* @param purchase The purchase that was (or was to be) consumed.
* @param result The result of the consumption operation.
*/
void onConsumeFinished(Purchase purchase, IabResult result);
}
/**
* Callback that notifies when a multi-item consumption operation finishes.
*/
public interface OnConsumeMultiFinishedListener {
/**
* Called to notify that a consumption of multiple items has finished.
*
* @param purchases The purchases that were (or were to be) consumed.
* @param results The results of each consumption operation, corresponding to each sku.
*/
void onConsumeMultiFinished(List<Purchase> purchases, List<IabResult> results);
}
} }

@ -25,6 +25,7 @@ package com.android.vending.billing;
*/ */
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
public class IabResult { public class IabResult {
int mResponse; int mResponse;
String mMessage; String mMessage;
@ -32,15 +33,29 @@ public class IabResult {
mResponse = response; mResponse = response;
if (message == null || message.trim().length() == 0) { if (message == null || message.trim().length() == 0) {
mMessage = IabHelper.getResponseDesc(response); mMessage = IabHelper.getResponseDesc(response);
} } else {
else {
mMessage = message + " (response: " + IabHelper.getResponseDesc(response) + ")"; mMessage = message + " (response: " + IabHelper.getResponseDesc(response) + ")";
} }
} }
public int getResponse() { return mResponse; }
public String getMessage() { return mMessage; } public int getResponse() {
public boolean isSuccess() { return mResponse == IabHelper.BILLING_RESPONSE_RESULT_OK; } return mResponse;
public boolean isFailure() { return !isSuccess(); } }
public String toString() { return "IabResult: " + getMessage(); }
public String getMessage() {
return mMessage;
}
public boolean isSuccess() {
return mResponse == IabHelper.BILLING_RESPONSE_RESULT_OK;
}
public boolean isFailure() {
return !isSuccess();
}
public String toString() {
return "IabResult: " + getMessage();
}
} }

@ -26,27 +26,37 @@ import java.util.Map;
*/ */
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
public class Inventory { public class Inventory {
Map<String,SkuDetails> mSkuMap = new HashMap<String,SkuDetails>();
Map<String,Purchase> mPurchaseMap = new HashMap<String,Purchase>();
Inventory() { } Map<String, SkuDetails> mSkuMap = new HashMap<String, SkuDetails>();
Map<String, Purchase> mPurchaseMap = new HashMap<String, Purchase>();
/** Returns the listing details for an in-app product. */ Inventory() {
}
/**
* 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);
} }
@ -60,24 +70,34 @@ public class Inventory {
* a new Inventory. * a new Inventory.
*/ */
public void erasePurchase(String sku) { public void erasePurchase(String sku) {
if (mPurchaseMap.containsKey(sku)) mPurchaseMap.remove(sku); if (mPurchaseMap.containsKey(sku)) {
mPurchaseMap.remove(sku);
}
} }
/** 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()) {
if (p.getItemType().equals(itemType)) result.add(p.getSku()); if (p.getItemType().equals(itemType)) {
result.add(p.getSku());
}
} }
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());
} }

@ -23,6 +23,7 @@ import org.json.JSONObject;
*/ */
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
public class Purchase { public class Purchase {
String mItemType; // ITEM_TYPE_INAPP or ITEM_TYPE_SUBS String mItemType; // ITEM_TYPE_INAPP or ITEM_TYPE_SUBS
String mOrderId; String mOrderId;
String mPackageName; String mPackageName;
@ -50,18 +51,52 @@ public class Purchase {
mSignature = signature; mSignature = signature;
} }
public String getItemType() { return mItemType; } public String getItemType() {
public String getOrderId() { return mOrderId; } return mItemType;
public String getPackageName() { return mPackageName; } }
public String getSku() { return mSku; }
public long getPurchaseTime() { return mPurchaseTime; } public String getOrderId() {
public int getPurchaseState() { return mPurchaseState; } return mOrderId;
public String getDeveloperPayload() { return mDeveloperPayload; } }
public String getToken() { return mToken; }
public String getOriginalJson() { return mOriginalJson; } public String getPackageName() {
public String getSignature() { return mSignature; } return mPackageName;
public boolean isAutoRenewing() { return mIsAutoRenewing; } }
public String getSku() {
return mSku;
}
public long getPurchaseTime() {
return mPurchaseTime;
}
public int getPurchaseState() {
return mPurchaseState;
}
public String getDeveloperPayload() {
return mDeveloperPayload;
}
public String getToken() {
return mToken;
}
public String getOriginalJson() {
return mOriginalJson;
}
public String getSignature() {
return mSignature;
}
public boolean isAutoRenewing() {
return mIsAutoRenewing;
}
@Override @Override
public String toString() { return "PurchaseInfo(type:" + mItemType + "):" + mOriginalJson; } public String toString() {
return "PurchaseInfo(type:" + mItemType + "):" + mOriginalJson;
}
} }

@ -19,7 +19,6 @@ import android.annotation.SuppressLint;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Base64; import android.util.Base64;
import android.util.Log; import android.util.Log;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.KeyFactory; import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
@ -41,6 +40,7 @@ import java.security.spec.X509EncodedKeySpec;
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
@SuppressLint("all") @SuppressLint("all")
public class Security { public class Security {
private static final String TAG = "IABUtil/Security"; private static final String TAG = "IABUtil/Security";
private static final String KEY_FACTORY_ALGORITHM = "RSA"; private static final String KEY_FACTORY_ALGORITHM = "RSA";
@ -51,11 +51,13 @@ public class Security {
* the verified purchase. The data is in JSON format and signed * the verified purchase. The data is in JSON format and signed
* with a private key. The data also contains the {@link PurchaseState} * with a private key. The data also contains the {@link 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, String signature) { public static boolean verifyPurchase(String base64PublicKey, String signedData,
String signature) {
if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey) || if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey) ||
TextUtils.isEmpty(signature)) { TextUtils.isEmpty(signature)) {
Log.e(TAG, "Purchase verification failed: missing data."); Log.e(TAG, "Purchase verification failed: missing data.");

@ -23,6 +23,7 @@ import org.json.JSONObject;
*/ */
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
public class SkuDetails { public class SkuDetails {
private final String mItemType; private final String mItemType;
private final String mSku; private final String mSku;
private final String mType; private final String mType;
@ -50,13 +51,33 @@ public class SkuDetails {
mDescription = o.optString("description"); mDescription = o.optString("description");
} }
public String getSku() { return mSku; } public String getSku() {
public String getType() { return mType; } return mSku;
public String getPrice() { return mPrice; } }
public long getPriceAmountMicros() { return mPriceAmountMicros; }
public String getPriceCurrencyCode() { return mPriceCurrencyCode; } public String getType() {
public String getTitle() { return mTitle; } return mType;
public String getDescription() { return mDescription; } }
public String getPrice() {
return mPrice;
}
public long getPriceAmountMicros() {
return mPriceAmountMicros;
}
public String getPriceCurrencyCode() {
return mPriceCurrencyCode;
}
public String getTitle() {
return mTitle;
}
public String getDescription() {
return mDescription;
}
@Override @Override
public String toString() { public String toString() {

@ -1,15 +1,13 @@
package org.tasks; package org.tasks;
import com.todoroo.astrid.gtasks.GtasksPreferenceService; import com.todoroo.astrid.gtasks.GtasksPreferenceService;
import javax.inject.Inject;
import org.tasks.billing.InventoryHelper; import org.tasks.billing.InventoryHelper;
import org.tasks.caldav.CaldavAccountManager; import org.tasks.caldav.CaldavAccountManager;
import org.tasks.gtasks.GoogleAccountManager; import org.tasks.gtasks.GoogleAccountManager;
import org.tasks.gtasks.PlayServices; import org.tasks.gtasks.PlayServices;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
import javax.inject.Inject;
public class FlavorSetup { public class FlavorSetup {
private final GtasksPreferenceService gtasksPreferenceService; private final GtasksPreferenceService gtasksPreferenceService;
@ -20,7 +18,8 @@ public class FlavorSetup {
private final CaldavAccountManager caldavAccountManager; private final CaldavAccountManager caldavAccountManager;
@Inject @Inject
public FlavorSetup(GtasksPreferenceService gtasksPreferenceService, InventoryHelper inventoryHelper, public FlavorSetup(GtasksPreferenceService gtasksPreferenceService,
InventoryHelper inventoryHelper,
Preferences preferences, PlayServices playServices, Preferences preferences, PlayServices playServices,
GoogleAccountManager googleAccountManager, CaldavAccountManager caldavAccountManager) { GoogleAccountManager googleAccountManager, CaldavAccountManager caldavAccountManager) {
this.gtasksPreferenceService = gtasksPreferenceService; this.gtasksPreferenceService = gtasksPreferenceService;

@ -1,7 +1,6 @@
package org.tasks.analytics; package org.tasks.analytics;
import android.content.Context; import android.content.Context;
import com.android.vending.billing.IabResult; import com.android.vending.billing.IabResult;
import com.google.android.gms.analytics.ExceptionParser; import com.google.android.gms.analytics.ExceptionParser;
import com.google.android.gms.analytics.ExceptionReporter; import com.google.android.gms.analytics.ExceptionReporter;
@ -9,14 +8,11 @@ import com.google.android.gms.analytics.GoogleAnalytics;
import com.google.android.gms.analytics.HitBuilders; import com.google.android.gms.analytics.HitBuilders;
import com.google.android.gms.analytics.StandardExceptionParser; import com.google.android.gms.analytics.StandardExceptionParser;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import javax.inject.Inject;
import org.tasks.BuildConfig; import org.tasks.BuildConfig;
import org.tasks.R; import org.tasks.R;
import org.tasks.injection.ApplicationScope; import org.tasks.injection.ApplicationScope;
import org.tasks.injection.ForApplication; import org.tasks.injection.ForApplication;
import javax.inject.Inject;
import timber.log.Timber; import timber.log.Timber;
@ApplicationScope @ApplicationScope
@ -33,7 +29,8 @@ 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, null); final StandardExceptionParser standardExceptionParser = new StandardExceptionParser(context,
null);
exceptionParser = (thread, throwable) -> { exceptionParser = (thread, throwable) -> {
StringBuilder stack = new StringBuilder() StringBuilder stack = new StringBuilder()
.append(standardExceptionParser.getDescription(thread, throwable)) .append(standardExceptionParser.getDescription(thread, throwable))

@ -2,23 +2,18 @@ package org.tasks.billing;
import android.content.Context; import android.content.Context;
import android.content.IntentFilter; import android.content.IntentFilter;
import com.android.vending.billing.IabBroadcastReceiver; import com.android.vending.billing.IabBroadcastReceiver;
import com.android.vending.billing.IabHelper; import com.android.vending.billing.IabHelper;
import com.android.vending.billing.Inventory; import com.android.vending.billing.Inventory;
import com.android.vending.billing.Purchase; import com.android.vending.billing.Purchase;
import java.util.concurrent.Executor;
import javax.inject.Inject;
import javax.inject.Named;
import org.tasks.LocalBroadcastManager; import org.tasks.LocalBroadcastManager;
import org.tasks.R; import org.tasks.R;
import org.tasks.injection.ApplicationScope; import org.tasks.injection.ApplicationScope;
import org.tasks.injection.ForApplication; import org.tasks.injection.ForApplication;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
import java.util.concurrent.Executor;
import javax.inject.Inject;
import javax.inject.Named;
import timber.log.Timber; import timber.log.Timber;
@ApplicationScope @ApplicationScope
@ -41,7 +36,8 @@ public class InventoryHelper implements IabBroadcastReceiver.IabBroadcastListene
} }
public void initialize() { public void initialize() {
context.registerReceiver(new IabBroadcastReceiver(this), new IntentFilter(IabBroadcastReceiver.ACTION)); context.registerReceiver(new IabBroadcastReceiver(this),
new IntentFilter(IabBroadcastReceiver.ACTION));
refreshInventory(); refreshInventory();
} }

@ -4,12 +4,15 @@ import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.widget.Toast; import android.widget.Toast;
import com.android.vending.billing.IabHelper; import com.android.vending.billing.IabHelper;
import com.android.vending.billing.IabResult; import com.android.vending.billing.IabResult;
import com.android.vending.billing.Purchase; import com.android.vending.billing.Purchase;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import javax.inject.Inject;
import javax.inject.Named;
import org.tasks.BuildConfig; import org.tasks.BuildConfig;
import org.tasks.LocalBroadcastManager; import org.tasks.LocalBroadcastManager;
import org.tasks.R; import org.tasks.R;
@ -17,14 +20,6 @@ import org.tasks.analytics.Tracker;
import org.tasks.injection.ApplicationScope; import org.tasks.injection.ApplicationScope;
import org.tasks.injection.ForApplication; import org.tasks.injection.ForApplication;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import javax.inject.Inject;
import javax.inject.Named;
import timber.log.Timber; import timber.log.Timber;
@ApplicationScope @ApplicationScope
@ -59,7 +54,8 @@ public class PurchaseHelper implements IabHelper.OnIabSetupFinishedListener {
} }
} }
public boolean purchase(final Activity activity, final String sku, final String pref, final int requestCode, final PurchaseHelperCallback callback) { public boolean purchase(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;
} }
@ -79,12 +75,13 @@ 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), executor); final IabHelper iabHelper = 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);
if (iabResult.isSuccess()) { if (iabResult.isSuccess()) {
@ -113,7 +110,8 @@ public class PurchaseHelper implements IabHelper.OnIabSetupFinishedListener {
} }
} }
private void launchPurchaseFlow(final Activity activity, final String sku, final String pref, final int requestCode, final PurchaseHelperCallback callback) { private void launchPurchaseFlow(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);
@ -167,7 +165,8 @@ public class PurchaseHelper implements IabHelper.OnIabSetupFinishedListener {
} }
} }
public void handleActivityResult(PurchaseHelperCallback callback, int requestCode, int resultCode, Intent data) { public void handleActivityResult(PurchaseHelperCallback callback, int requestCode, int resultCode,
Intent data) {
this.activityResultCallback = callback; this.activityResultCallback = callback;
if (iabHelper != null) { if (iabHelper != null) {

@ -4,7 +4,6 @@ import android.accounts.Account;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.widget.Toast; import android.widget.Toast;
import com.google.android.gms.auth.GoogleAuthException; import com.google.android.gms.auth.GoogleAuthException;
import com.google.android.gms.auth.GoogleAuthUtil; import com.google.android.gms.auth.GoogleAuthUtil;
import com.google.android.gms.auth.UserRecoverableAuthException; import com.google.android.gms.auth.UserRecoverableAuthException;
@ -13,15 +12,11 @@ import com.google.android.gms.common.GoogleApiAvailability;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential; import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.google.api.services.tasks.TasksScopes; import com.google.api.services.tasks.TasksScopes;
import com.todoroo.astrid.gtasks.auth.GtasksLoginActivity; import com.todoroo.astrid.gtasks.auth.GtasksLoginActivity;
import java.io.IOException;
import javax.inject.Inject;
import org.tasks.R; import org.tasks.R;
import org.tasks.injection.ForApplication; import org.tasks.injection.ForApplication;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
import java.io.IOException;
import javax.inject.Inject;
import timber.log.Timber; import timber.log.Timber;
public class PlayServices { public class PlayServices {
@ -65,7 +60,8 @@ 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.LENGTH_LONG).show(); Toast.makeText(activity, R.string.common_google_play_services_notification_ticker,
Toast.LENGTH_LONG).show();
} }
} }
@ -77,12 +73,13 @@ public class PlayServices {
return preferences.getInt(R.string.play_services_available, -1); return preferences.getInt(R.string.play_services_available, -1);
} }
public boolean clearToken(GoogleAccountCredential credential){ public boolean clearToken(GoogleAccountCredential credential) {
try { try {
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.getToken(context, credential.getSelectedAccount(), "oauth2:" + TasksScopes.TASKS, null); GoogleAuthUtil
.getToken(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());
@ -93,19 +90,21 @@ public class PlayServices {
} }
} }
public void getAuthToken(final Activity activity, final String accountName, final GtasksLoginActivity.AuthResultHandler handler) { public void getAuthToken(final Activity activity, final String accountName,
final GtasksLoginActivity.AuthResultHandler handler) {
final Account account = accountManager.getAccount(accountName); final Account account = accountManager.getAccount(accountName);
if (account == null) { if (account == null) {
handler.authenticationFailed(activity.getString(R.string.gtasks_error_accountNotFound, accountName)); handler.authenticationFailed(
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));
} }

@ -1,34 +1,29 @@
package org.tasks.location; package org.tasks.location;
import static com.google.android.gms.location.Geofence.NEVER_EXPIRE;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Lists.newArrayList;
import static java.util.Collections.singletonList;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import com.google.android.gms.common.api.PendingResult; import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.Status; import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.GeofencingRequest; import com.google.android.gms.location.GeofencingRequest;
import com.google.android.gms.location.LocationServices; import com.google.android.gms.location.LocationServices;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import org.tasks.R; import org.tasks.R;
import org.tasks.data.Location; import org.tasks.data.Location;
import org.tasks.injection.ForApplication; import org.tasks.injection.ForApplication;
import org.tasks.preferences.PermissionChecker; import org.tasks.preferences.PermissionChecker;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import timber.log.Timber; import timber.log.Timber;
import static com.google.android.gms.location.Geofence.NEVER_EXPIRE;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Lists.newArrayList;
import static java.util.Collections.singletonList;
public class GeofenceApi { public class GeofenceApi {
private final Context context; private final Context context;
@ -36,7 +31,8 @@ public class GeofenceApi {
private final PermissionChecker permissionChecker; private final PermissionChecker permissionChecker;
@Inject @Inject
public GeofenceApi(@ForApplication Context context, Preferences preferences, PermissionChecker permissionChecker) { public GeofenceApi(@ForApplication Context context, Preferences preferences,
PermissionChecker permissionChecker) {
this.context = context; this.context = context;
this.preferences = preferences; this.preferences = preferences;
this.permissionChecker = permissionChecker; this.permissionChecker = permissionChecker;
@ -53,7 +49,9 @@ public class GeofenceApi {
PendingResult<Status> result = LocationServices.GeofencingApi.addGeofences( PendingResult<Status> result = LocationServices.GeofencingApi.addGeofences(
client, client,
getRequests(locations), getRequests(locations),
PendingIntent.getBroadcast(context, 0, new Intent(context, GeofenceTransitionsIntentService.Broadcast.class), PendingIntent.FLAG_UPDATE_CURRENT)); PendingIntent.getBroadcast(context, 0,
new Intent(context, GeofenceTransitionsIntentService.Broadcast.class),
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);
@ -99,7 +97,8 @@ 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.toMillis(preferences.getIntegerFromString(R.string.p_geofence_responsiveness, 60)); int responsiveness = (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)

@ -4,32 +4,20 @@ import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.support.v4.app.JobIntentService; import android.support.v4.app.JobIntentService;
import com.google.android.gms.location.GeofencingEvent; import com.google.android.gms.location.GeofencingEvent;
import com.todoroo.astrid.reminders.ReminderService; import com.todoroo.astrid.reminders.ReminderService;
import java.util.List;
import javax.inject.Inject;
import org.tasks.Notifier; import org.tasks.Notifier;
import org.tasks.data.Location; import org.tasks.data.Location;
import org.tasks.data.LocationDao; import org.tasks.data.LocationDao;
import org.tasks.injection.InjectingJobIntentService; import org.tasks.injection.InjectingJobIntentService;
import org.tasks.injection.IntentServiceComponent; import org.tasks.injection.IntentServiceComponent;
import org.tasks.jobs.JobManager; import org.tasks.jobs.JobManager;
import java.util.List;
import javax.inject.Inject;
import timber.log.Timber; import timber.log.Timber;
public class GeofenceTransitionsIntentService extends InjectingJobIntentService { public class GeofenceTransitionsIntentService extends InjectingJobIntentService {
public static class Broadcast extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
JobIntentService.enqueueWork(context, GeofenceTransitionsIntentService.class, JobManager.JOB_ID_GEOFENCE_TRANSITION, intent);
}
}
@Inject LocationDao locationDao; @Inject LocationDao locationDao;
@Inject Notifier notifier; @Inject Notifier notifier;
@ -45,7 +33,8 @@ public class GeofenceTransitionsIntentService extends InjectingJobIntentService
int transitionType = geofencingEvent.getGeofenceTransition(); int transitionType = geofencingEvent.getGeofenceTransition();
List<com.google.android.gms.location.Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences(); List<com.google.android.gms.location.Geofence> triggeringGeofences = 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) {
@ -66,8 +55,17 @@ public class GeofenceTransitionsIntentService extends InjectingJobIntentService
try { try {
Location location = locationDao.getGeofence(Long.parseLong(requestId)); Location location = locationDao.getGeofence(Long.parseLong(requestId));
notifier.triggerTaskNotification(location.getTask(), ReminderService.TYPE_ALARM); notifier.triggerTaskNotification(location.getTask(), ReminderService.TYPE_ALARM);
} catch(Exception e) { } catch (Exception e) {
Timber.e(e, "Error triggering geofence %s: %s", requestId, e.getMessage()); Timber.e(e, "Error triggering geofence %s: %s", requestId, e.getMessage());
} }
} }
public static class Broadcast extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
JobIntentService.enqueueWork(context, GeofenceTransitionsIntentService.class,
JobManager.JOB_ID_GEOFENCE_TRANSITION, intent);
}
}
} }

@ -2,15 +2,11 @@ package org.tasks.location;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationServices; import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.places.Places; import com.google.android.gms.location.places.Places;
import org.tasks.injection.ForApplication;
import javax.inject.Inject; import javax.inject.Inject;
import org.tasks.injection.ForApplication;
import timber.log.Timber; import timber.log.Timber;
public class GoogleApi implements GoogleApiClient.ConnectionCallbacks { public class GoogleApi implements GoogleApiClient.ConnectionCallbacks {
@ -19,10 +15,6 @@ public class GoogleApi implements GoogleApiClient.ConnectionCallbacks {
private GoogleApiClient googleApiClient; private GoogleApiClient googleApiClient;
private GoogleApiClientConnectionHandler googleApiClientConnectionHandler; private GoogleApiClientConnectionHandler googleApiClientConnectionHandler;
public interface GoogleApiClientConnectionHandler {
void onConnect(GoogleApiClient client);
}
@Inject @Inject
public GoogleApi(@ForApplication Context context) { public GoogleApi(@ForApplication Context context) {
builder = new GoogleApiClient.Builder(context) builder = new GoogleApiClient.Builder(context)
@ -32,10 +24,12 @@ public class GoogleApi implements GoogleApiClient.ConnectionCallbacks {
} }
public void connect(final GoogleApiClientConnectionHandler googleApiClientConnectionHandler) { public void connect(final GoogleApiClientConnectionHandler googleApiClientConnectionHandler) {
connect(googleApiClientConnectionHandler, connectionResult -> Timber.e("onConnectionFailed(%s)", connectionResult)); connect(googleApiClientConnectionHandler,
connectionResult -> Timber.e("onConnectionFailed(%s)", connectionResult));
} }
private void connect(final GoogleApiClientConnectionHandler googleApiClientConnectionHandler, GoogleApiClient.OnConnectionFailedListener onConnectionFailedListener) { private void connect(final GoogleApiClientConnectionHandler googleApiClientConnectionHandler,
GoogleApiClient.OnConnectionFailedListener onConnectionFailedListener) {
this.googleApiClientConnectionHandler = googleApiClientConnectionHandler; this.googleApiClientConnectionHandler = googleApiClientConnectionHandler;
googleApiClient = builder googleApiClient = builder
.addOnConnectionFailedListener(onConnectionFailedListener) .addOnConnectionFailedListener(onConnectionFailedListener)
@ -53,4 +47,9 @@ public class GoogleApi implements GoogleApiClient.ConnectionCallbacks {
public void onConnectionSuspended(int i) { public void onConnectionSuspended(int i) {
Timber.i("onConnectionSuspended(%s)", i); Timber.i("onConnectionSuspended(%s)", i);
} }
public interface GoogleApiClientConnectionHandler {
void onConnect(GoogleApiClient client);
}
} }

@ -4,19 +4,17 @@ import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.widget.Toast; import android.widget.Toast;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException; import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import com.google.android.gms.common.GooglePlayServicesRepairableException; import com.google.android.gms.common.GooglePlayServicesRepairableException;
import com.google.android.gms.location.places.Place; import com.google.android.gms.location.places.Place;
import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.LatLng;
import org.tasks.R; import org.tasks.R;
import org.tasks.data.Location; import org.tasks.data.Location;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
import timber.log.Timber; import timber.log.Timber;
public class PlacePicker { public class PlacePicker {
public static Intent getIntent(Activity activity) { public static Intent getIntent(Activity activity) {
com.google.android.gms.location.places.ui.PlacePicker.IntentBuilder builder = com.google.android.gms.location.places.ui.PlacePicker.IntentBuilder builder =
new com.google.android.gms.location.places.ui.PlacePicker.IntentBuilder(); new com.google.android.gms.location.places.ui.PlacePicker.IntentBuilder();
@ -27,7 +25,8 @@ 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.LENGTH_LONG).show(); Toast.makeText(activity, R.string.common_google_play_services_notification_ticker,
Toast.LENGTH_LONG).show();
} }
return null; return null;
} }

@ -3,6 +3,7 @@
* *
* See the file "LICENSE" for the full license governing this code. * 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;
@ -15,7 +16,6 @@ import com.mdimension.jchronic.tags.Separator;
import com.mdimension.jchronic.tags.TimeZone; import com.mdimension.jchronic.tags.TimeZone;
import com.mdimension.jchronic.utils.Span; import com.mdimension.jchronic.utils.Span;
import com.mdimension.jchronic.utils.Token; import com.mdimension.jchronic.utils.Token;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -135,7 +135,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.replaceAll("\\b(?:in the|during the|at) (afternoon|evening|night)\\b", "$1"); normalizedText = 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");
@ -174,8 +175,7 @@ public class AstridChronic {
long guessValue; long guessValue;
if (span.getWidth() > 1) { if (span.getWidth() > 1) {
guessValue = span.getBegin() + (span.getWidth() / 2); guessValue = span.getBegin() + (span.getWidth() / 2);
} } else {
else {
guessValue = span.getBegin(); guessValue = span.getBegin();
} }
return new Span(guessValue, guessValue); return new Span(guessValue, guessValue);

@ -3,10 +3,10 @@
* *
* See the file "LICENSE" for the full license governing this code. * 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;
import com.todoroo.andlib.sql.Field; import com.todoroo.andlib.sql.Field;
/** /**
@ -16,19 +16,21 @@ import com.todoroo.andlib.sql.Field;
* value is null, it may be of an incorrect type, in which case an exception is * value is null, it may be of an incorrect type, in which case an exception is
* thrown, or the correct type, in which case the value is returned. * thrown, or the correct type, in which case the value is returned.
* *
* @param <TYPE> a database supported type, such as String or Integer
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
*
* @param <TYPE>
* a database supported type, such as String or Integer
*/ */
public abstract class Property<TYPE> extends Field implements Cloneable { public abstract class Property<TYPE> extends Field implements Cloneable {
// --- implementation // --- implementation
/** The database table name this property */ /**
* The database table name this property
*/
public final Table table; public final Table table;
/** The database column name for this property */ /**
* The database column name for this property
*/
public final String name; public final String name;
/** /**
@ -71,8 +73,9 @@ public abstract class Property<TYPE> extends Field implements Cloneable {
} }
try { try {
Property<TYPE> newInstance = this.getClass().getConstructor(Table.class, String.class).newInstance(aliasedTable, this.name); Property<TYPE> newInstance = this.getClass().getConstructor(Table.class, String.class)
if(!TextUtils.isEmpty(columnAlias)) { .newInstance(aliasedTable, this.name);
if (!TextUtils.isEmpty(columnAlias)) {
return (Property<TYPE>) newInstance.as(columnAlias); return (Property<TYPE>) newInstance.as(columnAlias);
} }
return newInstance; return newInstance;
@ -83,11 +86,17 @@ public abstract class Property<TYPE> extends Field implements Cloneable {
// --- children // --- children
public String getColumnName() {
if (hasAlias()) {
return alias;
}
return name;
}
/** /**
* Integer property type. See {@link Property} * Integer property type. See {@link Property}
* *
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
*
*/ */
public static class IntegerProperty extends Property<Integer> { public static class IntegerProperty extends Property<Integer> {
@ -104,7 +113,6 @@ public abstract class Property<TYPE> extends Field implements Cloneable {
* String property type. See {@link Property} * String property type. See {@link Property}
* *
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
*
*/ */
public static class StringProperty extends Property<String> { public static class StringProperty extends Property<String> {
@ -122,7 +130,6 @@ public abstract class Property<TYPE> extends Field implements Cloneable {
* Long property type. See {@link Property} * Long property type. See {@link Property}
* *
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
*
*/ */
public static class LongProperty extends Property<Long> { public static class LongProperty extends Property<Long> {
@ -136,17 +143,13 @@ public abstract class Property<TYPE> extends Field implements Cloneable {
} }
} }
public String getColumnName() {
if (hasAlias()) {
return alias;
}
return name;
}
// --- 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() {
super("count", "COUNT(1)"); super("count", "COUNT(1)");
alias = "count"; alias = "count";

@ -3,6 +3,7 @@
* *
* See the file "LICENSE" for the full license governing this code. * 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;
@ -12,9 +13,9 @@ import com.todoroo.andlib.sql.SqlTable;
* clone the table when it returns. * clone the table when it returns.
* *
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
*
*/ */
public final class Table extends SqlTable { public final class Table extends SqlTable {
public final String name; public final String name;
public Table(String name) { public Table(String name) {
@ -37,14 +38,14 @@ 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;
} }
public String name() { public String name() {
if(hasAlias()) { if (hasAlias()) {
return alias; return alias;
} }
return name; return name;

@ -3,6 +3,7 @@
* *
* See the file "LICENSE" for the full license governing this code. * 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;
@ -13,11 +14,6 @@ import static com.todoroo.andlib.sql.SqlConstants.RIGHT_PARENTHESIS;
import static com.todoroo.andlib.sql.SqlConstants.SPACE; import static com.todoroo.andlib.sql.SqlConstants.SPACE;
public abstract class Criterion { public abstract class Criterion {
final Operator operator;
public Criterion(Operator operator) {
this.operator = operator;
}
public static final Criterion all = new Criterion(Operator.exists) { public static final Criterion all = new Criterion(Operator.exists) {
@Override @Override
@ -25,6 +21,11 @@ public abstract class Criterion {
sb.append(1); sb.append(1);
} }
}; };
final Operator operator;
public Criterion(Operator operator) {
this.operator = operator;
}
public static Criterion and(final Criterion criterion, final Criterion... criterions) { public static Criterion and(final Criterion criterion, final Criterion... criterions) {
return new Criterion(Operator.and) { return new Criterion(Operator.and) {

@ -3,16 +3,18 @@
* *
* See the file "LICENSE" for the full license governing this code. * 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;
import static com.todoroo.andlib.sql.SqlConstants.SPACE; import static com.todoroo.andlib.sql.SqlConstants.SPACE;
public abstract class DBObject<T extends DBObject<?>> implements Cloneable { public abstract class DBObject<T extends DBObject<?>> implements Cloneable {
protected String alias;
protected final String expression; protected final String expression;
protected String alias;
DBObject(String expression){ DBObject(String expression) {
this.expression = expression; this.expression = expression;
} }
@ -44,7 +46,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) : dbObject.expression != null) { if (expression != null ? !expression.equals(dbObject.expression)
: dbObject.expression != null) {
return false; return false;
} }
@ -72,7 +75,7 @@ public abstract class DBObject<T extends DBObject<?>> implements Cloneable {
sb.append(SPACE).append(AS).append(SPACE).append(alias); sb.append(SPACE).append(AS).append(SPACE).append(alias);
} else { } else {
int pos = expression.indexOf('.'); int pos = expression.indexOf('.');
if(pos > 0) { if (pos > 0) {
sb.append(SPACE).append(AS).append(SPACE).append(expression.substring(pos + 1)); sb.append(SPACE).append(AS).append(SPACE).append(expression.substring(pos + 1));
} }
} }

@ -3,6 +3,7 @@
* *
* See the file "LICENSE" for the full license governing this code. * 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;
@ -21,14 +22,14 @@ public class Field extends DBObject<Field> {
} }
public Criterion eq(Object value) { public Criterion eq(Object value) {
if(value == null) { if (value == null) {
return UnaryCriterion.isNull(this); return UnaryCriterion.isNull(this);
} }
return UnaryCriterion.eq(this, value); return UnaryCriterion.eq(this, value);
} }
public Criterion neq(Object value) { public Criterion neq(Object value) {
if(value == null) { if (value == null) {
return UnaryCriterion.isNotNull(this); return UnaryCriterion.isNotNull(this);
} }
return UnaryCriterion.neq(this, value); return UnaryCriterion.neq(this, value);
@ -56,7 +57,8 @@ 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).append(SPACE); sb.append(field).append(SPACE).append(Operator.in).append(SPACE).append(LEFT_PARENTHESIS)
.append(SPACE);
for (T t : value) { for (T t : value) {
sb.append(t.toString()).append(COMMA); sb.append(t.toString()).append(COMMA);
} }
@ -71,7 +73,8 @@ 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).append(query) sb.append(field).append(SPACE).append(Operator.in).append(SPACE).append(LEFT_PARENTHESIS)
.append(query)
.append(RIGHT_PARENTHESIS); .append(RIGHT_PARENTHESIS);
} }
}; };

@ -3,6 +3,7 @@
* *
* See the file "LICENSE" for the full license governing this code. * 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 {

@ -3,6 +3,7 @@
* *
* See the file "LICENSE" for the full license governing this code. * 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;
@ -11,6 +12,7 @@ import static com.todoroo.andlib.sql.SqlConstants.ON;
import static com.todoroo.andlib.sql.SqlConstants.SPACE; import static com.todoroo.andlib.sql.SqlConstants.SPACE;
public class Join { public class Join {
private final SqlTable joinTable; private final SqlTable joinTable;
private final JoinType joinType; private final JoinType joinType;
private final Criterion[] criterions; private final Criterion[] criterions;
@ -32,7 +34,8 @@ 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).append(ON).append(SPACE).append("("); sb.append(joinType).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) {

@ -3,6 +3,7 @@
* *
* See the file "LICENSE" for the full license governing this code. * 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 {

@ -3,24 +3,25 @@
* *
* See the file "LICENSE" for the full license governing this code. * 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 {
private final String operator;
public static final Operator eq = new Operator("="); public static final Operator eq = new Operator("=");
static final Operator neq = new Operator("<>");
public static final Operator isNull = new Operator("IS NULL"); public static final Operator isNull = new Operator("IS NULL");
static final Operator isNotNull = new Operator("IS NOT NULL");
static final Operator gt = new Operator(">");
static final Operator lt = new Operator("<");
static final Operator lte = new Operator("<=");
public static final Operator and = new Operator("AND"); public static final Operator and = new Operator("AND");
public static final Operator or = new Operator("OR"); public static final Operator or = new Operator("OR");
public static final Operator not = new Operator("NOT"); public static final Operator not = new Operator("NOT");
public static final Operator exists = new Operator("EXISTS"); public static final Operator exists = new Operator("EXISTS");
public static final Operator like = new Operator("LIKE"); public static final Operator like = new Operator("LIKE");
public static final Operator in = new Operator("IN"); public static final Operator in = new Operator("IN");
static final Operator neq = new Operator("<>");
static final Operator isNotNull = new Operator("IS NOT NULL");
static final Operator gt = new Operator(">");
static final Operator lt = new Operator("<");
static final Operator lte = new Operator("<=");
private final String operator;
private Operator(String operator) { private Operator(String operator) {
this.operator = operator; this.operator = operator;

@ -3,14 +3,16 @@
* *
* See the file "LICENSE" for the full license governing this code. * 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 java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
public class Order { public class Order {
private final Object expression; private final Object expression;
private final List<Order> secondaryExpressions; private final List<Order> secondaryExpressions;
private final OrderType orderType; private final OrderType orderType;
@ -52,7 +54,7 @@ public class Order {
} }
public Order reverse() { public Order reverse() {
if(orderType == OrderType.ASC) { if (orderType == OrderType.ASC) {
return new Order(expression, OrderType.DESC); return new Order(expression, OrderType.DESC);
} else { } else {
return new Order(expression, OrderType.ASC); return new Order(expression, OrderType.ASC);

@ -3,6 +3,7 @@
* *
* See the file "LICENSE" for the full license governing this code. * 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 {

@ -3,11 +3,8 @@
* *
* See the file "LICENSE" for the full license governing this code. * See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.sql;
import com.todoroo.astrid.data.Task;
import java.util.ArrayList; package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.ALL; import static com.todoroo.andlib.sql.SqlConstants.ALL;
import static com.todoroo.andlib.sql.SqlConstants.COMMA; import static com.todoroo.andlib.sql.SqlConstants.COMMA;
@ -19,14 +16,17 @@ import static com.todoroo.andlib.sql.SqlConstants.SPACE;
import static com.todoroo.andlib.sql.SqlConstants.WHERE; import static com.todoroo.andlib.sql.SqlConstants.WHERE;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
import com.todoroo.astrid.data.Task;
import java.util.ArrayList;
public final class Query { public final class Query {
private SqlTable table;
private String queryTemplate = null;
private final ArrayList<Criterion> criterions = new ArrayList<>(); private final ArrayList<Criterion> criterions = new ArrayList<>();
private final ArrayList<Field> fields = new ArrayList<>(); private final ArrayList<Field> fields = new ArrayList<>();
private final ArrayList<Join> joins = new ArrayList<>(); private final ArrayList<Join> joins = new ArrayList<>();
private final ArrayList<Order> orders = new ArrayList<>(); private final ArrayList<Order> orders = new ArrayList<>();
private SqlTable table;
private String queryTemplate = null;
private int limits = -1; private int limits = -1;
private Query(Field... fields) { private Query(Field... fields) {
@ -68,7 +68,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().equals(o.toString()); return this == o || !(o == null || getClass() != o.getClass()) && this.toString()
.equals(o.toString());
} }
@Override @Override
@ -83,12 +84,12 @@ public final class Query {
visitFromClause(sql); visitFromClause(sql);
visitJoinClause(sql); visitJoinClause(sql);
if(queryTemplate == null) { if (queryTemplate == null) {
visitWhereClause(sql); visitWhereClause(sql);
visitOrderByClause(sql); visitOrderByClause(sql);
visitLimitClause(sql); visitLimitClause(sql);
} else { } else {
if(orders.size() > 0) { if (orders.size() > 0) {
throw new IllegalStateException("Can't have extras AND query template"); //$NON-NLS-1$ throw new IllegalStateException("Can't have extras AND query template"); //$NON-NLS-1$
} }
sql.append(queryTemplate); sql.append(queryTemplate);
@ -144,13 +145,14 @@ public final class Query {
} }
private void visitLimitClause(StringBuilder sql) { private void visitLimitClause(StringBuilder sql) {
if(limits > -1) { if (limits > -1) {
sql.append(LIMIT).append(SPACE).append(limits).append(SPACE); sql.append(LIMIT).append(SPACE).append(limits).append(SPACE);
} }
} }
/** /**
* Add the SQL query template (comes after the "from") * Add the SQL query template (comes after the "from")
*
* @return query * @return query
*/ */
public Query withQueryTemplate(String template) { public Query withQueryTemplate(String template) {

@ -3,9 +3,8 @@
* *
* See the file "LICENSE" for the full license governing this code. * See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.sql;
import java.util.ArrayList; package com.todoroo.andlib.sql;
import static com.todoroo.andlib.sql.SqlConstants.COMMA; import static com.todoroo.andlib.sql.SqlConstants.COMMA;
import static com.todoroo.andlib.sql.SqlConstants.LIMIT; import static com.todoroo.andlib.sql.SqlConstants.LIMIT;
@ -14,12 +13,13 @@ import static com.todoroo.andlib.sql.SqlConstants.SPACE;
import static com.todoroo.andlib.sql.SqlConstants.WHERE; import static com.todoroo.andlib.sql.SqlConstants.WHERE;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
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>
*
*/ */
public final class QueryTemplate { public final class QueryTemplate {
@ -49,7 +49,7 @@ public final class QueryTemplate {
visitJoinClause(sql); visitJoinClause(sql);
visitWhereClause(sql); visitWhereClause(sql);
visitOrderByClause(sql); visitOrderByClause(sql);
if(limit != null) { if (limit != null) {
sql.append(LIMIT).append(SPACE).append(limit); sql.append(LIMIT).append(SPACE).append(limit);
} }
return sql.toString(); return sql.toString();

@ -3,23 +3,25 @@
* *
* See the file "LICENSE" for the full license governing this code. * See the file "LICENSE" for the full license governing this code.
*/ */
package com.todoroo.andlib.sql; package com.todoroo.andlib.sql;
public final class SqlConstants { public final class SqlConstants {
public static final String SELECT = "SELECT"; public static final String SELECT = "SELECT";
public static final String SPACE = " "; public static final String SPACE = " ";
public static final String AS = "AS"; public static final String AS = "AS";
static final String COMMA = ",";
public static final String FROM = "FROM"; public static final String FROM = "FROM";
public static final String ON = "ON"; public static final String ON = "ON";
static final String JOIN = "JOIN";
public static final String ALL = "*"; public static final String ALL = "*";
static final String LEFT_PARENTHESIS = "(";
static final String RIGHT_PARENTHESIS = ")";
public static final String AND = "AND"; public static final String AND = "AND";
public static final String OR = "OR"; public static final String OR = "OR";
static final String ORDER_BY = "ORDER BY";
public static final String WHERE = "WHERE"; public static final String WHERE = "WHERE";
public static final String NOT = "NOT"; public static final String NOT = "NOT";
public static final String LIMIT = "LIMIT"; public static final String LIMIT = "LIMIT";
static final String COMMA = ",";
static final String JOIN = "JOIN";
static final String LEFT_PARENTHESIS = "(";
static final String RIGHT_PARENTHESIS = ")";
static final String ORDER_BY = "ORDER BY";
} }

@ -3,6 +3,7 @@
* *
* See the file "LICENSE" for the full license governing this code. * 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> {

@ -3,11 +3,13 @@
* *
* See the file "LICENSE" for the full license governing this code. * 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;
public class UnaryCriterion extends Criterion { public class UnaryCriterion extends Criterion {
private final Field expression; private final Field expression;
private final Object value; private final Object value;
@ -17,40 +19,10 @@ public class UnaryCriterion extends Criterion {
this.value = value; this.value = value;
} }
@Override
protected void populate(StringBuilder sb) {
beforePopulateOperator(sb);
populateOperator(sb);
afterPopulateOperator(sb);
}
public static Criterion eq(Field expression, Object value) { public static Criterion eq(Field expression, Object value) {
return new UnaryCriterion(expression, Operator.eq, value); return new UnaryCriterion(expression, Operator.eq, value);
} }
@SuppressWarnings("WeakerAccess")
void beforePopulateOperator(StringBuilder sb) {
sb.append(expression);
}
@SuppressWarnings("WeakerAccess")
void populateOperator(StringBuilder sb) {
sb.append(operator);
}
@SuppressWarnings("WeakerAccess")
void afterPopulateOperator(StringBuilder sb) {
if(value == null) {
return;
}
if(value instanceof String) {
sb.append("'").append(sanitize((String) value)).append("'");
} else {
sb.append(value);
}
}
/** /**
* Sanitize the given input for SQL * Sanitize the given input for SQL
*/ */
@ -100,4 +72,34 @@ public class UnaryCriterion extends Criterion {
} }
}; };
} }
@Override
protected void populate(StringBuilder sb) {
beforePopulateOperator(sb);
populateOperator(sb);
afterPopulateOperator(sb);
}
@SuppressWarnings("WeakerAccess")
void beforePopulateOperator(StringBuilder sb) {
sb.append(expression);
}
@SuppressWarnings("WeakerAccess")
void populateOperator(StringBuilder sb) {
sb.append(operator);
}
@SuppressWarnings("WeakerAccess")
void afterPopulateOperator(StringBuilder sb) {
if (value == null) {
return;
}
if (value instanceof String) {
sb.append("'").append(sanitize((String) value)).append("'");
} else {
sb.append(value);
}
}
} }

@ -3,6 +3,7 @@
* *
* See the file "LICENSE" for the full license governing this code. * 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;
@ -13,7 +14,6 @@ import android.util.DisplayMetrics;
import android.view.View; import android.view.View;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.widget.TextView; import android.widget.TextView;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
@ -23,14 +23,12 @@ import java.io.OutputStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import timber.log.Timber; import timber.log.Timber;
/** /**
* Android Utility Classes * Android Utility Classes
* *
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
*
*/ */
public class AndroidUtilities { public class AndroidUtilities {
@ -39,7 +37,9 @@ public class AndroidUtilities {
// --- 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);
@ -57,25 +57,28 @@ public class AndroidUtilities {
*/ */
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()) {
addSerialized(result, entry.getKey(), entry.getValue()); addSerialized(result, entry.getKey(), entry.getValue());
} }
return result.toString(); return result.toString();
} }
/** add serialized helper */ /**
* add serialized helper
*/
private static void addSerialized(StringBuilder result, private static void addSerialized(StringBuilder result,
String key, Object value) { String key, Object value) {
result.append(key.replace(SERIALIZATION_SEPARATOR, SEPARATOR_ESCAPE)).append( result.append(key.replace(SERIALIZATION_SEPARATOR, SEPARATOR_ESCAPE)).append(
SERIALIZATION_SEPARATOR); 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) {
result.append('d').append(value); result.append('d').append(value);
} 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').append(value.toString().replace(SERIALIZATION_SEPARATOR, SEPARATOR_ESCAPE)); result.append('s')
.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);
} else { } else {
@ -112,18 +115,14 @@ public class AndroidUtilities {
return result; return result;
} }
public interface SerializedPut<T> {
void put(T object, String key, char type, String value) throws NumberFormatException;
}
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);
String value = pairs[i+1].substring(1); String value = pairs[i + 1].substring(1);
try { try {
putter.put(object, key, pairs[i+1].charAt(0), value); putter.put(object, key, pairs[i + 1].charAt(0), value);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
// failed parse to number // failed parse to number
putter.put(object, key, 's', value); putter.put(object, key, 's', value);
@ -137,7 +136,6 @@ public class AndroidUtilities {
/** /**
* Copy a file from one place to another * Copy a file from one place to another
* @throws Exception
*/ */
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);
@ -152,7 +150,6 @@ public class AndroidUtilities {
/** /**
* Copy stream from source to destination * Copy stream from source to destination
* @throws IOException
*/ */
private static void copyStream(InputStream source, OutputStream dest) throws IOException { private static void copyStream(InputStream source, OutputStream dest) throws IOException {
int bytes; int bytes;
@ -243,7 +240,8 @@ public class AndroidUtilities {
try { try {
View currentFocus = activity.getCurrentFocus(); View currentFocus = activity.getCurrentFocus();
if (currentFocus != null) { if (currentFocus != null) {
InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); InputMethodManager inputMethodManager = (InputMethodManager) activity
.getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(currentFocus.getWindowToken(), 0); inputMethodManager.hideSoftInputFromWindow(currentFocus.getWindowToken(), 0);
} }
} catch (Exception e) { } catch (Exception e) {
@ -253,10 +251,12 @@ public class AndroidUtilities {
/** /**
* Dismiss the keyboard if it is displayed by any of the listed views * Dismiss the keyboard if it is displayed by any of the listed views
*
* @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.getSystemService(Context.INPUT_METHOD_SERVICE); InputMethodManager imm = (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);
} }
@ -276,4 +276,9 @@ public class AndroidUtilities {
} }
return extension; return extension;
} }
public interface SerializedPut<T> {
void put(T object, String key, char type, String value) throws NumberFormatException;
}
} }

@ -3,24 +3,46 @@
* *
* See the file "LICENSE" for the full license governing this code. * 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.time.DateTimeUtils.currentTimeMillis;
import android.content.Context; import android.content.Context;
import android.text.format.DateFormat; import android.text.format.DateFormat;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import org.tasks.R; import org.tasks.R;
import org.tasks.locale.Locale; import org.tasks.locale.Locale;
import org.tasks.time.DateTime; import org.tasks.time.DateTime;
import static org.tasks.date.DateTimeUtils.newDateTime;
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
public class DateUtilities { public class DateUtilities {
/**
* Represents a single hour
*/
public static final long ONE_HOUR = 3600000L;
/**
* Represents a single day
*/
public static final long ONE_DAY = 24 * ONE_HOUR;
/**
* Represents a single week
*/
public static final long ONE_WEEK = 7 * ONE_DAY;
/**
* Represents a single minute
*/
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_YEAR = "yy\u5E74 " + JA;
private static final String KO = "MMM d\uC77C";
private static final String KO_YEAR = "yy\uB144 " + KO;
private static final String ZH = "MMM d\u65E5";
private static final String ZH_YEAR = "yy\u5E74 " + ZH;
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/>
@ -35,49 +57,32 @@ public class DateUtilities {
DateTime result = dt.plusMonths(interval); DateTime result = dt.plusMonths(interval);
// preserving java.util.date behavior // preserving java.util.date behavior
int diff = dt.getDayOfMonth() - result.getDayOfMonth(); int diff = dt.getDayOfMonth() - result.getDayOfMonth();
if(diff > 0) { if (diff > 0) {
result = result.plusDays(diff); result = result.plusDays(diff);
} }
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();
} }
/** Returns unixtime one month from now */
public static long oneMonthFromNow() {
return addCalendarMonthsToUnixtime(currentTimeMillis(), 1);
}
/** Represents a single hour */
public static final long ONE_HOUR = 3600000L;
/** Represents a single day */
public static final long ONE_DAY = 24 * ONE_HOUR;
/** Represents a single week */
public static final long ONE_WEEK = 7 * ONE_DAY;
/** Represents a single minute */
public static final long ONE_MINUTE = 60000L;
private static final String JA = "MMM d\u65E5";
private static final String JA_YEAR = "yy\u5E74 " + JA;
private static final String KO = "MMM d\uC77C";
private static final String KO_YEAR = "yy\uB144 " + KO;
private static final String ZH = "MMM d\u65E5";
private static final String ZH_YEAR = "yy\u5E74 " + ZH;
/* ====================================================================== /* ======================================================================
* =========================================================== formatters * =========================================================== formatters
* ====================================================================== */ * ====================================================================== */
static Boolean is24HourOverride = null; /**
* Returns unixtime one month from now
*/
public static long oneMonthFromNow() {
return addCalendarMonthsToUnixtime(currentTimeMillis(), 1);
}
public static boolean is24HourFormat(Context context) { public static boolean is24HourFormat(Context context) {
if(is24HourOverride != null) { if (is24HourOverride != null) {
return is24HourOverride; return is24HourOverride;
} }
@ -92,7 +97,7 @@ public class DateUtilities {
String value; String value;
if (is24HourFormat(context)) { if (is24HourFormat(context)) {
value = "HH:mm"; value = "HH:mm";
} else if (date.getMinuteOfHour() == 0){ } else if (date.getMinuteOfHour() == 0) {
value = "h a"; value = "h a";
} else { } else {
value = "h:mm a"; value = "h:mm a";
@ -119,7 +124,7 @@ public class DateUtilities {
} }
private static String getFormat(Locale locale, String monthFormat, boolean includeYear) { private static String getFormat(Locale locale, String monthFormat, boolean includeYear) {
switch(locale.getLanguage()) { switch (locale.getLanguage()) {
case "ja": case "ja":
return includeYear ? JA_YEAR : JA; return includeYear ? JA_YEAR : JA;
case "ko": case "ko":
@ -183,20 +188,21 @@ public class DateUtilities {
long today = getStartOfDay(currentTimeMillis()); long today = getStartOfDay(currentTimeMillis());
long input = getStartOfDay(date); long input = getStartOfDay(date);
if(today == input) { if (today == input) {
return context.getString(R.string.today); return context.getString(R.string.today);
} }
if(today + ONE_DAY == input) { if (today + ONE_DAY == input) {
return context.getString(abbreviated ? R.string.tmrw : R.string.tomorrow); return context.getString(abbreviated ? R.string.tmrw : R.string.tomorrow);
} }
if(today == input + ONE_DAY) { if (today == input + ONE_DAY) {
return context.getString(abbreviated ? R.string.yest : R.string.yesterday); return context.getString(abbreviated ? R.string.yest : R.string.yesterday);
} }
if(today + abbreviationLimit >= input && today - abbreviationLimit <= input) { if (today + abbreviationLimit >= input && today - abbreviationLimit <= input) {
return abbreviated ? DateUtilities.getWeekdayShort(newDateTime(date)) : DateUtilities.getWeekday(newDateTime(date)); return abbreviated ? DateUtilities.getWeekdayShort(newDateTime(date))
: DateUtilities.getWeekday(newDateTime(date));
} }
return getDateString(newDateTime(date)); return getDateString(newDateTime(date));

@ -3,12 +3,12 @@
* *
* See the file "LICENSE" for the full license governing this code. * 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 {
@ -18,13 +18,13 @@ public class DialogUtilities {
*/ */
@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) {
Timber.e(e, e.getMessage()); Timber.e(e, e.getMessage());
} }
}); });

@ -3,8 +3,11 @@
* *
* See the file "LICENSE" for the full license governing this code. * 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 android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.content.ContextCompat; import android.support.v4.content.ContextCompat;
@ -12,9 +15,13 @@ import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.view.MenuItem; import android.view.MenuItem;
import butterknife.BindView;
import butterknife.ButterKnife;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.inject.Inject;
import org.tasks.R; import org.tasks.R;
import org.tasks.injection.ActivityComponent; import org.tasks.injection.ActivityComponent;
import org.tasks.injection.ThemedInjectingAppCompatActivity; import org.tasks.injection.ThemedInjectingAppCompatActivity;
@ -22,29 +29,55 @@ 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;
import java.util.ArrayList; public class BeastModePreferences extends ThemedInjectingAppCompatActivity implements
import java.util.Collections; Toolbar.OnMenuItemClickListener {
import java.util.List;
import javax.inject.Inject;
import butterknife.BindView;
import butterknife.ButterKnife;
import static java.util.Arrays.asList;
public class BeastModePreferences extends ThemedInjectingAppCompatActivity implements Toolbar.OnMenuItemClickListener {
private static final String BEAST_MODE_ORDER_PREF = "beast_mode_order_v3"; //$NON-NLS-1$
private static final String BEAST_MODE_PREF_ITEM_SEPARATOR = ";";
@BindView(R.id.toolbar) Toolbar toolbar; @BindView(R.id.toolbar) Toolbar toolbar;
@BindView(R.id.recycler_view) RecyclerView recyclerView; @BindView(R.id.recycler_view) RecyclerView recyclerView;
@Inject Preferences preferences;
private BeastModeRecyclerAdapter adapter;
private static final String BEAST_MODE_ORDER_PREF = "beast_mode_order_v3"; //$NON-NLS-1$ public static void setDefaultOrder(Preferences preferences, Context context) {
if (preferences.getStringValue(BEAST_MODE_ORDER_PREF) != null) {
return;
}
private static final String BEAST_MODE_PREF_ITEM_SEPARATOR = ";"; ArrayList<String> list = constructOrderedControlList(preferences, context);
StringBuilder newSetting = new StringBuilder();
for (String item : list) {
newSetting.append(item);
newSetting.append(BEAST_MODE_PREF_ITEM_SEPARATOR);
}
preferences.setString(BEAST_MODE_ORDER_PREF, newSetting.toString());
}
private BeastModeRecyclerAdapter adapter; public static ArrayList<String> constructOrderedControlList(Preferences preferences,
Context context) {
String order = preferences.getStringValue(BEAST_MODE_ORDER_PREF);
ArrayList<String> list = new ArrayList<>();
String[] itemsArray;
if (order == null) {
itemsArray = context.getResources().getStringArray(R.array.TEA_control_sets_prefs);
} else {
itemsArray = order.split(BEAST_MODE_PREF_ITEM_SEPARATOR);
}
@Inject Preferences preferences; Collections.addAll(list, itemsArray);
if (order == null) {
return list;
}
itemsArray = context.getResources().getStringArray(R.array.TEA_control_sets_prefs);
for (int i = 0; i < itemsArray.length; i++) {
if (!list.contains(itemsArray[i])) {
list.add(i, itemsArray[i]);
}
}
return list;
}
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -72,7 +105,7 @@ public class BeastModePreferences extends ThemedInjectingAppCompatActivity imple
@Override @Override
public boolean onMenuItemClick(MenuItem item) { public boolean onMenuItemClick(MenuItem item) {
switch(item.getItemId()) { switch (item.getItemId()) {
case R.id.menu_reset_to_defaults: case R.id.menu_reset_to_defaults:
String[] prefsArray = getResources().getStringArray(R.array.TEA_control_sets_prefs); String[] prefsArray = getResources().getStringArray(R.array.TEA_control_sets_prefs);
adapter.setItems(asList(prefsArray)); adapter.setItems(asList(prefsArray));
@ -98,43 +131,4 @@ public class BeastModePreferences extends ThemedInjectingAppCompatActivity imple
} }
super.finish(); super.finish();
} }
public static void setDefaultOrder(Preferences preferences, Context context) {
if (preferences.getStringValue(BEAST_MODE_ORDER_PREF) != null) {
return;
}
ArrayList<String> list = constructOrderedControlList(preferences, context);
StringBuilder newSetting = new StringBuilder();
for (String item : list) {
newSetting.append(item);
newSetting.append(BEAST_MODE_PREF_ITEM_SEPARATOR);
}
preferences.setString(BEAST_MODE_ORDER_PREF, newSetting.toString());
}
public static ArrayList<String> constructOrderedControlList(Preferences preferences, Context context) {
String order = preferences.getStringValue(BEAST_MODE_ORDER_PREF);
ArrayList<String> list = new ArrayList<>();
String[] itemsArray;
if (order == null) {
itemsArray = context.getResources().getStringArray(R.array.TEA_control_sets_prefs);
} else {
itemsArray = order.split(BEAST_MODE_PREF_ITEM_SEPARATOR);
}
Collections.addAll(list, itemsArray);
if (order == null) {
return list;
}
itemsArray = context.getResources().getStringArray(R.array.TEA_control_sets_prefs);
for (int i = 0; i < itemsArray.length; i++) {
if (!list.contains(itemsArray[i])) {
list.add(i, itemsArray[i]);
}
}
return list;
}
} }

@ -1,22 +1,20 @@
/** /**
* 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 android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.service.TaskCreator; import com.todoroo.astrid.service.TaskCreator;
import javax.inject.Inject;
import org.tasks.injection.ActivityComponent; import org.tasks.injection.ActivityComponent;
import org.tasks.injection.InjectingAppCompatActivity; import org.tasks.injection.InjectingAppCompatActivity;
import javax.inject.Inject;
import static org.tasks.intents.TaskIntents.getEditTaskStack;
/** /**
* @author joshuagross * @author joshuagross
* *

@ -3,8 +3,11 @@
* *
* See the file "LICENSE" for the full license governing this code. * 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 android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
@ -18,7 +21,8 @@ import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import butterknife.BindView;
import butterknife.ButterKnife;
import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.api.Filter; import com.todoroo.astrid.api.Filter;
@ -31,7 +35,8 @@ import com.todoroo.astrid.service.TaskDeleter;
import com.todoroo.astrid.timers.TimerPlugin; import com.todoroo.astrid.timers.TimerPlugin;
import com.todoroo.astrid.ui.EditTitleControlSet; import com.todoroo.astrid.ui.EditTitleControlSet;
import com.todoroo.astrid.utility.Flags; import com.todoroo.astrid.utility.Flags;
import java.util.List;
import javax.inject.Inject;
import org.tasks.LocalBroadcastManager; import org.tasks.LocalBroadcastManager;
import org.tasks.R; import org.tasks.R;
import org.tasks.analytics.Tracker; import org.tasks.analytics.Tracker;
@ -48,54 +53,38 @@ 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;
import java.util.List; public final class TaskEditFragment extends InjectingFragment implements
Toolbar.OnMenuItemClickListener {
import javax.inject.Inject;
import butterknife.BindView;
import butterknife.ButterKnife;
import static org.tasks.date.DateTimeUtils.newDateTime;
public final class TaskEditFragment extends InjectingFragment implements Toolbar.OnMenuItemClickListener {
public interface TaskEditFragmentCallbackHandler {
void taskEditFinished();
}
public static TaskEditFragment newTaskEditFragment(Task task) {
TaskEditFragment taskEditFragment = new TaskEditFragment();
Bundle arguments = new Bundle();
arguments.putParcelable(EXTRA_TASK, task);
taskEditFragment.setArguments(arguments);
return taskEditFragment;
}
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";
@Inject TaskDao taskDao; @Inject TaskDao taskDao;
@Inject UserActivityDao userActivityDao; @Inject UserActivityDao userActivityDao;
@Inject TaskDeleter taskDeleter; @Inject TaskDeleter taskDeleter;
@Inject NotificationManager notificationManager; @Inject NotificationManager notificationManager;
@Inject DialogBuilder dialogBuilder; @Inject DialogBuilder dialogBuilder;
@Inject @ForActivity Context context; @Inject @ForActivity
Context context;
@Inject TaskEditControlSetFragmentManager taskEditControlSetFragmentManager; @Inject TaskEditControlSetFragmentManager taskEditControlSetFragmentManager;
@Inject CommentsController commentsController; @Inject CommentsController commentsController;
@Inject Preferences preferences; @Inject Preferences preferences;
@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.toolbar) Toolbar toolbar;
@BindView(R.id.comments) LinearLayout comments; @BindView(R.id.comments) LinearLayout comments;
@BindView(R.id.control_sets) LinearLayout controlSets; @BindView(R.id.control_sets) LinearLayout controlSets;
Task model = null; Task model = null;
private TaskEditFragmentCallbackHandler callback; private TaskEditFragmentCallbackHandler callback;
public static TaskEditFragment newTaskEditFragment(Task task) {
TaskEditFragment taskEditFragment = new TaskEditFragment();
Bundle arguments = new Bundle();
arguments.putParcelable(EXTRA_TASK, task);
taskEditFragment.setArguments(arguments);
return taskEditFragment;
}
@Override @Override
public void onAttach(Activity activity) { public void onAttach(Activity activity) {
super.onAttach(activity); super.onAttach(activity);
@ -109,7 +98,8 @@ public final class TaskEditFragment extends InjectingFragment implements Toolbar
} }
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(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);
@ -138,18 +128,20 @@ public final class TaskEditFragment extends InjectingFragment implements Toolbar
commentsController.reloadView(); commentsController.reloadView();
FragmentManager fragmentManager = getChildFragmentManager(); FragmentManager fragmentManager = getChildFragmentManager();
List<TaskEditControlFragment> taskEditControlFragments = taskEditControlSetFragmentManager.getOrCreateFragments(fragmentManager, model); List<TaskEditControlFragment> taskEditControlFragments = 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.replace(TaskEditControlSetFragmentManager.TASK_EDIT_CONTROL_FRAGMENT_ROWS[i], taskEditControlFragment, tag); fragmentTransaction
.replace(TaskEditControlSetFragmentManager.TASK_EDIT_CONTROL_FRAGMENT_ROWS[i],
taskEditControlFragment, tag);
} }
fragmentTransaction.commit(); fragmentTransaction.commit();
for (int i = taskEditControlFragments.size() - 2; i > 1; i--) {
for (int i = taskEditControlFragments.size() - 2; i > 1 ; i--) {
controlSets.addView(inflater.inflate(R.layout.task_edit_row_divider, controlSets, false), i); controlSets.addView(inflater.inflate(R.layout.task_edit_row_divider, controlSets, false), i);
} }
@ -189,15 +181,12 @@ public final class TaskEditFragment extends InjectingFragment implements Toolbar
return model; return model;
} }
/* /**
* ====================================================================== * Save task model from values in UI components
* =============================================== model reading / saving
* ======================================================================
*/ */
/** Save task model from values in UI components */
public void save() { public void save() {
List<TaskEditControlFragment> fragments = taskEditControlSetFragmentManager.getFragmentsInPersistOrder(getChildFragmentManager()); List<TaskEditControlFragment> fragments = taskEditControlSetFragmentManager
.getFragmentsInPersistOrder(getChildFragmentManager());
if (hasChanges(fragments)) { if (hasChanges(fragments)) {
boolean isNewTask = model.isNew(); boolean isNewTask = model.isNew();
if (isNewTask) { if (isNewTask) {
@ -223,6 +212,12 @@ public final class TaskEditFragment extends InjectingFragment implements Toolbar
} }
} }
/*
* ======================================================================
* =============================================== model reading / saving
* ======================================================================
*/
private EditTitleControlSet getEditTitleControlSet() { private EditTitleControlSet getEditTitleControlSet() {
return getFragment(EditTitleControlSet.TAG); return getFragment(EditTitleControlSet.TAG);
} }
@ -244,12 +239,6 @@ public final class TaskEditFragment extends InjectingFragment implements Toolbar
return (T) getChildFragmentManager().findFragmentByTag(getString(tag)); return (T) getChildFragmentManager().findFragmentByTag(getString(tag));
} }
/*
* ======================================================================
* ======================================================= event handlers
* ======================================================================
*/
private boolean hasChanges(List<TaskEditControlFragment> fragments) { private boolean hasChanges(List<TaskEditControlFragment> fragments) {
try { try {
for (TaskEditControlFragment fragment : fragments) { for (TaskEditControlFragment fragment : fragments) {
@ -257,14 +246,21 @@ public final class TaskEditFragment extends InjectingFragment implements Toolbar
return true; return true;
} }
} }
} catch(Exception e) { } catch (Exception e) {
tracker.reportException(e); tracker.reportException(e);
} }
return false; return false;
} }
/*
* ======================================================================
* ======================================================= event handlers
* ======================================================================
*/
public void discardButtonClick() { public void discardButtonClick() {
if (hasChanges(taskEditControlSetFragmentManager.getFragmentsInPersistOrder(getChildFragmentManager()))) { if (hasChanges(
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())
@ -293,16 +289,16 @@ public final class TaskEditFragment extends InjectingFragment implements Toolbar
.show(); .show();
} }
public void onPriorityChange(int priority) {
getEditTitleControlSet().setPriority(priority);
}
/* /*
* ====================================================================== * ======================================================================
* ========================================== UI component helper classes * ========================================== UI component helper classes
* ====================================================================== * ======================================================================
*/ */
public void onPriorityChange(int priority) {
getEditTitleControlSet().setPriority(priority);
}
public void onRepeatChanged(boolean repeat) { public void onRepeatChanged(boolean repeat) {
getEditTitleControlSet().repeatChanged(repeat); getEditTitleControlSet().repeatChanged(repeat);
} }
@ -329,4 +325,9 @@ public final class TaskEditFragment extends InjectingFragment implements Toolbar
userActivityDao.createNew(userActivity); userActivityDao.createNew(userActivity);
commentsController.reloadView(); commentsController.reloadView();
} }
public interface TaskEditFragmentCallbackHandler {
void taskEditFinished();
}
} }

@ -3,8 +3,14 @@
* *
* See the file "LICENSE" for the full license governing this code. * 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.astrid.activity.TaskEditFragment.newTaskEditFragment;
import static org.tasks.tasklist.ActionUtils.applySupportActionModeColor;
import static org.tasks.ui.NavigationDrawerFragment.OnFilterItemClickedListener;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.arch.lifecycle.ViewModelProviders; import android.arch.lifecycle.ViewModelProviders;
import android.content.Intent; import android.content.Intent;
@ -17,7 +23,8 @@ import android.support.v7.view.ActionMode;
import android.view.View; import android.view.View;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import butterknife.BindView;
import butterknife.ButterKnife;
import com.todoroo.astrid.api.CaldavFilter; import com.todoroo.astrid.api.CaldavFilter;
import com.todoroo.astrid.api.Filter; import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.FilterListItem; import com.todoroo.astrid.api.FilterListItem;
@ -32,7 +39,7 @@ import com.todoroo.astrid.subtasks.SubtasksHelper;
import com.todoroo.astrid.subtasks.SubtasksListFragment; import com.todoroo.astrid.subtasks.SubtasksListFragment;
import com.todoroo.astrid.subtasks.SubtasksTagListFragment; import com.todoroo.astrid.subtasks.SubtasksTagListFragment;
import com.todoroo.astrid.timers.TimerControlSet; import com.todoroo.astrid.timers.TimerControlSet;
import javax.inject.Inject;
import org.tasks.LocalBroadcastManager; import org.tasks.LocalBroadcastManager;
import org.tasks.R; import org.tasks.R;
import org.tasks.activities.TagSettingsActivity; import org.tasks.activities.TagSettingsActivity;
@ -64,18 +71,8 @@ import org.tasks.ui.EmptyTaskEditFragment;
import org.tasks.ui.NavigationDrawerFragment; import org.tasks.ui.NavigationDrawerFragment;
import org.tasks.ui.PriorityControlSet; import org.tasks.ui.PriorityControlSet;
import org.tasks.ui.TaskListViewModel; import org.tasks.ui.TaskListViewModel;
import javax.inject.Inject;
import butterknife.BindView;
import butterknife.ButterKnife;
import timber.log.Timber; import timber.log.Timber;
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastLollipop;
import static com.todoroo.astrid.activity.TaskEditFragment.newTaskEditFragment;
import static org.tasks.tasklist.ActionUtils.applySupportActionModeColor;
import static org.tasks.ui.NavigationDrawerFragment.OnFilterItemClickedListener;
public class TaskListActivity extends InjectingAppCompatActivity implements public class TaskListActivity extends InjectingAppCompatActivity implements
OnFilterItemClickedListener, OnFilterItemClickedListener,
TaskListFragment.TaskListFragmentCallbackHandler, TaskListFragment.TaskListFragmentCallbackHandler,
@ -88,6 +85,15 @@ 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
*/
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 LOAD_FILTER = "load_filter";
public static final String OPEN_TASK = "open_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";
@Inject Preferences preferences; @Inject Preferences preferences;
@Inject SubtasksHelper subtasksHelper; @Inject SubtasksHelper subtasksHelper;
@Inject RepeatConfirmationReceiver repeatConfirmationReceiver; @Inject RepeatConfirmationReceiver repeatConfirmationReceiver;
@ -101,22 +107,11 @@ 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.drawer_layout) DrawerLayout drawerLayout;
@BindView(R.id.master) FrameLayout master; @BindView(R.id.master) FrameLayout master;
@BindView(R.id.detail) FrameLayout detail; @BindView(R.id.detail) FrameLayout detail;
private NavigationDrawerFragment navigationDrawer; private NavigationDrawerFragment navigationDrawer;
private TaskListViewModel viewModel; private TaskListViewModel viewModel;
/** 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$
private static final String FRAG_TAG_TASK_LIST = "frag_tag_task_list";
public static final String OPEN_FILTER = "open_filter"; //$NON-NLS-1$
public static final String LOAD_FILTER = "load_filter";
public static final String OPEN_TASK = "open_task"; //$NON-NLS-1$
public static final String OPEN_NEW_TASK = "open_new_task"; //$NON-NLS-1$
private int currentNightMode; private int currentNightMode;
private Filter filter; private Filter filter;
@ -167,7 +162,8 @@ 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.hasExtra(OPEN_TASK) || intent.hasExtra(OPEN_NEW_TASK)) { } else if (intent.hasExtra(OPEN_FILTER) || intent.hasExtra(LOAD_FILTER) || intent
.hasExtra(OPEN_TASK) || intent.hasExtra(OPEN_NEW_TASK)) {
taskEditFragment.save(); taskEditFragment.save();
taskEditFinished(); taskEditFinished();
} else { } else {
@ -180,7 +176,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.getFilterFromPreference(intent.getStringExtra(LOAD_FILTER)); Filter 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) {
@ -309,7 +306,7 @@ public class TaskListActivity extends InjectingAppCompatActivity implements
getTaskEditFragment().save(); getTaskEditFragment().save();
} }
if(item instanceof Filter) { if (item instanceof Filter) {
viewModel.clear(); viewModel.clear();
startActivity(TaskIntents.getTaskListIntent(this, (Filter) item)); startActivity(TaskIntents.getTaskListIntent(this, (Filter) item));
} }
@ -460,7 +457,8 @@ public class TaskListActivity extends InjectingAppCompatActivity implements
@Override @Override
public void taskEditFinished() { public void taskEditFinished() {
getSupportFragmentManager().popBackStackImmediate(TaskEditFragment.TAG_TASKEDIT_FRAGMENT, FragmentManager.POP_BACK_STACK_INCLUSIVE); getSupportFragmentManager().popBackStackImmediate(TaskEditFragment.TAG_TASKEDIT_FRAGMENT,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
hideDetailFragment(); hideDetailFragment();
hideKeyboard(); hideKeyboard();
getTaskListFragment().loadTaskListContent(); getTaskListFragment().loadTaskListContent();
@ -469,7 +467,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(INPUT_METHOD_SERVICE); InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(
INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
} }
} }

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

Loading…
Cancel
Save