diff --git a/.github/workflows/CI-build.yml b/.github/workflows/CI-build.yml index d7ea5b44..4bcda7db 100644 --- a/.github/workflows/CI-build.yml +++ b/.github/workflows/CI-build.yml @@ -26,12 +26,8 @@ jobs: # https://github.com/actions/runner-images/blob/ubuntu22/20231016.1/images/linux/Ubuntu2204-Readme.md#android - name: "Set up Android SDK" uses: android-actions/setup-android@v3 - - - name: "Set up JDK 8." - uses: actions/setup-java@v3 with: - java-version: 8 - distribution: temurin + log-accepted-android-sdk-licenses: false - name: "Checkout ${{ github.ref }} branch in ${{ github.repository }} repository." uses: actions/checkout@v3 @@ -53,7 +49,7 @@ jobs: --stacktrace --continue --no-build-cache - build -x :Android:lint + build - name: "Upload 'Unit Test Results' artifact." if: success() || failure() diff --git a/Android/build.gradle b/Android/build.gradle index adcbd2f0..0cf39cba 100644 --- a/Android/build.gradle +++ b/Android/build.gradle @@ -1,13 +1,13 @@ //name = 'Better London Travel Android App' -apply plugin: 'net.twisterrob.android-app' +apply plugin: 'net.twisterrob.gradle.plugin.android-app' apply plugin: 'com.android.application' repositories { - maven { // jcenter() deprecated - name = "jcenter" - setUrl("https://jcenter.bintray.com/") + maven { + name = "jitpack.io" + url = uri("https://jitpack.io/") content { - includeModule("com.rarepebble", "colorpicker") + includeModule("com.github.martin-stone", "hsv-alpha-color-picker-android") } } } @@ -18,7 +18,9 @@ dependencies { implementation("net.twisterrob.lib:twister-lib-android-slf4j") implementation("net.twisterrob.lib:twister-lib-android-widgets") implementation("net.twisterrob.lib:twister-lib-android-stringers") + implementation("net.twisterrob.lib:twister-lib-android-about") + implementation("net.twisterrob.lib:twister-lib-android-color_picker") implementation("net.twisterrob.lib:twister-lib-android-settings") implementation(project(':Shared')) { @@ -26,19 +28,18 @@ dependencies { } implementation("com.google.android.gms:play-services-maps:${VERSION_MAPS}") implementation("com.google.android.gms:play-services-places:${VERSION_MAPS}") - implementation("com.android.support:support-v4:${VERSION_SUPPORT}") - implementation("com.android.support:appcompat-v7:${VERSION_SUPPORT}") - implementation("com.android.support:design:${VERSION_SUPPORT}") + implementation("com.google.code.findbugs:jsr305:${VERSION_JSR305}") implementation("com.github.bumptech.glide:glide:${VERSION_GLIDE}") apply from: "${rootDir}/gradle/testCompile.gradle", to: project } android { - compileSdkVersion 28 + namespace = "net.twisterrob.blt.android" + compileSdk = 34 defaultConfig { - targetSdkVersion 19 - applicationId 'net.twisterrob.blt' + minSdk = 21 + targetSdk = 21 version { major = 1 } @@ -53,33 +54,49 @@ android { matchingFallbacks = ['release'] } } - lintOptions { + buildFeatures { + buildConfig = true + } + lint { checkAllWarnings = true checkDependencies = true + abortOnError = false lintConfig = file("lint.xml") baseline file("lint-baseline.xml") - } - flavorDimensions "app-build" + flavorDimensions += "app-build" productFlavors { full { // default + applicationId = 'net.twisterrob.blt' dimension "app-build" } range { - applicationId 'net.twisterrob.blt.range' + applicationId = 'net.twisterrob.blt.range' dimension "app-build" } } } -def generateDataBase = tasks.register("generateDataBase", Copy.class) { +abstract class GenerateDatabase extends Copy { + @Internal("An intermediate property to satisfy AGP, tracked in destination.") + abstract DirectoryProperty getOutput() +} +def generateDataBase = tasks.register("generateDataBase", GenerateDatabase.class) { dependsOn(":Data:runNetwork", ":Data:runPostCode") from(new File(project(':Data').projectDir, 'output')) { include '*.data.*.sql' } - into android.sourceSets.main.assets.srcDirs[0] + into(output) } -android.applicationVariants.all { com.android.build.gradle.api.ApplicationVariant variant -> - variant.mergeAssetsProvider.configure { dependsOn(generateDataBase) } +androidComponents { + onVariants(selector().all()) { variant -> + variant.sources.assets.addGeneratedSourceDirectory(generateDataBase, { it.output }) + afterEvaluate { + tasks.named("generate${variant.name.capitalize()}Assets").configure { + // This should be not necessary with addGeneratedSourceDirectory, but without this, it doesn't work. + dependsOn(generateDataBase) + } + } + } } diff --git a/Android/gradle.properties b/Android/gradle.properties deleted file mode 100644 index 646c51b9..00000000 --- a/Android/gradle.properties +++ /dev/null @@ -1,2 +0,0 @@ -android.useAndroidX=true -android.enableJetifier=true diff --git a/Android/src/main/AndroidManifest.xml b/Android/src/main/AndroidManifest.xml index 50280cc7..6fb671dc 100644 --- a/Android/src/main/AndroidManifest.xml +++ b/Android/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ + > diff --git a/Android/src/main/java/net/twisterrob/android/utils/concurrent/MailSenderAsyncTask.java b/Android/src/main/java/net/twisterrob/android/utils/concurrent/MailSenderAsyncTask.java new file mode 100644 index 00000000..f9cb29f4 --- /dev/null +++ b/Android/src/main/java/net/twisterrob/android/utils/concurrent/MailSenderAsyncTask.java @@ -0,0 +1,31 @@ +package net.twisterrob.android.utils.concurrent; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import android.os.AsyncTask; + +import net.twisterrob.java.io.MailSender; + +public class MailSenderAsyncTask extends AsyncTask { + private static final Logger LOG = LoggerFactory.getLogger(MailSenderAsyncTask.class); + + private final MailSender m = new MailSender(); + + public MailSenderAsyncTask(String subject, String from, String... to) { + m.setTo(to); + m.setFrom(from); + m.setSubject(subject); + } + + @Override protected Boolean doInBackground(String... params) { + try { + m.setBody(params[0]); + m.send(); + return true; + } catch (Exception ex) { + LOG.error("Cannot send {}.", m, ex); + return false; + } + } +} diff --git a/Android/src/main/java/net/twisterrob/blt/android/ui/ColorPickerWidget.java b/Android/src/main/java/net/twisterrob/blt/android/ui/ColorPickerWidget.java index e813fec2..0cfd8fd9 100644 --- a/Android/src/main/java/net/twisterrob/blt/android/ui/ColorPickerWidget.java +++ b/Android/src/main/java/net/twisterrob/blt/android/ui/ColorPickerWidget.java @@ -4,8 +4,8 @@ import android.view.View; import android.view.View.OnClickListener; -import net.twisterrob.android.utils.tools.DialogTools; import net.twisterrob.android.utils.tools.DialogTools.PopupCallbacks; +import net.twisterrob.android.utils.tools.DialogToolsColor; public class ColorPickerWidget { private final View display; @@ -28,7 +28,7 @@ public ColorPickerWidget(View view) { this.display = view; this.display.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - DialogTools.pickColor(v.getContext(), value, new PopupCallbacks() { + DialogToolsColor.pickColor(v.getContext(), value, new PopupCallbacks() { @Override public void finished(Integer value) { if (value != null) { setValueInternal(value, true); diff --git a/Android/src/main/java/net/twisterrob/blt/android/ui/activity/PredictionSummaryActivity.java b/Android/src/main/java/net/twisterrob/blt/android/ui/activity/PredictionSummaryActivity.java index 0a1b3e00..5fa08cef 100644 --- a/Android/src/main/java/net/twisterrob/blt/android/ui/activity/PredictionSummaryActivity.java +++ b/Android/src/main/java/net/twisterrob/blt/android/ui/activity/PredictionSummaryActivity.java @@ -227,17 +227,16 @@ protected void restoreExpandedState() { } @Override public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.menu__option__compass_east: - case R.id.menu__option__compass_west: - case R.id.menu__option__compass_north: - case R.id.menu__option__compass_south: - case R.id.menu__option__compass_others: - toggleCompass(menuIDs.get(item.getItemId())); - return true; - default: - return super.onOptionsItemSelected(item); + int id = item.getItemId(); + if (id == R.id.menu__option__compass_east + || id == R.id.menu__option__compass_west + || id == R.id.menu__option__compass_north + || id == R.id.menu__option__compass_south + || id == R.id.menu__option__compass_others) { + toggleCompass(menuIDs.get(item.getItemId())); + return true; } + return super.onOptionsItemSelected(item); } protected final Set m_directionsEnabled = EnumSet.noneOf(PlatformDirection.class); diff --git a/Android/src/main/java/net/twisterrob/blt/android/ui/activity/RangeOptionsFragment.java b/Android/src/main/java/net/twisterrob/blt/android/ui/activity/RangeOptionsFragment.java index ada463df..d69de2d8 100644 --- a/Android/src/main/java/net/twisterrob/blt/android/ui/activity/RangeOptionsFragment.java +++ b/Android/src/main/java/net/twisterrob/blt/android/ui/activity/RangeOptionsFragment.java @@ -263,17 +263,17 @@ private ColorPickerWidget color(@IdRes int menuItemId, .show(); return true; } - switch (item.getItemId()) { - case R.id.menu__action__range__reset_generator: - genConfig.set(new RangeMapGeneratorConfig()); - bindConfigs(genConfig, drawConfig); // update self UI - configsUpdatedListener.onConfigsUpdated(); - return true; - case R.id.menu__action__range__reset_drawing: - drawConfig.set(new RangeMapDrawerConfig()); - bindConfigs(genConfig, drawConfig); // update self UI - configsUpdatedListener.onConfigsUpdated(); - return true; + int id = item.getItemId(); + if (id == R.id.menu__action__range__reset_generator) { + genConfig.set(new RangeMapGeneratorConfig()); + bindConfigs(genConfig, drawConfig); // update self UI + configsUpdatedListener.onConfigsUpdated(); + return true; + } else if (id == R.id.menu__action__range__reset_drawing) { + drawConfig.set(new RangeMapDrawerConfig()); + bindConfigs(genConfig, drawConfig); // update self UI + configsUpdatedListener.onConfigsUpdated(); + return true; } return super.onOptionsItemSelected(item); } diff --git a/Android/src/main/java/net/twisterrob/blt/android/ui/activity/main/MainActivity.java b/Android/src/main/java/net/twisterrob/blt/android/ui/activity/main/MainActivity.java index 02b1de8e..8bcc595d 100644 --- a/Android/src/main/java/net/twisterrob/blt/android/ui/activity/main/MainActivity.java +++ b/Android/src/main/java/net/twisterrob/blt/android/ui/activity/main/MainActivity.java @@ -59,10 +59,10 @@ public class MainActivity extends BaseActivity { } @Override public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.menu__action__about: - startActivity(new Intent(getApplicationContext(), AboutActivity.class)); - return true; + int id = item.getItemId(); + if (id == R.id.menu__action__about) { + startActivity(new Intent(getApplicationContext(), AboutActivity.class)); + return true; } return super.onOptionsItemSelected(item); } diff --git a/Android/src/range/AndroidManifest.xml b/Android/src/range/AndroidManifest.xml index 63b74e7e..0f80d8d2 100644 --- a/Android/src/range/AndroidManifest.xml +++ b/Android/src/range/AndroidManifest.xml @@ -3,7 +3,7 @@ + > diff --git a/Android/src/range/java/net/twisterrob/blt/android/ui/activity/StandaloneRangeMapActivity.java b/Android/src/range/java/net/twisterrob/blt/android/ui/activity/StandaloneRangeMapActivity.java index 8b12b9ac..f58eef9c 100644 --- a/Android/src/range/java/net/twisterrob/blt/android/ui/activity/StandaloneRangeMapActivity.java +++ b/Android/src/range/java/net/twisterrob/blt/android/ui/activity/StandaloneRangeMapActivity.java @@ -14,11 +14,11 @@ public class StandaloneRangeMapActivity extends RangeMapActivity { } @Override public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - case R.id.menu__action__about: - startActivity(new Intent(getApplicationContext(), AboutActivity.class)); - return true; + int id = item.getItemId(); + if (id == android.R.id.home + || id == R.id.menu__action__about) { + startActivity(new Intent(getApplicationContext(), AboutActivity.class)); + return true; } return super.onOptionsItemSelected(item); } diff --git a/AppEngine/build.gradle b/AppEngine/build.gradle index 30fbb2db..10242220 100644 --- a/AppEngine/build.gradle +++ b/AppEngine/build.gradle @@ -1,11 +1,13 @@ apply plugin: 'java' apply plugin: 'war' -apply plugin: 'com.google.cloud.tools.appengine' -apply plugin: 'com.google.cloud.tools.endpoints-framework-server' +apply plugin: 'com.google.cloud.tools.appengine-appenginewebxml' +//apply plugin: 'com.google.cloud.tools.endpoints-framework-server' apply plugin: 'idea' -sourceCompatibility = JavaVersion.VERSION_1_7 -targetCompatibility = JavaVersion.VERSION_1_8 +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} configurations { dev @@ -80,6 +82,6 @@ appengine { com.google.cloud.tools.gradle.appengine.standard.AppEngineStandardEx } } -endpointsServer { - hostname = "twisterrob-london.appspot.com" -} +//endpointsServer { +// hostname = "twisterrob-london.appspot.com" +//} diff --git a/AppEngine/src/test/java/net/twisterrob/blt/gapp/viewmodel/LineColorTest.java b/AppEngine/src/test/java/net/twisterrob/blt/gapp/viewmodel/LineColorTest.java index 463ff092..7593febe 100644 --- a/AppEngine/src/test/java/net/twisterrob/blt/gapp/viewmodel/LineColorTest.java +++ b/AppEngine/src/test/java/net/twisterrob/blt/gapp/viewmodel/LineColorTest.java @@ -4,6 +4,8 @@ import org.junit.*; import org.mockito.*; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; @@ -14,11 +16,9 @@ import net.twisterrob.blt.model.*; public class LineColorTest { - @Mock LineColors colors; + @Rule public final MockitoRule mockito = MockitoJUnit.rule(); - @Before public void setUp() { - MockitoAnnotations.initMocks(this); - } + @Mock LineColors colors; @Test public void testShortColor() { testColors(0x000000AB, "#0000AB", 0x000000CD, "#0000CD"); @@ -54,7 +54,7 @@ private void testColors(int bgColor, String bgExpect, int fgColor, String fgExpe } } assertThat(seen, hasSize(Line.values().length)); - verifyZeroInteractions(colors); + verifyNoInteractions(colors); } @Test(expected = UnsupportedOperationException.class) public void testAllColorsCannotRemove() { diff --git a/Data/build.gradle b/Data/build.gradle index 5481e1cb..66bccff2 100644 --- a/Data/build.gradle +++ b/Data/build.gradle @@ -4,11 +4,13 @@ version = '0.0.1-SNAPSHOT' // Standalone project to handle large feeds apply plugin: 'java-library' -apply plugin: 'net.twisterrob.java' +apply plugin: 'net.twisterrob.gradle.plugin.java' dependencies { //configurations.implementation.resolutionStrategy.cacheChangingModulesFor 0, 'seconds' // -SNAPSHOT api project(':Shared') + implementation("com.google.code.findbugs:jsr305:${VERSION_JSR305}") + implementation("org.slf4j:slf4j-api:${VERSION_SLF4J}") runtimeOnly "org.slf4j:slf4j-simple:${VERSION_SLF4J}" implementation 'org.xerial:sqlite-jdbc:3.7.15-M1' @@ -46,7 +48,7 @@ task runNetwork(type: JavaExec) { outputs.dir outputDir group = ApplicationPlugin.APPLICATION_GROUP classpath = sourceSets.main.runtimeClasspath - main = 'net.twisterrob.blt.data.apps.TravelNetworkParser' + mainClass = 'net.twisterrob.blt.data.apps.TravelNetworkParser' args = [ inputDir, outputDir ] enableAssertions = true } @@ -58,14 +60,14 @@ task runPostCode(type: JavaExec) { outputs.file outputFile group = ApplicationPlugin.APPLICATION_GROUP classpath = sourceSets.main.runtimeClasspath - main = 'net.twisterrob.blt.data.apps.PostCodeAreas' + mainClass = 'net.twisterrob.blt.data.apps.PostCodeAreas' enableAssertions = true } task runDisplay(type: JavaExec) { group = ApplicationPlugin.APPLICATION_GROUP classpath = sourceSets.main.runtimeClasspath - main = 'net.twisterrob.blt.data.apps.DisplayLine' + mainClass = 'net.twisterrob.blt.data.apps.DisplayLine' args = [ 'DLR' ] if (project.hasProperty('lines')) { args = project.property('lines').toString().split(',') as List; diff --git a/Shared/android-polyfill/build.gradle b/Shared/android-polyfill/build.gradle index e9b471c7..3f4e5fd5 100644 --- a/Shared/android-polyfill/build.gradle +++ b/Shared/android-polyfill/build.gradle @@ -1,4 +1,9 @@ -apply plugin: 'net.twisterrob.java' +apply plugin: 'net.twisterrob.gradle.plugin.java' + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} dependencies { implementation 'net.sf.kxml:kxml2:2.3.0' diff --git a/Shared/android-polyfill/src/main/java/android/util/Xml.java b/Shared/android-polyfill/src/main/java/android/util/Xml.java index 3f8a47ac..2fcf2625 100644 --- a/Shared/android-polyfill/src/main/java/android/util/Xml.java +++ b/Shared/android-polyfill/src/main/java/android/util/Xml.java @@ -18,9 +18,11 @@ import java.io.*; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParserFactory; + import org.kxml2.io.KXmlParser; import org.xml.sax.*; -import org.xml.sax.helpers.XMLReaderFactory; import org.xmlpull.v1.*; /** @@ -41,14 +43,10 @@ public class Xml { * Parses the given xml string and fires events on the given SAX handler. */ public static void parse(String xml, ContentHandler contentHandler) - throws SAXException { - try { - XMLReader reader = XMLReaderFactory.createXMLReader(); - reader.setContentHandler(contentHandler); - reader.parse(new InputSource(new StringReader(xml))); - } catch (IOException e) { - throw new AssertionError(e); - } + throws IOException, SAXException { + XMLReader reader = newXMLReader(); + reader.setContentHandler(contentHandler); + reader.parse(new InputSource(new StringReader(xml))); } /** @@ -57,7 +55,7 @@ public static void parse(String xml, ContentHandler contentHandler) */ public static void parse(Reader in, ContentHandler contentHandler) throws IOException, SAXException { - XMLReader reader = XMLReaderFactory.createXMLReader(); + XMLReader reader = newXMLReader(); reader.setContentHandler(contentHandler); reader.parse(new InputSource(in)); } @@ -66,15 +64,25 @@ public static void parse(Reader in, ContentHandler contentHandler) * Parses xml from the given input stream and fires events on the given SAX * handler. */ - public static void parse(InputStream in, Encoding encoding, - ContentHandler contentHandler) throws IOException, SAXException { - XMLReader reader = XMLReaderFactory.createXMLReader(); + public static void parse(InputStream in, Encoding encoding, ContentHandler contentHandler) + throws IOException, SAXException { + XMLReader reader = newXMLReader(); reader.setContentHandler(contentHandler); InputSource source = new InputSource(in); source.setEncoding(encoding.expatName); reader.parse(source); } + private static XMLReader newXMLReader() throws SAXException { + SAXParserFactory factory = SAXParserFactory.newInstance(); + try { + factory.setFeature("http://xml.org/sax/features/namespaces", true); + return factory.newSAXParser().getXMLReader(); + } catch (ParserConfigurationException e) { + throw new SAXException("Cannot initialize SAX parser", e); + } + } + /** * Returns a new pull parser with namespace support. */ diff --git a/Shared/android-polyfill/src/main/java/com/android/internal/util/XmlUtils.java b/Shared/android-polyfill/src/main/java/com/android/internal/util/XmlUtils.java index 6296951b..b4f78300 100644 --- a/Shared/android-polyfill/src/main/java/com/android/internal/util/XmlUtils.java +++ b/Shared/android-polyfill/src/main/java/com/android/internal/util/XmlUtils.java @@ -792,9 +792,9 @@ private static final Object readThisValueXml(XmlPullParser parser, String[] name } else if (tagName.equals("long")) { res = Long.valueOf(parser.getAttributeValue(null, "value")); } else if (tagName.equals("float")) { - res = new Float(parser.getAttributeValue(null, "value")); + res = Float.valueOf(parser.getAttributeValue(null, "value")); } else if (tagName.equals("double")) { - res = new Double(parser.getAttributeValue(null, "value")); + res = Double.valueOf(parser.getAttributeValue(null, "value")); } else if (tagName.equals("boolean")) { res = Boolean.valueOf(parser.getAttributeValue(null, "value")); } else if (tagName.equals("int-array")) { diff --git a/Shared/build.gradle b/Shared/build.gradle index 529252b9..5c867a13 100644 --- a/Shared/build.gradle +++ b/Shared/build.gradle @@ -1,14 +1,21 @@ apply plugin: 'java-library' -apply plugin: 'net.twisterrob.java' -sourceCompatibility = JavaVersion.VERSION_1_7 -targetCompatibility = JavaVersion.VERSION_1_8 +apply plugin: 'net.twisterrob.gradle.plugin.java' + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + // Better London Travel Shared // Shared model and surrounding classes //name = 'twister-travel-shared' version = '0.0.1-SNAPSHOT' dependencies { api('net.twisterrob.lib:twister-lib-general') + api('net.twisterrob.lib:twister-lib-core') + implementation("com.google.code.findbugs:jsr305:${VERSION_JSR305}") + implementation("org.slf4j:slf4j-api:${VERSION_SLF4J}") implementation project(':Shared:android-polyfill') implementation('net.twisterrob.lib:twister-lib-java_desktop') diff --git a/Shared/src/main/java/net/twisterrob/blt/io/feeds/BaseFeedHandler.java b/Shared/src/main/java/net/twisterrob/blt/io/feeds/BaseFeedHandler.java index a0a274ef..f8aaeac8 100644 --- a/Shared/src/main/java/net/twisterrob/blt/io/feeds/BaseFeedHandler.java +++ b/Shared/src/main/java/net/twisterrob/blt/io/feeds/BaseFeedHandler.java @@ -13,7 +13,7 @@ protected static void sendMail(String body) { MailSender sender = new MailSender(); sender.setSubject("Better London Travel"); sender.setFrom("better-london-travel@twisterrob.net"); - sender.setTo("papp.robert.s@gmail.com"); + sender.setTos("papp.robert.s@gmail.com"); sender.setBody(body); try { sender.send(); diff --git a/Shared/src/main/java/net/twisterrob/java/io/MailSender.java b/Shared/src/main/java/net/twisterrob/java/io/MailSender.java new file mode 100644 index 00000000..e8f55c9e --- /dev/null +++ b/Shared/src/main/java/net/twisterrob/java/io/MailSender.java @@ -0,0 +1,71 @@ +package net.twisterrob.java.io; + +import java.io.*; +import java.net.*; +import java.util.Locale; + +import net.twisterrob.java.utils.ArrayTools; + +public class MailSender { + private String from = ""; + private String[] to; + private String subject = ""; + private String body = ""; + + public void send() throws IOException { + try { + URL url = new URL("http://twisterrob-london.appspot.com/InternalFeedback"); + HttpURLConnection conn = (HttpURLConnection)url.openConnection(); + conn.setDoInput(true); + conn.setDoOutput(true); + conn.setRequestMethod("POST"); + conn.connect(); + IOTools.writeAll(conn.getOutputStream(), this.toString()); + InputStream response = new BufferedInputStream(conn.getInputStream()); + String result = IOTools.readAll(response, "UTF-8"); + conn.disconnect(); + if (result.trim().length() != 0) { + throw new IOException("Server responded with: " + result); + } + } catch (IOException ex) { + throw new IOException("Cannot send " + this, ex); + } + } + + public String getBody() { + return body; + } + public void setBody(String body) { + this.body = body; + } + + public String[] getTo() { + return to; + } + @SuppressWarnings("MethodCanBeVariableArityMethod") // Contradicts lint:KotlinPropertyAccess. + public void setTo(String[] toArr) { + this.to = toArr; + } + public void setTos(String... toArr) { + this.to = toArr; + } + + public String getFrom() { + return from; + } + public void setFrom(String string) { + this.from = string; + } + + public String getSubject() { + return subject; + } + public void setSubject(String string) { + this.subject = string; + } + + @Override public String toString() { + return String.format(Locale.ROOT, "email from %s to %s: %s\n%s", + from, ArrayTools.toString(to), subject, body); + } +} diff --git a/build.gradle b/build.gradle index 10463549..f7865335 100644 --- a/build.gradle +++ b/build.gradle @@ -15,7 +15,7 @@ allprojects { "-Werror", "-Xmaxwarns", "1000", "-Xmaxerrs", "1000", - "-Xlint:deprecation", + "-Xlint:-deprecation", "-Xlint:unchecked", ] } diff --git a/gradle.properties b/gradle.properties index 0c282a08..1592ce0c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,21 +2,25 @@ org.gradle.daemon=true org.gradle.configureondemand=true org.gradle.parallel=true org.gradle.jvmargs=-Xmx2048M + +android.useAndroidX=true +android.enableJetifier=true +android.nonTransitiveRClass=false + # # # Common # VERSION_SLF4J=1.7.30 +VERSION_JSR305=3.0.2 # # # Android # -VERSION_AGP=4.1.3 -VERSION_TWISTER_GRADLE=0.13 +VERSION_AGP=8.1.1 +VERSION_TWISTER_GRADLE=0.16 # # TODO replace SupportPlaceAutocompleteFragment when updating to AndroidX -# (https://developers.google.com/places/android-sdk/client-migration#embed_an_autocompletefragment) -VERSION_SUPPORT=28.0.0 # TODO update to 17.0.0 when using AndroidX VERSION_MAPS=16.1.0 VERSION_GLIDE=3.8.0 @@ -25,7 +29,7 @@ VERSION_GLIDE=3.8.0 # AppEngine # # https://github.com/GoogleCloudPlatform/app-gradle-plugin/blob/master/CHANGELOG.md -VERSION_APPENGINE_PLUGIN=2.4.1 +VERSION_APPENGINE_PLUGIN=2.5.0 # https://cloud.google.com/appengine/docs/standard/java/release-notes VERSION_APPENGINE=1.9.83 # https://github.com/GoogleCloudPlatform/endpoints-framework-gradle-plugin/blob/master/CHANGELOG.md @@ -42,11 +46,8 @@ VERSION_LOG4J=2.14.0 # # Test # -# This cannot go above 47, until powermock pulls some new classes -# https://github.com/jayway/powermock/issues/686 -VERSION_MOCKITO=2.0.47-beta -VERSION_POWERMOCK=1.6.5 -VERSION_JUNIT=4.13.1 +VERSION_MOCKITO=5.7.0 +VERSION_JUNIT=4.13.2 # Use this instead of 1.3 # If `hamcrest-1.3` appears in the dependency list, check if it's excluded from all usages. VERSION_HAMCREST=2.0.0.0 diff --git a/gradle/testCompile.gradle b/gradle/testCompile.gradle index 616e9b8a..d0a9ae66 100644 --- a/gradle/testCompile.gradle +++ b/gradle/testCompile.gradle @@ -8,16 +8,6 @@ dependencies { exclude module: 'junit' } testImplementation("org.mockito:mockito-core:${VERSION_MOCKITO}") {} - testImplementation("org.powermock:powermock-api-mockito2:${VERSION_POWERMOCK}") { - // this depends on hamcrest-core too which we don't want - exclude module: 'hamcrest-core' - } - testImplementation("org.powermock:powermock-module-junit4:${VERSION_POWERMOCK}") { - // this needs to be excluded because otherwise the hamcrest-core exclusion above doesn't work - exclude module: 'junit' - } testImplementation 'com.shazam:gwen:1.0.2' -// testImplementation 'cglib:cglib:3.2.4' -// testImplementation 'pl.pragmatists:JUnitParams:1.0.4' -// testImplementation 'nl.jqno.equalsverifier:equalsverifier:1.7.2' + testRuntimeOnly("org.slf4j:slf4j-simple:${VERSION_SLF4J}") } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 5c2d1cf0..e708b1c0 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 14e30f74..84a0b92f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 83f2acfd..4f906e0c 100755 --- a/gradlew +++ b/gradlew @@ -82,6 +82,7 @@ esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -129,6 +130,7 @@ fi if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath @@ -154,19 +156,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi @@ -175,14 +177,9 @@ save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } -APP_ARGS=$(save "$@") +APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 9618d8d9..107acd32 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -51,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -61,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/libs b/libs index 89ec813e..93d78664 160000 --- a/libs +++ b/libs @@ -1 +1 @@ -Subproject commit 89ec813e034d63ebd28d76907fb27b36afea5fd2 +Subproject commit 93d78664464c005bd39883d78b24d713fd2454a3 diff --git a/settings.gradle b/settings.gradle index fbed329e..6a298a98 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,12 +6,6 @@ include ':AppEngine' include ':Shared:android-polyfill' include ':Data' -includeBuild("libs/twister-lib-java") { build -> - name = "twister-libs-java" - apply from: new File(build.projectDir, "settings.substitutions.gradle"), to: build -} - -includeBuild("libs/twister-lib-android") { build -> - name = "twister-libs-android" - apply from: new File(build.projectDir, "settings.substitutions.gradle"), to: build +includeBuild("libs") { build -> + apply from: new File(build.projectDir, "gradle/settings.substitutions.gradle"), to: build }