diff --git a/app/build.gradle b/app/build.gradle index ae3c59e49..168b59458 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,6 +30,10 @@ dependencies { compile 'io.reactivex:rxandroid:0.23.0' testCompile 'junit:junit:4.12' + + androidTestCompile 'com.android.support:support-annotations:23.2.1' + androidTestCompile 'com.android.support.test:runner:0.5' + androidTestCompile 'com.android.support.test:rules:0.5' } if (!hasProperty('sourceDeps')) { @@ -147,6 +151,10 @@ android { targetCompatibility JavaVersion.VERSION_1_7 } + defaultConfig { + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + testOptions { // prevent tests from dying on android.util.Log calls unitTests.returnDefaultValues = true diff --git a/app/src/androidTest/java/org/fdroid/fdroid/FDroidTest.java b/app/src/androidTest/java/org/fdroid/fdroid/FDroidTest.java deleted file mode 100644 index 07d9f3ee3..000000000 --- a/app/src/androidTest/java/org/fdroid/fdroid/FDroidTest.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.fdroid.fdroid; - -import android.annotation.TargetApi; -import android.os.Build; -import android.test.ActivityInstrumentationTestCase2; - -@TargetApi(Build.VERSION_CODES.CUPCAKE) -public class FDroidTest extends ActivityInstrumentationTestCase2 { - - public FDroidTest() { - super("org.fdroid.fdroid", FDroid.class); - } - -} diff --git a/app/src/androidTest/java/org/fdroid/fdroid/FileCompatTest.java b/app/src/androidTest/java/org/fdroid/fdroid/FileCompatTest.java index 53be0b601..97fe44ecf 100644 --- a/app/src/androidTest/java/org/fdroid/fdroid/FileCompatTest.java +++ b/app/src/androidTest/java/org/fdroid/fdroid/FileCompatTest.java @@ -1,17 +1,32 @@ package org.fdroid.fdroid; +import android.app.Instrumentation; import android.os.Build; -import android.test.InstrumentationTestCase; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; import android.util.Log; import org.fdroid.fdroid.compat.FileCompatForTest; import org.fdroid.fdroid.data.SanitizedFile; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; import java.io.File; import java.util.UUID; -@SuppressWarnings("PMD") // TODO port this to JUnit 4 semantics -public class FileCompatTest extends InstrumentationTestCase { +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + + +/** + * This test needs to run on the emulator, even though it technically could + * run as a plain JUnit test, because it is testing the specifics of + * Android's symlink handling. + */ +@RunWith(AndroidJUnit4.class) +public class FileCompatTest { private static final String TAG = "FileCompatTest"; @@ -19,14 +34,17 @@ public class FileCompatTest extends InstrumentationTestCase { private SanitizedFile sourceFile; private SanitizedFile destFile; + @Before public void setUp() { - dir = TestUtils.getWriteableDir(getInstrumentation()); - sourceFile = SanitizedFile.knownSanitized(TestUtils.copyAssetToDir(getInstrumentation().getContext(), "simpleIndex.jar", dir)); + Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); + dir = TestUtils.getWriteableDir(instrumentation); + sourceFile = SanitizedFile.knownSanitized(TestUtils.copyAssetToDir(instrumentation.getContext(), "simpleIndex.jar", dir)); destFile = new SanitizedFile(dir, "dest-" + UUID.randomUUID() + ".testproduct"); assertFalse(destFile.exists()); assertTrue(sourceFile.getAbsolutePath() + " should exist.", sourceFile.exists()); } + @After public void tearDown() { if (!sourceFile.delete()) { System.out.println("Can't delete " + sourceFile.getAbsolutePath() + "."); @@ -37,11 +55,13 @@ public class FileCompatTest extends InstrumentationTestCase { } } + @Test public void testSymlinkRuntime() { FileCompatForTest.symlinkRuntimeTest(sourceFile, destFile); assertTrue(destFile.getAbsolutePath() + " should exist after symlinking", destFile.exists()); } + @Test public void testSymlinkLibcore() { if (Build.VERSION.SDK_INT >= 19) { @@ -52,6 +72,7 @@ public class FileCompatTest extends InstrumentationTestCase { } } + @Test public void testSymlinkOs() { if (Build.VERSION.SDK_INT >= 21) { diff --git a/app/src/androidTest/java/org/fdroid/fdroid/RepoUpdaterTest.java b/app/src/androidTest/java/org/fdroid/fdroid/RepoUpdaterTest.java index 8aa99a9e1..95c95b65f 100644 --- a/app/src/androidTest/java/org/fdroid/fdroid/RepoUpdaterTest.java +++ b/app/src/androidTest/java/org/fdroid/fdroid/RepoUpdaterTest.java @@ -1,16 +1,23 @@ package org.fdroid.fdroid; +import android.app.Instrumentation; import android.content.Context; -import android.test.InstrumentationTestCase; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; import org.fdroid.fdroid.RepoUpdater.UpdateException; import org.fdroid.fdroid.data.Repo; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; import java.io.File; -@SuppressWarnings("PMD") // TODO port this to JUnit 4 semantics -public class RepoUpdaterTest extends InstrumentationTestCase { +import static org.junit.Assert.fail; + +@RunWith(AndroidJUnit4.class) +public class RepoUpdaterTest { private static final String TAG = "RepoUpdaterTest"; private Context context; @@ -19,15 +26,17 @@ public class RepoUpdaterTest extends InstrumentationTestCase { String simpleIndexPubkey = "308201ee30820157a0030201020204300d845b300d06092a864886f70d01010b0500302a3110300e060355040b1307462d44726f6964311630140603550403130d70616c6174736368696e6b656e301e170d3134303432373030303633315a170d3431303931323030303633315a302a3110300e060355040b1307462d44726f6964311630140603550403130d70616c6174736368696e6b656e30819f300d06092a864886f70d010101050003818d0030818902818100a439472e4b6d01141bfc94ecfe131c7c728fdda670bb14c57ca60bd1c38a8b8bc0879d22a0a2d0bc0d6fdd4cb98d1d607c2caefbe250a0bd0322aedeb365caf9b236992fac13e6675d3184a6c7c6f07f73410209e399a9da8d5d7512bbd870508eebacff8b57c3852457419434d34701ccbf692267cbc3f42f1c5d1e23762d790203010001a321301f301d0603551d0e041604140b1840691dab909746fde4bfe28207d1cae15786300d06092a864886f70d01010b05000381810062424c928ffd1b6fd419b44daafef01ca982e09341f7077fb865905087aeac882534b3bd679b51fdfb98892cef38b63131c567ed26c9d5d9163afc775ac98ad88c405d211d6187bde0b0d236381cc574ba06ef9080721a92ae5a103a7301b2c397eecc141cc850dd3e123813ebc41c59d31ddbcb6e984168280c53272f6a442b"; - @Override - protected void setUp() { - context = getInstrumentation().getContext(); - testFilesDir = TestUtils.getWriteableDir(getInstrumentation()); + @Before + public void setUp() { + Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); + context = instrumentation.getContext(); + testFilesDir = TestUtils.getWriteableDir(instrumentation); Repo repo = new Repo(); repo.pubkey = this.simpleIndexPubkey; repoUpdater = new RepoUpdater(context, repo); } + @Test public void testExtractIndexFromJar() { if (!testFilesDir.canWrite()) { return; @@ -43,20 +52,17 @@ public class RepoUpdaterTest extends InstrumentationTestCase { } } - public void testExtractIndexFromJarWithoutSignatureJar() { + @Test(expected = UpdateException.class) + public void testExtractIndexFromJarWithoutSignatureJar() throws UpdateException { if (!testFilesDir.canWrite()) { return; } // this is supposed to fail - try { - File jarFile = TestUtils.copyAssetToDir(context, "simpleIndexWithoutSignature.jar", testFilesDir); - repoUpdater.processDownloadedFile(jarFile); - fail(); - } catch (UpdateException e) { - // success! - } + File jarFile = TestUtils.copyAssetToDir(context, "simpleIndexWithoutSignature.jar", testFilesDir); + repoUpdater.processDownloadedFile(jarFile); } + @Test public void testExtractIndexFromJarWithCorruptedManifestJar() { if (!testFilesDir.canWrite()) { return; @@ -74,6 +80,7 @@ public class RepoUpdaterTest extends InstrumentationTestCase { } } + @Test public void testExtractIndexFromJarWithCorruptedSignature() { if (!testFilesDir.canWrite()) { return; @@ -91,6 +98,7 @@ public class RepoUpdaterTest extends InstrumentationTestCase { } } + @Test public void testExtractIndexFromJarWithCorruptedCertificate() { if (!testFilesDir.canWrite()) { return; @@ -108,6 +116,7 @@ public class RepoUpdaterTest extends InstrumentationTestCase { } } + @Test public void testExtractIndexFromJarWithCorruptedEverything() { if (!testFilesDir.canWrite()) { return; @@ -125,6 +134,7 @@ public class RepoUpdaterTest extends InstrumentationTestCase { } } + @Test public void testExtractIndexFromMasterKeyIndexJar() { if (!testFilesDir.canWrite()) { return; @@ -133,8 +143,10 @@ public class RepoUpdaterTest extends InstrumentationTestCase { try { File jarFile = TestUtils.copyAssetToDir(context, "masterKeyIndex.jar", testFilesDir); repoUpdater.processDownloadedFile(jarFile); - fail(); - } catch (UpdateException | SecurityException e) { + fail(); //NOPMD + } catch (UpdateException e) { + // success! + } catch (SecurityException e) { // success! } } diff --git a/app/src/androidTest/java/org/fdroid/fdroid/RepoXMLHandlerTest.java b/app/src/androidTest/java/org/fdroid/fdroid/RepoXMLHandlerTest.java index dcbb8bd43..041f5b0e8 100644 --- a/app/src/androidTest/java/org/fdroid/fdroid/RepoXMLHandlerTest.java +++ b/app/src/androidTest/java/org/fdroid/fdroid/RepoXMLHandlerTest.java @@ -2,7 +2,7 @@ package org.fdroid.fdroid; import android.support.annotation.NonNull; -import android.test.AndroidTestCase; +import android.support.test.runner.AndroidJUnit4; import android.text.TextUtils; import android.util.Log; @@ -10,6 +10,8 @@ import org.fdroid.fdroid.data.Apk; import org.fdroid.fdroid.data.App; import org.fdroid.fdroid.data.Repo; import org.fdroid.fdroid.mock.MockRepo; +import org.junit.Test; +import org.junit.runner.RunWith; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; @@ -24,20 +26,18 @@ import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; -@SuppressWarnings("PMD") // TODO port this to JUnit 4 semantics -public class RepoXMLHandlerTest extends AndroidTestCase { +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +@RunWith(AndroidJUnit4.class) +public class RepoXMLHandlerTest { private static final String TAG = "RepoXMLHandlerTest"; private static final String FAKE_PUBKEY = "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345"; - public RepoXMLHandlerTest() { - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - } - + @Test public void testSimpleIndex() { Repo expectedRepo = new Repo(); expectedRepo.name = "F-Droid"; @@ -47,6 +47,7 @@ public class RepoXMLHandlerTest extends AndroidTestCase { handlerTestSuite(expectedRepo, actualDetails, 0, 0, -1, 12); } + @Test public void testSmallRepo() { Repo expectedRepo = new Repo(); expectedRepo.name = "Android-Nexus-7-20139453 on UNSET"; @@ -70,6 +71,7 @@ public class RepoXMLHandlerTest extends AndroidTestCase { }); } + @Test public void testMediumRepo() { Repo expectedRepo = new Repo(); expectedRepo.name = "Guardian Project Official Releases"; @@ -96,6 +98,7 @@ public class RepoXMLHandlerTest extends AndroidTestCase { }); } + @Test public void testLargeRepo() { Repo expectedRepo = new Repo(); expectedRepo.name = "F-Droid"; diff --git a/app/src/androidTest/java/org/fdroid/fdroid/UtilsTest.java b/app/src/androidTest/java/org/fdroid/fdroid/UtilsTest.java index 7e4265f56..da038dd10 100644 --- a/app/src/androidTest/java/org/fdroid/fdroid/UtilsTest.java +++ b/app/src/androidTest/java/org/fdroid/fdroid/UtilsTest.java @@ -1,10 +1,19 @@ package org.fdroid.fdroid; -import android.test.AndroidTestCase; +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; -@SuppressWarnings("PMD") // TODO port this to JUnit 4 semantics -public class UtilsTest extends AndroidTestCase { +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +@RunWith(AndroidJUnit4.class) +public class UtilsTest { String fdroidFingerprint = "43238D512C1E5EB2D6569F4A3AFBF5523418B82E0A3ED1552770ABB9A9C9CCAB"; String fdroidPubkey = "3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef"; @@ -34,57 +43,60 @@ public class UtilsTest extends AndroidTestCase { String fingerprintLongByOneFingerprint = "59050C8155DCA377F23D5A15B77D37134000CDBD8B42FBFBE0E3F38096E68CECE"; String fingerprintLongByOnePubkey = "308203c5308202ada00302010202047b7cf549300d06092a864886f70d01010b0500308192310b30090603550406130255533111300f060355040813084e657720596f726b3111300f060355040713084e657720596f726b311d301b060355040a131454686520477561726469616e2050726f6a656374311f301d060355040b1316477561726469616e20462d44726f6964204275696c64311d301b06035504031314677561726469616e70726f6a6563742e696e666f301e170d3132313032393130323530305a170d3430303331363130323530305a308192310b30090603550406130255533111300f060355040813084e657720596f726b3111300f060355040713084e657720596f726b311d301b060355040a131454686520477561726469616e2050726f6a656374311f301d060355040b1316477561726469616e20462d44726f6964204275696c64311d301b06035504031314677561726469616e70726f6a6563742e696e666f30820122300d06092a864886f70d01010105000382010f003082010a0282010100b7f1f635fa3fce1a8042aaa960c2dc557e4ad2c082e5787488cba587fd26207cf59507919fc4dcebda5c8c0959d14146d0445593aa6c29dc639570b71712451fd5c231b0c9f5f0bec380503a1c2a3bc00048bc5db682915afa54d1ecf67b45e1e05c0934b3037a33d3a565899131f27a72c03a5de93df17a2376cc3107f03ee9d124c474dfab30d4053e8f39f292e2dcb6cc131bce12a0c5fc307985195d256bf1d7a2703d67c14bf18ed6b772bb847370b20335810e337c064fef7e2795a524c664a853cd46accb8494f865164dabfb698fa8318236432758bc40d52db00d5ce07fe2210dc06cd95298b4f09e6c9b7b7af61c1d62ea43ea36a2331e7b2d4e250203010001a321301f301d0603551d0e0416041404d763e981cf3a295b94a790d8536a783097232b300d06092a864886f70d01010b05000382010100654e6484ff032c54fed1d96d3c8e731302be9dbd7bb4fe635f2dac05b69f3ecbb5acb7c9fe405e2a066567a8f5c2beb8b199b5a4d5bb1b435cf02df026d4fb4edd9d8849078f085b00950083052d57467d65c6eebd98f037cff9b148d621cf8819c4f7dc1459bf8fc5c7d76f901495a7caf35d1e5c106e1d50610c4920c3c1b50adcfbd4ad83ce7353cdea7d856bba0419c224f89a2f3ebc203d20eb6247711ad2b55fd4737936dc42ced7a047cbbd24012079204a2883b6d55d5d5b66d9fd82fb51fca9a5db5fad9af8564cb380ff30ae8263dbbf01b46e01313f53279673daa3f893380285646b244359203e7eecde94ae141b7dfa8e6499bb8e7e0b25ab85"; + @Test public void testFormatFingerprint() { - String badResult = Utils.formatFingerprint(getContext(), ""); + Context context = InstrumentationRegistry.getTargetContext(); + String badResult = Utils.formatFingerprint(context, ""); // real fingerprints String formatted; - formatted = Utils.formatFingerprint(getContext(), fdroidFingerprint); + formatted = Utils.formatFingerprint(context, fdroidFingerprint); assertFalse(formatted.equals(badResult)); assertTrue(formatted.matches("[A-Z0-9][A-Z0-9] [A-Z0-9 ]+")); - formatted = Utils.formatFingerprint(getContext(), gpRepoFingerprint); + formatted = Utils.formatFingerprint(context, gpRepoFingerprint); assertFalse(formatted.equals(badResult)); assertTrue(formatted.matches("[A-Z0-9][A-Z0-9] [A-Z0-9 ]+")); - formatted = Utils.formatFingerprint(getContext(), gpTest1Fingerprint); + formatted = Utils.formatFingerprint(context, gpTest1Fingerprint); assertFalse(formatted.equals(badResult)); assertTrue(formatted.matches("[A-Z0-9][A-Z0-9] [A-Z0-9 ]+")); // random garbage assertEquals( badResult, - Utils.formatFingerprint(getContext(), "234k2lk3jljwlk4j2lk3jlkmqwekljrlkj34lk2jlk2j34lkjl2k3j4lk2j34lja")); + Utils.formatFingerprint(context, "234k2lk3jljwlk4j2lk3jlkmqwekljrlkj34lk2jlk2j34lkjl2k3j4lk2j34lja")); assertEquals( badResult, - Utils.formatFingerprint(getContext(), "g000000000000000000000000000000000000000000000000000000000000000")); + Utils.formatFingerprint(context, "g000000000000000000000000000000000000000000000000000000000000000")); assertEquals( badResult, - Utils.formatFingerprint(getContext(), "98273498723948728934789237489273p1928731982731982739182739817238")); + Utils.formatFingerprint(context, "98273498723948728934789237489273p1928731982731982739182739817238")); // too short assertEquals( badResult, - Utils.formatFingerprint(getContext(), "C63AED1AC79D37C7B0474472AC6EFA6C3AB2B11A767A4F42CF360FA5496E3C5")); + Utils.formatFingerprint(context, "C63AED1AC79D37C7B0474472AC6EFA6C3AB2B11A767A4F42CF360FA5496E3C5")); assertEquals( badResult, - Utils.formatFingerprint(getContext(), "C63AED1")); + Utils.formatFingerprint(context, "C63AED1")); assertEquals( badResult, - Utils.formatFingerprint(getContext(), "f")); + Utils.formatFingerprint(context, "f")); assertEquals( badResult, - Utils.formatFingerprint(getContext(), "")); + Utils.formatFingerprint(context, "")); assertEquals( badResult, - Utils.formatFingerprint(getContext(), null)); + Utils.formatFingerprint(context, null)); // real digits but too long assertEquals( badResult, - Utils.formatFingerprint(getContext(), "43238D512C1E5EB2D6569F4A3AFBF5523418B82E0A3ED1552770ABB9A9C9CCAB43238D512C1E5EB2D6569F4A3AFBF5523418B82E0A3ED1552770ABB9A9C9CCAB")); + Utils.formatFingerprint(context, "43238D512C1E5EB2D6569F4A3AFBF5523418B82E0A3ED1552770ABB9A9C9CCAB43238D512C1E5EB2D6569F4A3AFBF5523418B82E0A3ED1552770ABB9A9C9CCAB")); assertEquals( badResult, - Utils.formatFingerprint(getContext(), "C63AED1AC79D37C7B0474472AC6EFA6C3AB2B11A767A4F42CF360FA5496E3C50F")); + Utils.formatFingerprint(context, "C63AED1AC79D37C7B0474472AC6EFA6C3AB2B11A767A4F42CF360FA5496E3C50F")); assertEquals( badResult, - Utils.formatFingerprint(getContext(), "3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef")); + Utils.formatFingerprint(context, "3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef")); } + @Test public void testCalcFingerprintString() { // these should pass assertEquals(fdroidFingerprint, Utils.calcFingerprint(fdroidPubkey)); @@ -124,7 +136,5 @@ public class UtilsTest extends AndroidTestCase { } } - public void testCalcFingerprintCertificate() { - // TODO write tests that work with a Certificate - } + // TODO write tests that work with a Certificate } diff --git a/app/src/main/java/org/fdroid/fdroid/AppDetails.java b/app/src/main/java/org/fdroid/fdroid/AppDetails.java index 5cda16ec3..26668808c 100644 --- a/app/src/main/java/org/fdroid/fdroid/AppDetails.java +++ b/app/src/main/java/org/fdroid/fdroid/AppDetails.java @@ -247,7 +247,7 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A if (!Preferences.get().expertMode()) { holder.api.setVisibility(View.GONE); - } else if (apk.minSdkVersion > 0 && apk.maxSdkVersion > 0) { + } else if (apk.minSdkVersion > 0 && apk.maxSdkVersion < Apk.SDK_VERSION_MAX_VALUE) { holder.api.setText(getString(R.string.minsdk_up_to_maxsdk, Utils.getAndroidVersionName(apk.minSdkVersion), Utils.getAndroidVersionName(apk.maxSdkVersion))); diff --git a/app/src/main/java/org/fdroid/fdroid/FDroidApp.java b/app/src/main/java/org/fdroid/fdroid/FDroidApp.java index df06334e8..57862494b 100644 --- a/app/src/main/java/org/fdroid/fdroid/FDroidApp.java +++ b/app/src/main/java/org/fdroid/fdroid/FDroidApp.java @@ -49,6 +49,7 @@ import org.acra.ReportingInteractionMode; import org.acra.annotation.ReportsCrashes; import org.apache.commons.net.util.SubnetUtils; import org.fdroid.fdroid.Preferences.ChangeListener; +import org.fdroid.fdroid.Preferences.Theme; import org.fdroid.fdroid.compat.PRNGFixes; import org.fdroid.fdroid.data.AppProvider; import org.fdroid.fdroid.data.InstalledAppCacheUpdater; @@ -96,19 +97,10 @@ public class FDroidApp extends Application { enableSpongyCastle(); } - public enum Theme { - light, - dark, - night, - lightWithDarkActionBar, // Obsolete - } - private static Theme curTheme = Theme.light; public void reloadTheme() { - curTheme = Theme.valueOf(PreferenceManager - .getDefaultSharedPreferences(getBaseContext()) - .getString(Preferences.PREF_THEME, Preferences.DEFAULT_THEME)); + curTheme = Preferences.get().getTheme(); } public void applyTheme(Activity activity) { @@ -194,6 +186,7 @@ public class FDroidApp extends Application { // Perhaps the constructor is a better place, but then again, // it is more deterministic as to when this gets called... Preferences.setup(this); + curTheme = Preferences.get().getTheme(); // Apply the Google PRNG fixes to properly seed SecureRandom PRNGFixes.apply(); @@ -241,9 +234,6 @@ public class FDroidApp extends Application { // been installed, but this causes problems for proprietary gapps // users since the introduction of verification (on pre-4.2 Android), // because the install intent says it's finished when it hasn't. - SharedPreferences prefs = PreferenceManager - .getDefaultSharedPreferences(getBaseContext()); - curTheme = Theme.valueOf(prefs.getString(Preferences.PREF_THEME, Preferences.DEFAULT_THEME)); Utils.deleteFiles(Utils.getApkDownloadDir(this), null, ".apk"); if (!Preferences.get().shouldCacheApks()) { Utils.deleteFiles(Utils.getApkCacheDir(this), null, ".apk"); diff --git a/app/src/main/java/org/fdroid/fdroid/Preferences.java b/app/src/main/java/org/fdroid/fdroid/Preferences.java index 17fd38081..99670579f 100644 --- a/app/src/main/java/org/fdroid/fdroid/Preferences.java +++ b/app/src/main/java/org/fdroid/fdroid/Preferences.java @@ -85,6 +85,13 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh private static final boolean DEFAULT_FIRST_TIME = true; private static final boolean DEFAULT_POST_PRIVILEGED_INSTALL = false; + public enum Theme { + light, + dark, + night, + lightWithDarkActionBar, // Obsolete + } + private boolean filterAppsRequiringRoot = DEFAULT_ROOTED; private final Map initialized = new HashMap<>(); @@ -155,6 +162,10 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh return preferences.getBoolean(PREF_EXPERT, DEFAULT_EXPERT); } + public Theme getTheme() { + return Theme.valueOf(preferences.getString(Preferences.PREF_THEME, Preferences.DEFAULT_THEME)); + } + public boolean isLocalRepoHttpsEnabled() { return false; // disabled until it works well } diff --git a/app/src/main/java/org/fdroid/fdroid/UpdateService.java b/app/src/main/java/org/fdroid/fdroid/UpdateService.java index f95dae114..8f045744b 100644 --- a/app/src/main/java/org/fdroid/fdroid/UpdateService.java +++ b/app/src/main/java/org/fdroid/fdroid/UpdateService.java @@ -31,6 +31,7 @@ import android.database.Cursor; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Build; +import android.os.Process; import android.os.SystemClock; import android.preference.PreferenceManager; import android.support.v4.app.NotificationCompat; @@ -338,6 +339,7 @@ public class UpdateService extends IntentService implements ProgressListener { @Override protected void onHandleIntent(Intent intent) { + Process.setThreadPriority(Process.THREAD_PRIORITY_LOWEST); final long startTime = System.currentTimeMillis(); String address = intent.getStringExtra(EXTRA_ADDRESS); diff --git a/app/src/main/java/org/fdroid/fdroid/data/Apk.java b/app/src/main/java/org/fdroid/fdroid/data/Apk.java index 09f694bf0..1e7dc633f 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/Apk.java +++ b/app/src/main/java/org/fdroid/fdroid/data/Apk.java @@ -11,6 +11,9 @@ import java.util.Date; public class Apk extends ValueObject implements Comparable { + // Using only byte-range keeps it only 8-bits in the SQLite database + public static final int SDK_VERSION_MAX_VALUE = Byte.MAX_VALUE; + public String packageName; public String version; public int vercode; @@ -19,7 +22,7 @@ public class Apk extends ValueObject implements Comparable { public String hash; public String hashType; public int minSdkVersion; // 0 if unknown - public int maxSdkVersion = Byte.MAX_VALUE; // "infinity" if not set + public int maxSdkVersion = SDK_VERSION_MAX_VALUE; // "infinity" if not set public Date added; public Utils.CommaSeparatedList permissions; // null if empty or // unknown diff --git a/app/src/main/java/org/fdroid/fdroid/net/HttpDownloader.java b/app/src/main/java/org/fdroid/fdroid/net/HttpDownloader.java index f9d7ece2b..20dc237f2 100644 --- a/app/src/main/java/org/fdroid/fdroid/net/HttpDownloader.java +++ b/app/src/main/java/org/fdroid/fdroid/net/HttpDownloader.java @@ -1,7 +1,5 @@ package org.fdroid.fdroid.net; -import android.util.Log; - import com.nostra13.universalimageloader.core.download.BaseImageDownloader; import org.fdroid.fdroid.FDroidApp; @@ -18,7 +16,6 @@ import java.net.MalformedURLException; import java.net.URL; import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLHandshakeException; import info.guardianproject.netcipher.NetCipher; @@ -72,25 +69,18 @@ public class HttpDownloader extends Downloader { return new BufferedInputStream(connection.getInputStream()); } - // Get a remote file. Returns the HTTP response code. - // If 'etag' is not null, it's passed to the server as an If-None-Match - // header, in which case expect a 304 response if nothing changed. - // In the event of a 200 response ONLY, 'retag' (which should be passed - // empty) may contain an etag value for the response, or it may be left - // empty if none was available. + /** + * Get a remote file, checking the HTTP response code. If 'etag' is not + * {@code null}, it's passed to the server as an If-None-Match header, in + * which case expect a 304 response if nothing changed. In the event of a + * 200 response ONLY, 'retag' (which should be passed empty) may contain + * an etag value for the response, or it may be left empty if none was + * available. + */ @Override public void download() throws IOException, InterruptedException { - try { - setupConnection(); - doDownload(); - } catch (SSLHandshakeException e) { - // TODO this should be handled better, it is not internationalised here - throw new IOException( - "A problem occurred while establishing an SSL " + - "connection. If this problem persists, AND you have a " + - "very old device, you could try using http instead of " + - "https for the repo URL." + Log.getStackTraceString(e)); - } + setupConnection(); + doDownload(); } private boolean isSwapUrl() { diff --git a/app/src/test/java/org/fdroid/fdroid/net/HttpDownloaderTest.java b/app/src/test/java/org/fdroid/fdroid/net/HttpDownloaderTest.java index 7075e3260..9d92fa74e 100644 --- a/app/src/test/java/org/fdroid/fdroid/net/HttpDownloaderTest.java +++ b/app/src/test/java/org/fdroid/fdroid/net/HttpDownloaderTest.java @@ -32,11 +32,11 @@ public class HttpDownloaderTest { for (String urlString : urls) { URL url = new URL(urlString); File destFile = File.createTempFile("dl-", ""); - destFile.deleteOnExit(); // this probably does nothing, but maybe... HttpDownloader httpDownloader = new HttpDownloader(url, destFile); httpDownloader.download(); assertTrue(destFile.exists()); assertTrue(destFile.canRead()); + destFile.deleteOnExit(); } } @@ -46,7 +46,6 @@ public class HttpDownloaderTest { receivedProgress = false; URL url = new URL(urlString); File destFile = File.createTempFile("dl-", ""); - destFile.deleteOnExit(); // this probably does nothing, but maybe... HttpDownloader httpDownloader = new HttpDownloader(url, destFile); httpDownloader.setListener(new Downloader.DownloaderProgressListener() { @Override @@ -58,6 +57,7 @@ public class HttpDownloaderTest { assertTrue(destFile.exists()); assertTrue(destFile.canRead()); assertTrue(receivedProgress); + destFile.deleteOnExit(); } } @@ -65,39 +65,38 @@ public class HttpDownloaderTest { public void downloadHttpBasicAuth() throws IOException, InterruptedException { URL url = new URL("https://httpbin.org/basic-auth/myusername/supersecretpassword"); File destFile = File.createTempFile("dl-", ""); - destFile.deleteOnExit(); // this probably does nothing, but maybe... HttpDownloader httpDownloader = new HttpDownloader(url, destFile, "myusername", "supersecretpassword"); httpDownloader.download(); assertTrue(destFile.exists()); assertTrue(destFile.canRead()); + destFile.deleteOnExit(); } @Test(expected = IOException.class) public void downloadHttpBasicAuthWrongPassword() throws IOException, InterruptedException { URL url = new URL("https://httpbin.org/basic-auth/myusername/supersecretpassword"); File destFile = File.createTempFile("dl-", ""); - destFile.deleteOnExit(); // this probably does nothing, but maybe... HttpDownloader httpDownloader = new HttpDownloader(url, destFile, "myusername", "wrongpassword"); httpDownloader.download(); assertFalse(destFile.exists()); + destFile.deleteOnExit(); } @Test(expected = IOException.class) public void downloadHttpBasicAuthWrongUsername() throws IOException, InterruptedException { URL url = new URL("https://httpbin.org/basic-auth/myusername/supersecretpassword"); File destFile = File.createTempFile("dl-", ""); - destFile.deleteOnExit(); // this probably does nothing, but maybe... HttpDownloader httpDownloader = new HttpDownloader(url, destFile, "wrongusername", "supersecretpassword"); httpDownloader.download(); assertFalse(destFile.exists()); + destFile.deleteOnExit(); } @Test public void downloadThenCancel() throws IOException, InterruptedException { - final CountDownLatch latch = new CountDownLatch(5); + final CountDownLatch latch = new CountDownLatch(2); URL url = new URL("https://f-droid.org/repo/index.jar"); File destFile = File.createTempFile("dl-", ""); - destFile.deleteOnExit(); // this probably does nothing, but maybe... final HttpDownloader httpDownloader = new HttpDownloader(url, destFile); httpDownloader.setListener(new Downloader.DownloaderProgressListener() { @Override @@ -121,8 +120,9 @@ public class HttpDownloaderTest { } } }.start(); - latch.await(100, TimeUnit.SECONDS); // either 5 progress reports or 100 seconds + latch.await(100, TimeUnit.SECONDS); // either 2 progress reports or 100 seconds httpDownloader.cancelDownload(); assertTrue(receivedProgress); + destFile.deleteOnExit(); } }