diff --git a/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java b/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java
index 7d7f74158..9eaad2d44 100644
--- a/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java
+++ b/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java
@@ -42,8 +42,17 @@ import org.fdroid.fdroid.data.Schema.CatJoinTable;
 import org.fdroid.fdroid.data.Schema.InstalledAppTable;
 import org.fdroid.fdroid.data.Schema.PackageTable;
 import org.fdroid.fdroid.data.Schema.RepoTable;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
 import java.util.List;
 
 /**
@@ -56,8 +65,7 @@ import java.util.List;
 public class DBHelper extends SQLiteOpenHelper {
 
     private static final String TAG = "DBHelper";
-
-    public static final int REPO_XML_ARG_COUNT = 8;
+    public static final int REPO_XML_ITEM_COUNT = 8;
 
     private static DBHelper instance;
     private static final String DATABASE_NAME = "fdroid";
@@ -257,27 +265,135 @@ public class DBHelper extends SQLiteOpenHelper {
         db.execSQL(CREATE_TABLE_APK_ANTI_FEATURE_JOIN);
         ensureIndexes(db);
 
-        String[] defaultRepos = context.getResources().getStringArray(R.array.default_repos);
-        if (defaultRepos.length % REPO_XML_ARG_COUNT != 0) {
-            throw new IllegalArgumentException(
-                    "default_repo.xml array does not have the right number of elements");
-        }
-        for (int i = 0; i < defaultRepos.length / REPO_XML_ARG_COUNT; i++) {
-            int offset = i * REPO_XML_ARG_COUNT;
+        List<String> initialRepos = DBHelper.loadInitialRepos(context);
+
+        for (int i = 0; i < initialRepos.size(); i += REPO_XML_ITEM_COUNT) {
             insertRepo(
                     db,
-                    defaultRepos[offset],     // name
-                    defaultRepos[offset + 1], // address
-                    defaultRepos[offset + 2], // description
-                    defaultRepos[offset + 3], // version
-                    defaultRepos[offset + 4], // enabled
-                    defaultRepos[offset + 5], // priority
-                    defaultRepos[offset + 6], // pushRequests
-                    defaultRepos[offset + 7]  // pubkey
+                    initialRepos.get(i),     // name
+                    initialRepos.get(i + 1), // address
+                    initialRepos.get(i + 2), // description
+                    initialRepos.get(i + 3), // version
+                    initialRepos.get(i + 4), // enabled
+                    initialRepos.get(i + 5), // priority
+                    initialRepos.get(i + 6), // pushRequests
+                    initialRepos.get(i + 7)  // pubkey
             );
         }
     }
 
+    /**
+     * Load Additional Repos first, then Default Repos. This way, Default
+     * Repos will be shown after the OEM-added ones on the Manage Repos
+     * screen.  This throws a hard {@code Exception} on parse errors since
+     * Default Repos are built into the APK.  So it should fail as hard and fast
+     * as possible so the developer catches the problem.
+     * <p>
+     * Additional Repos ({@code additional_repos.xml}) come from the ROM,
+     * while Default Repos ({@code default_repos.xml} is built into the APK.
+     * <p>
+     * This also cleans up the whitespace in the description item, since the
+     * XML parsing will include the linefeeds and indenting in the description.
+     */
+    public static List<String> loadInitialRepos(Context context) throws IllegalArgumentException {
+        String packageName = context.getPackageName();
+        List<String> initialRepos = DBHelper.loadAdditionalRepos(packageName);
+        List<String> defaultRepos = Arrays.asList(context.getResources().getStringArray(R.array.default_repos));
+        initialRepos.addAll(defaultRepos);
+
+        if (initialRepos.size() % REPO_XML_ITEM_COUNT != 0) {
+            throw new IllegalArgumentException("default_repos.xml has wrong item count: " +
+                    initialRepos.size() + " % REPO_XML_ARG_COUNT(" + REPO_XML_ITEM_COUNT + ") != 0");
+        }
+
+        final int descriptionIndex = 2;
+        for (int i = descriptionIndex; i < initialRepos.size(); i += REPO_XML_ITEM_COUNT) {
+            String description = initialRepos.get(i);
+            initialRepos.set(i, description.replaceAll("\\s+", " "));
+        }
+
+        return initialRepos;
+    }
+
+    /**
+     * Look for additional, initial repositories from the device's filesystem.
+     * These can be added as part of the ROM ({@code /system} or included later
+     * by vendors/OEMs ({@code /vendor}, {@code /odm}, {@code /oem}). These are
+     * always added at a lower priority than the repos embedded in the APK via
+     * {@code default_repos.xml}.
+     * <p>
+     * ROM has the lowest priority, then Vendor, ODM, and OEM.
+     */
+    private static List<String> loadAdditionalRepos(String packageName) {
+        List<String> repoItems = new LinkedList<>();
+        for (String root : Arrays.asList("/system", "/vendor", "/odm", "/oem")) {
+            File additionalReposFile = new File(root + "/etc/" + packageName + "/additional_repos.xml");
+            try {
+                if (additionalReposFile.isFile()) {
+                    repoItems.addAll(DBHelper.parseAdditionalReposXml(additionalReposFile));
+                }
+            } catch (Exception e) {
+                Log.e(TAG, "Error loading " + additionalReposFile + ": " + e.getMessage());
+            }
+        }
+
+        return repoItems;
+    }
+
+    /**
+     * Parse {@code additional_repos.xml} into a list of items. Walk through
+     * all TEXT pieces of the xml file and put them into a single list of repo
+     * elements.  Each repo is defined as eight elements in that list.
+     * {@code additional_repos.xml} has seven elements per repo because it is
+     * not allowed to set the priority since that would give it the power to
+     * override {@code default_repos.xml}.
+     */
+    public static List<String> parseAdditionalReposXml(File additionalReposFile)
+            throws IOException, XmlPullParserException {
+        List<String> repoItems = new LinkedList<>();
+        InputStream xmlInputStream = new FileInputStream(additionalReposFile);
+        XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+        factory.setNamespaceAware(true);
+        XmlPullParser parser = factory.newPullParser();
+        parser.setInput(xmlInputStream, "UTF-8");
+
+        int eventType = parser.getEventType();
+        boolean isItem = false;
+        while (eventType != XmlPullParser.END_DOCUMENT) {
+            String tagname = parser.getName();
+            switch (eventType) {
+                case XmlPullParser.START_TAG:
+                    if ("item".equals(tagname)) {
+                        isItem = true;
+                    }
+                    break;
+                case XmlPullParser.END_TAG:
+                    isItem = false;
+                    break;
+                case XmlPullParser.TEXT:
+                    if (isItem) {
+                        repoItems.add(parser.getText());
+                    }
+                    break;
+            }
+            eventType = parser.next();
+        }
+        xmlInputStream.close();
+
+        final int priorityIndex = 5;
+        for (int i = priorityIndex; i < repoItems.size(); i += REPO_XML_ITEM_COUNT) {
+            repoItems.add(i, "0");
+        }
+
+        if (repoItems.size() % REPO_XML_ITEM_COUNT == 0) {
+            return repoItems;
+        }
+
+        Log.e(TAG, "Ignoring " + additionalReposFile + ", wrong number of items: "
+                + repoItems.size() + " % " + (REPO_XML_ITEM_COUNT - 1) + " != 0");
+        return new LinkedList<>();
+    }
+
     @Override
     public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
         resetTransient(context);
@@ -600,10 +716,10 @@ public class DBHelper extends SQLiteOpenHelper {
         String[] defaultRepos = context.getResources().getStringArray(R.array.default_repos);
         String fdroidPubKey = defaultRepos[7];
         String fdroidAddress = defaultRepos[1];
-        String fdroidArchiveAddress = defaultRepos[REPO_XML_ARG_COUNT + 1];
-        String gpPubKey = defaultRepos[REPO_XML_ARG_COUNT * 2 + 7];
-        String gpAddress = defaultRepos[REPO_XML_ARG_COUNT * 2 + 1];
-        String gpArchiveAddress = defaultRepos[REPO_XML_ARG_COUNT * 3 + 1];
+        String fdroidArchiveAddress = defaultRepos[REPO_XML_ITEM_COUNT + 1];
+        String gpPubKey = defaultRepos[REPO_XML_ITEM_COUNT * 2 + 7];
+        String gpAddress = defaultRepos[REPO_XML_ITEM_COUNT * 2 + 1];
+        String gpArchiveAddress = defaultRepos[REPO_XML_ITEM_COUNT * 3 + 1];
 
         updateRepoPriority(db, fdroidPubKey, fdroidAddress, 1);
         updateRepoPriority(db, fdroidPubKey, fdroidArchiveAddress, 2);
@@ -854,8 +970,8 @@ public class DBHelper extends SQLiteOpenHelper {
         }
 
         String[] defaultRepos = context.getResources().getStringArray(R.array.default_repos);
-        for (int i = 0; i < defaultRepos.length / REPO_XML_ARG_COUNT; i++) {
-            int offset = i * REPO_XML_ARG_COUNT;
+        for (int i = 0; i < defaultRepos.length / REPO_XML_ITEM_COUNT; i++) {
+            int offset = i * REPO_XML_ITEM_COUNT;
             insertNameAndDescription(db,
                     defaultRepos[offset],     // name
                     defaultRepos[offset + 1], // address
diff --git a/app/src/test/java/org/fdroid/fdroid/data/DBHelperTest.java b/app/src/test/java/org/fdroid/fdroid/data/DBHelperTest.java
new file mode 100644
index 000000000..2159a709b
--- /dev/null
+++ b/app/src/test/java/org/fdroid/fdroid/data/DBHelperTest.java
@@ -0,0 +1,314 @@
+package org.fdroid.fdroid.data;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.text.TextUtils;
+import android.util.Log;
+import org.apache.commons.io.IOUtils;
+import org.fdroid.fdroid.TestUtils;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+@RunWith(RobolectricTestRunner.class)
+public class DBHelperTest {
+    static final String TAG = "DBHelperTest";
+
+    private List<String> getReposFromXml(String xml) throws IOException, XmlPullParserException {
+        File additionalReposXml = File.createTempFile("." + context.getPackageName() + "-DBHelperTest_",
+                "_additional_repos.xml");
+        Log.i(TAG, "additionalReposXml: " + additionalReposXml);
+
+        FileOutputStream outputStream = new FileOutputStream(additionalReposXml);
+        outputStream.write(xml.getBytes());
+        outputStream.close();
+
+        // Now parse that xml file
+        return DBHelper.parseAdditionalReposXml(additionalReposXml);
+    }
+
+    protected Context context;
+
+    @Before
+    public final void setupBase() {
+        context = InstrumentationRegistry.getContext();
+    }
+
+    @Test
+    public void parseAdditionalReposXmlAllOneLineTest() throws IOException, XmlPullParserException {
+        String oneRepoXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
+                "<resources>" +
+                "<string-array name=\"default_repos\">\n" +
+                "<!-- name -->" +
+                "<item>F-Droid</item>" +
+                "<!-- address -->" +
+                "<item>https://f-droid.org/repo</item>" +
+                "<!-- description -->" +
+                "<item>The official F-Droid repository. Applications in this repository are mostly built" +
+                "directory from the source code. Some are official binaries built by the original" +
+                "application developers - these will be replaced by source-built versions over time." +
+                "</item>" +
+                "<!-- version -->" +
+                "<item>13</item>" +
+                "<!-- enabled -->" +
+                "<item>1</item>" +
+                "<!-- push requests -->" +
+                "<item>ignore</item>" +
+                "<!-- pubkey -->" +
+                "<item>" +
+                "3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b30090603550406130255" +
+                "</item>" +
+                "</string-array>" +
+                "</resources>";
+        List<String> repos = getReposFromXml(oneRepoXml);
+        assertEquals("Should contain one repo's worth of items", DBHelper.REPO_XML_ITEM_COUNT, repos.size());
+    }
+
+    @Test
+    public void parseAdditionalReposXmlIncludedPriorityTest() throws IOException, XmlPullParserException {
+        String wrongXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
+                "<resources>" +
+                "<string-array name=\"default_repos\">\n" +
+                "<!-- name -->" +
+                "<item>F-Droid</item>" +
+                "<!-- address -->" +
+                "<item>https://f-droid.org/repo</item>" +
+                "<!-- description -->" +
+                "<item>The official F-Droid repository. Applications in this repository are mostly built" +
+                "directory from the source code. Some are official binaries built by the original" +
+                "application developers - these will be replaced by source-built versions over time." +
+                "</item>" +
+                "<!-- version -->" +
+                "<item>13</item>" +
+                "<!-- enabled -->" +
+                "<item>1</item>" +
+                "<!-- priority -->" +
+                "<item>1</item>" +
+                "<!-- push requests -->" +
+                "<item>ignore</item>" +
+                "<!-- pubkey -->" +
+                "<item>" +
+                "3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b3009060355040613025" +
+                "</item>" +
+                "</string-array>" +
+                "</resources>";
+        getReposFromXml(wrongXml);
+        List<String> repos = getReposFromXml(wrongXml);
+        assertEquals("Should be empty", 0, repos.size());
+    }
+
+    @Test(expected = XmlPullParserException.class)
+    public void parseAdditionalReposXmlDoubleTagTest() throws IOException, XmlPullParserException {
+        String wrongXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+                + "<resources>"
+                + "<string-array name=\"additional_repos\">"
+                + "<!-- address -->"
+                + "<item><item>https://www.oem0.com/yeah/repo</item>"
+                + "<!-- description -->"
+                + "<item>I'm the first oem repo.</item>"
+                + "<!-- version -->"
+                + "<item>22</item>"
+                + "<!-- enabled -->"
+                + "<item>1</item>"
+                + "<!-- push requests -->"
+                + "<item>ignore</item>"
+                + "<!-- pubkey -->"
+                + "<item>fffff2313aaaaabcccc111</item>"
+                + "</string-array>"
+                + "</resources>";
+        getReposFromXml(wrongXml);
+        fail("Invalid xml read successfully --> Wrong");
+    }
+
+    @Test(expected = XmlPullParserException.class)
+    public void parseAdditionalReposXmlMissingStartTagTest() throws IOException, XmlPullParserException {
+        String wrongXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+                + "<item>https://www.oem0.com/yeah/repo</item>"
+                + "<!-- description -->"
+                + "<item>I'm the first oem repo.</item>"
+                + "<!-- version -->"
+                + "<item>22</item>"
+                + "<!-- enabled -->"
+                + "<item>1</item>"
+                + "<!-- push requests -->"
+                + "<item>ignore</item>"
+                + "<!-- pubkey -->"
+                + "<item>fffff2313aaaaabcccc111</item>"
+                + "</string-array>"
+                + "</resources>";
+        getReposFromXml(wrongXml);
+        fail("Invalid xml read successfully --> Wrong");
+    }
+
+    @Test
+    public void parseAdditionalReposXmlWrongCountTest() throws IOException, XmlPullParserException {
+        String wrongXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+                + "<resources>"
+                + "<string-array name=\"default_repos\"><item>foo</item></string-array>"
+                + "</resources>";
+        List<String> repos = getReposFromXml(wrongXml);
+        assertEquals("Should be empty", 0, repos.size());
+    }
+
+    /**
+     * Parse valid xml but make sure that only <item> tags are parsed
+     */
+    @Test
+    public void parseAdditionalReposXmlSloppyTest() throws IOException, XmlPullParserException {
+        InputStream input = TestUtils.class.getClassLoader().getResourceAsStream("ugly_additional_repos.xml");
+        String validXml = IOUtils.toString(input, "UTF-8");
+
+        List<String> repos = getReposFromXml(validXml);
+        assertEquals(2 * DBHelper.REPO_XML_ITEM_COUNT, repos.size());
+        assertEquals("Repo Name", repos.get(8));
+        assertEquals("https://www.oem0.com/yeah/repo", repos.get(9));
+    }
+
+    @Test
+    public void parseAdditionalReposXmlPositiveTest() throws IOException {
+        InputStream input = TestUtils.class.getClassLoader().getResourceAsStream("additional_repos.xml");
+        String reposXmlContent = IOUtils.toString(input, "UTF-8");
+
+        List<String> additionalRepos;
+        try {
+            additionalRepos = getReposFromXml(reposXmlContent);
+        } catch (IOException io) {
+            fail("IOException. Failed parsing xml string into repos.");
+            return;
+        } catch (XmlPullParserException xppe) {
+            fail("XmlPullParserException. Failed parsing xml string into repos.");
+            return;
+        }
+
+        // We should have loaded these repos
+        List<String> oem0 = Arrays.asList(
+                "oem0Name",
+                "https://www.oem0.com/yeah/repo",
+                "I'm the first oem repo.",
+                "22",
+                "1",
+                "0",  // priority is inserted by DBHelper.parseAdditionalReposXml()
+                "ignore",
+                "fffff2313aaaaabcccc111");
+        List<String> oem1 = Arrays.asList(
+                "oem1MyNameIs",
+                "https://www.mynameis.com/rapper/repo",
+                "Who is the first repo?",
+                "22",
+                "0",
+                "0",  // priority is inserted by DBHelper.parseAdditionalReposXml()
+                "ignore",
+                "ddddddd2313aaaaabcccc111");
+        List<String> shouldBeRepos = new LinkedList<>();
+        shouldBeRepos.addAll(oem0);
+        shouldBeRepos.addAll(oem1);
+
+        assertEquals(additionalRepos.size(), shouldBeRepos.size());
+        for (int i = 0; i < additionalRepos.size(); i++) {
+            assertEquals(shouldBeRepos.get(i), additionalRepos.get(i));
+        }
+    }
+
+    @SuppressWarnings("LineLength")
+    @Test
+    public void canAddAdditionalRepos() throws IOException {
+        File oemEtcDir = new File("/oem/etc");
+        File oemEtcPackageDir = new File(oemEtcDir, context.getPackageName());
+        if (!oemEtcPackageDir.canWrite() || !oemEtcDir.canWrite()) {
+            if (oemEtcDir.canWrite() || new File("/").canWrite()) {
+                oemEtcPackageDir.mkdirs();
+            }
+            if (TextUtils.isEmpty(System.getenv("CI")) && !oemEtcPackageDir.isDirectory()) {
+                Log.e(TAG, "Cannot create " + oemEtcDir + ", skipping test!");
+                return;
+            }
+        }
+
+        File additionalReposXmlFile = new File(oemEtcPackageDir, "additional_repos.xml");
+        FileOutputStream outputStream = new FileOutputStream(additionalReposXmlFile);
+        outputStream.write(("<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+                + "<resources>"
+                + "<string-array name=\"default_repos\">"
+                + "<!-- name -->"
+                + "<item>oem0Name</item>"
+                + "<!-- address -->"
+                + "<item>https://www.oem0.com/yeah/repo</item>"
+                + "<!-- description -->"
+                + "<item>I'm the first oem repo.</item>"
+                + "<!-- version -->"
+                + "<item>22</item>"
+                + "<!-- enabled -->"
+                + "<item>1</item>"
+                + "<!-- push requests -->"
+                + "<item>ignore</item>"
+                + "<!-- pubkey -->"
+                + "<item>fffff2313aaaaabcccc111</item>"
+
+                + "<!-- name -->"
+                + "<item>oem1MyNameIs</item>"
+                + "<!-- address -->"
+                + "<item>https://www.mynameis.com/rapper/repo</item>"
+                + "<!-- description -->"
+                + "<item>Who is the first repo?</item>"
+                + "<!-- version -->"
+                + "<item>22</item>"
+                + "<!-- enabled -->"
+                + "<item>0</item>"
+                + "<!-- push requests -->"
+                + "<item>ignore</item>"
+                + "<!-- pubkey -->"
+                + "<item>ddddddd2313aaaaabcccc111</item>"
+                + "</string-array>"
+                + "</resources>").getBytes());
+        outputStream.close();
+
+        try {
+            List<String> initialRepos = DBHelper.loadInitialRepos(context);
+
+            // Construct the repos that we should have loaded
+            List<String> oem0 = Arrays.asList("oem0Name", "https://www.oem0.com/yeah/repo", "I'm the first oem repo.",
+                    "22", "1", "0", "ignore", "fffff2313aaaaabcccc111");
+            List<String> oem1 = Arrays.asList("oem1MyNameIs", "https://www.mynameis.com/rapper/repo", "Who is the first repo?",
+                    "22", "0", "0", "ignore", "ddddddd2313aaaaabcccc111");
+            List<String> fdroid0 = Arrays.asList("F-Droid", "https://f-droid.org/repo", "The official F-Droid repository. Applications in this repository are mostly built directory from the source code. Some are official binaries built by the original application developers - these will be replaced by source-built versions over time.",
+                    "13", "1", "1", "ignore", "3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef");
+            List<String> fdroid1 = Arrays.asList("F-Droid Archive", "https://f-droid.org/archive", "The archive repository of the F-Droid client. This contains older versions of applications from the main repository.",
+                    "13", "0", "2", "ignore", "3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef");
+            List<String> fdroid2 = Arrays.asList("Guardian Project", "https://guardianproject.info/fdroid/repo", "The official app repository of The Guardian Project. Applications in this repository are official binaries build by the original application developers and signed by the same key as the APKs that are released in the Google Play store.",
+                    "13", "0", "3", "ignore", "308205d8308203c0020900a397b4da7ecda034300d06092a864886f70d01010505003081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f301e170d3134303632363139333931385a170d3431313131303139333931385a3081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f30820222300d06092a864886f70d01010105000382020f003082020a0282020100b3cd79121b9b883843be3c4482e320809106b0a23755f1dd3c7f46f7d315d7bb2e943486d61fc7c811b9294dcc6b5baac4340f8db2b0d5e14749e7f35e1fc211fdbc1071b38b4753db201c314811bef885bd8921ad86facd6cc3b8f74d30a0b6e2e6e576f906e9581ef23d9c03e926e06d1f033f28bd1e21cfa6a0e3ff5c9d8246cf108d82b488b9fdd55d7de7ebb6a7f64b19e0d6b2ab1380a6f9d42361770d1956701a7f80e2de568acd0bb4527324b1e0973e89595d91c8cc102d9248525ae092e2c9b69f7414f724195b81427f28b1d3d09a51acfe354387915fd9521e8c890c125fc41a12bf34d2a1b304067ab7251e0e9ef41833ce109e76963b0b256395b16b886bca21b831f1408f836146019e7908829e716e72b81006610a2af08301de5d067c9e114a1e5759db8a6be6a3cc2806bcfe6fafd41b5bc9ddddb3dc33d6f605b1ca7d8a9e0ecdd6390d38906649e68a90a717bea80fa220170eea0c86fc78a7e10dac7b74b8e62045a3ecca54e035281fdc9fe5920a855fde3c0be522e3aef0c087524f13d973dff3768158b01a5800a060c06b451ec98d627dd052eda804d0556f60dbc490d94e6e9dea62ffcafb5beffbd9fc38fb2f0d7050004fe56b4dda0a27bc47554e1e0a7d764e17622e71f83a475db286bc7862deee1327e2028955d978272ea76bf0b88e70a18621aba59ff0c5993ef5f0e5d6b6b98e68b70203010001300d06092a864886f70d0101050500038202010079c79c8ef408a20d243d8bd8249fb9a48350dc19663b5e0fce67a8dbcb7de296c5ae7bbf72e98a2020fb78f2db29b54b0e24b181aa1c1d333cc0303685d6120b03216a913f96b96eb838f9bff125306ae3120af838c9fc07ebb5100125436bd24ec6d994d0bff5d065221871f8410daf536766757239bf594e61c5432c9817281b985263bada8381292e543a49814061ae11c92a316e7dc100327b59e3da90302c5ada68c6a50201bda1fcce800b53f381059665dbabeeb0b50eb22b2d7d2d9b0aa7488ca70e67ac6c518adb8e78454a466501e89d81a45bf1ebc350896f2c3ae4b6679ecfbf9d32960d4f5b493125c7876ef36158562371193f600bc511000a67bdb7c664d018f99d9e589868d103d7e0994f166b2ba18ff7e67d8c4da749e44dfae1d930ae5397083a51675c409049dfb626a96246c0015ca696e94ebb767a20147834bf78b07fece3f0872b057c1c519ff882501995237d8206b0b3832f78753ebd8dcbd1d3d9f5ba733538113af6b407d960ec4353c50eb38ab29888238da843cd404ed8f4952f59e4bbc0035fc77a54846a9d419179c46af1b4a3b7fc98e4d312aaa29b9b7d79e739703dc0fa41c7280d5587709277ffa11c3620f5fba985b82c238ba19b17ebd027af9424be0941719919f620dd3bb3c3f11638363708aa11f858e153cf3a69bce69978b90e4a273836100aa1e617ba455cd00426847f");
+            List<String> fdroid3 = Arrays.asList("Guardian Project Archive", "https://guardianproject.info/fdroid/archive", "The official repository of The Guardian Project apps for use with F-Droid client. This contains older versions of applications from the main repository.",
+                    "13", "0", "4", "ignore", "308205d8308203c0020900a397b4da7ecda034300d06092a864886f70d01010505003081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f301e170d3134303632363139333931385a170d3431313131303139333931385a3081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f30820222300d06092a864886f70d01010105000382020f003082020a0282020100b3cd79121b9b883843be3c4482e320809106b0a23755f1dd3c7f46f7d315d7bb2e943486d61fc7c811b9294dcc6b5baac4340f8db2b0d5e14749e7f35e1fc211fdbc1071b38b4753db201c314811bef885bd8921ad86facd6cc3b8f74d30a0b6e2e6e576f906e9581ef23d9c03e926e06d1f033f28bd1e21cfa6a0e3ff5c9d8246cf108d82b488b9fdd55d7de7ebb6a7f64b19e0d6b2ab1380a6f9d42361770d1956701a7f80e2de568acd0bb4527324b1e0973e89595d91c8cc102d9248525ae092e2c9b69f7414f724195b81427f28b1d3d09a51acfe354387915fd9521e8c890c125fc41a12bf34d2a1b304067ab7251e0e9ef41833ce109e76963b0b256395b16b886bca21b831f1408f836146019e7908829e716e72b81006610a2af08301de5d067c9e114a1e5759db8a6be6a3cc2806bcfe6fafd41b5bc9ddddb3dc33d6f605b1ca7d8a9e0ecdd6390d38906649e68a90a717bea80fa220170eea0c86fc78a7e10dac7b74b8e62045a3ecca54e035281fdc9fe5920a855fde3c0be522e3aef0c087524f13d973dff3768158b01a5800a060c06b451ec98d627dd052eda804d0556f60dbc490d94e6e9dea62ffcafb5beffbd9fc38fb2f0d7050004fe56b4dda0a27bc47554e1e0a7d764e17622e71f83a475db286bc7862deee1327e2028955d978272ea76bf0b88e70a18621aba59ff0c5993ef5f0e5d6b6b98e68b70203010001300d06092a864886f70d0101050500038202010079c79c8ef408a20d243d8bd8249fb9a48350dc19663b5e0fce67a8dbcb7de296c5ae7bbf72e98a2020fb78f2db29b54b0e24b181aa1c1d333cc0303685d6120b03216a913f96b96eb838f9bff125306ae3120af838c9fc07ebb5100125436bd24ec6d994d0bff5d065221871f8410daf536766757239bf594e61c5432c9817281b985263bada8381292e543a49814061ae11c92a316e7dc100327b59e3da90302c5ada68c6a50201bda1fcce800b53f381059665dbabeeb0b50eb22b2d7d2d9b0aa7488ca70e67ac6c518adb8e78454a466501e89d81a45bf1ebc350896f2c3ae4b6679ecfbf9d32960d4f5b493125c7876ef36158562371193f600bc511000a67bdb7c664d018f99d9e589868d103d7e0994f166b2ba18ff7e67d8c4da749e44dfae1d930ae5397083a51675c409049dfb626a96246c0015ca696e94ebb767a20147834bf78b07fece3f0872b057c1c519ff882501995237d8206b0b3832f78753ebd8dcbd1d3d9f5ba733538113af6b407d960ec4353c50eb38ab29888238da843cd404ed8f4952f59e4bbc0035fc77a54846a9d419179c46af1b4a3b7fc98e4d312aaa29b9b7d79e739703dc0fa41c7280d5587709277ffa11c3620f5fba985b82c238ba19b17ebd027af9424be0941719919f620dd3bb3c3f11638363708aa11f858e153cf3a69bce69978b90e4a273836100aa1e617ba455cd00426847f");
+
+            List<String> shouldBeRepos = new LinkedList<>();
+            shouldBeRepos.addAll(oem0);
+            shouldBeRepos.addAll(oem1);
+            shouldBeRepos.addAll(fdroid0);
+            shouldBeRepos.addAll(fdroid1);
+            shouldBeRepos.addAll(fdroid2);
+            shouldBeRepos.addAll(fdroid3);
+
+            for (int i = 0; i < initialRepos.size(); i++) {
+                assertEquals(shouldBeRepos.get(i), initialRepos.get(i));
+            }
+        } finally {
+            for (Repo repo : RepoProvider.Helper.all(context, new String[]{Schema.RepoTable.Cols._ID})) {
+                RepoProvider.Helper.remove(context, repo.getId());
+            }
+            additionalReposXmlFile.delete();
+            DBHelper.clearDbHelperSingleton();
+        }
+    }
+}
diff --git a/app/src/test/java/org/fdroid/fdroid/data/RepoProviderTest.java b/app/src/test/java/org/fdroid/fdroid/data/RepoProviderTest.java
index 378ef8cfa..e2a726abc 100644
--- a/app/src/test/java/org/fdroid/fdroid/data/RepoProviderTest.java
+++ b/app/src/test/java/org/fdroid/fdroid/data/RepoProviderTest.java
@@ -157,16 +157,16 @@ public class RepoProviderTest extends FDroidProviderTest {
         assertEquals(defaultRepos.size(), 4); // based on app/src/main/res/default_repo.xml
 
         String[] reposFromXml = context.getResources().getStringArray(R.array.default_repos);
-        if (reposFromXml.length % DBHelper.REPO_XML_ARG_COUNT != 0) {
+        if (reposFromXml.length % DBHelper.REPO_XML_ITEM_COUNT != 0) {
             throw new IllegalArgumentException(
                     "default_repo.xml array does not have the right number of elements");
         }
-        for (int i = 0; i < reposFromXml.length / DBHelper.REPO_XML_ARG_COUNT; i++) {
-            int offset = i * DBHelper.REPO_XML_ARG_COUNT;
+        for (int i = 0; i < reposFromXml.length / DBHelper.REPO_XML_ITEM_COUNT; i++) {
+            int offset = i * DBHelper.REPO_XML_ITEM_COUNT;
             assertRepo(
                     defaultRepos.get(i),
                     reposFromXml[offset + 1], // address
-                    reposFromXml[offset + 2], // description
+                    reposFromXml[offset + 2].replaceAll("\\s+", " "), // description
                     Utils.calcFingerprint(reposFromXml[offset + 7]), // pubkey
                     reposFromXml[offset]      // name
             );
diff --git a/app/src/test/resources/additional_repos.xml b/app/src/test/resources/additional_repos.xml
new file mode 100644
index 000000000..da6fa4c1c
--- /dev/null
+++ b/app/src/test/resources/additional_repos.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string-array name="additional_repos">
+        <!-- name -->
+        <item>oem0Name</item>
+        <!-- address -->
+        <item>https://www.oem0.com/yeah/repo</item>
+        <!-- description -->
+        <item>I'm the first oem repo.</item>
+        <!-- version -->
+        <item>22</item>
+        <!-- enabled -->
+        <item>1</item>
+        <!-- push requests -->
+        <item>ignore</item>
+        <!-- pubkey -->
+        <item>fffff2313aaaaabcccc111</item>
+
+        <!-- name -->
+        <item>oem1MyNameIs</item>
+        <!-- address -->
+        <item>https://www.mynameis.com/rapper/repo</item>
+        <!-- description -->
+        <item>Who is the first repo?</item>
+        <!-- version -->
+        <item>22</item>
+        <!-- enabled -->
+        <item>0</item>
+        <!-- push requests -->
+        <item>ignore</item>
+        <!-- pubkey -->
+        <item>ddddddd2313aaaaabcccc111</item>
+    </string-array>
+</resources>
diff --git a/app/src/test/resources/ugly_additional_repos.xml b/app/src/test/resources/ugly_additional_repos.xml
new file mode 100644
index 000000000..a91932d88
--- /dev/null
+++ b/app/src/test/resources/ugly_additional_repos.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string-array name="additional_repos">
+        <!-- name -->
+        <item>FTW</item>
+        <!-- address -->
+        <item>https://f-droid.org/repo</item>
+        <!-- description -->
+        <item>I'm the first oem repo.</item>
+        <!-- version -->
+        <item>22</item>
+        <!-- enabled -->
+        <item>1</item>
+        <!-- push requests -->
+        <item>prompt</item>
+        <!-- pubkey -->
+        <item>fffff2313aaaaabcccc111</item>
+
+
+        <ite>SHOULD BE IGNORED</ite>
+        <item>Repo Name</item>
+        <item>https://www.oem0.com/yeah/repo</item>
+        <item>I'm the second oem repo.</item>
+        <item>22</item>
+        <item>1</item>
+        <item_>SHOULD BE IGNORED</item_>
+        <ITEM>SHOULD BE IGNORED</ITEM>
+        <item>always</item>
+        <item>fffff2313aaaaabcccc111</item>
+    </string-array>
+</resources>