diff --git a/app/src/androidTest/assets/org.fdroid.permissions.minmax.apk b/app/src/androidTest/assets/org.fdroid.permissions.minmax.apk
new file mode 100644
index 000000000..880342cc6
Binary files /dev/null and b/app/src/androidTest/assets/org.fdroid.permissions.minmax.apk differ
diff --git a/app/src/androidTest/assets/org.fdroid.permissions.minmax.zip b/app/src/androidTest/assets/org.fdroid.permissions.minmax.zip
new file mode 100644
index 000000000..068ad82fd
Binary files /dev/null and b/app/src/androidTest/assets/org.fdroid.permissions.minmax.zip differ
diff --git a/app/src/androidTest/assets/org.fdroid.permissions.sdk14.apk b/app/src/androidTest/assets/org.fdroid.permissions.sdk14.apk
new file mode 100644
index 000000000..046b8ddf4
Binary files /dev/null and b/app/src/androidTest/assets/org.fdroid.permissions.sdk14.apk differ
diff --git a/app/src/androidTest/assets/org.fdroid.permissions.sdk14.zip b/app/src/androidTest/assets/org.fdroid.permissions.sdk14.zip
new file mode 100644
index 000000000..3ab3d0f59
Binary files /dev/null and b/app/src/androidTest/assets/org.fdroid.permissions.sdk14.zip differ
diff --git a/app/src/androidTest/java/org/fdroid/fdroid/AssetUtils.java b/app/src/androidTest/java/org/fdroid/fdroid/AssetUtils.java
new file mode 100644
index 000000000..6d5265dfb
--- /dev/null
+++ b/app/src/androidTest/java/org/fdroid/fdroid/AssetUtils.java
@@ -0,0 +1,39 @@
+package org.fdroid.fdroid;
+
+import android.content.Context;
+import android.support.annotation.Nullable;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import static org.junit.Assert.fail;
+
+public class AssetUtils {
+
+    private static final String TAG = "Utils";
+
+    @Nullable
+    public static File copyAssetToDir(Context context, String assetName, File directory) {
+        File tempFile = null;
+        InputStream input = null;
+        OutputStream output = null;
+        try {
+            tempFile = File.createTempFile(assetName, ".testasset", directory);
+            Log.i(TAG, "Copying asset file " + assetName + " to directory " + directory);
+            input = context.getAssets().open(assetName);
+            output = new FileOutputStream(tempFile);
+            Utils.copy(input, output);
+        } catch (IOException e) {
+            fail(e.getMessage());
+        } finally {
+            Utils.closeQuietly(output);
+            Utils.closeQuietly(input);
+        }
+        return tempFile;
+    }
+
+}
diff --git a/app/src/androidTest/java/org/fdroid/fdroid/compat/FileCompatTest.java b/app/src/androidTest/java/org/fdroid/fdroid/compat/FileCompatTest.java
index f65c28b46..77eac511a 100644
--- a/app/src/androidTest/java/org/fdroid/fdroid/compat/FileCompatTest.java
+++ b/app/src/androidTest/java/org/fdroid/fdroid/compat/FileCompatTest.java
@@ -4,12 +4,10 @@ import android.app.Instrumentation;
 import android.content.Context;
 import android.os.Build;
 import android.os.Environment;
-import android.support.annotation.Nullable;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
-import android.util.Log;
 
-import org.fdroid.fdroid.Utils;
+import org.fdroid.fdroid.AssetUtils;
 import org.fdroid.fdroid.data.SanitizedFile;
 import org.junit.After;
 import org.junit.Before;
@@ -17,10 +15,6 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
 import java.util.UUID;
 
 import static org.junit.Assert.assertFalse;
@@ -36,8 +30,6 @@ import static org.junit.Assume.assumeTrue;
 @RunWith(AndroidJUnit4.class)
 public class FileCompatTest {
 
-    private static final String TAG = "FileCompatTest";
-
     private SanitizedFile sourceFile;
     private SanitizedFile destFile;
 
@@ -45,7 +37,8 @@ public class FileCompatTest {
     public void setUp() {
         Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
         File dir = getWriteableDir(instrumentation);
-        sourceFile = SanitizedFile.knownSanitized(copyAssetToDir(instrumentation.getContext(), "simpleIndex.jar", dir));
+        sourceFile = SanitizedFile.knownSanitized(
+                AssetUtils.copyAssetToDir(instrumentation.getContext(), "simpleIndex.jar", dir));
         destFile = new SanitizedFile(dir, "dest-" + UUID.randomUUID() + ".testproduct");
         assertFalse(destFile.exists());
         assertTrue(sourceFile.getAbsolutePath() + " should exist.", sourceFile.exists());
@@ -82,26 +75,6 @@ public class FileCompatTest {
         assertTrue(destFile.getAbsolutePath() + " should exist after symlinking", destFile.exists());
     }
 
-    @Nullable
-    private static File copyAssetToDir(Context context, String assetName, File directory) {
-        File tempFile;
-        InputStream input = null;
-        OutputStream output = null;
-        try {
-            tempFile = File.createTempFile(assetName + "-", ".testasset", directory);
-            Log.i(TAG, "Copying asset file " + assetName + " to directory " + directory);
-            input = context.getAssets().open(assetName);
-            output = new FileOutputStream(tempFile);
-            Utils.copy(input, output);
-        } catch (IOException e) {
-            e.printStackTrace();
-            return null;
-        } finally {
-            Utils.closeQuietly(output);
-            Utils.closeQuietly(input);
-        }
-        return tempFile;
-    }
 
     /**
      * Prefer internal over external storage, because external tends to be FAT filesystems,
diff --git a/app/src/androidTest/java/org/fdroid/fdroid/installer/ApkVerifierTest.java b/app/src/androidTest/java/org/fdroid/fdroid/installer/ApkVerifierTest.java
new file mode 100644
index 000000000..ecfa3047d
--- /dev/null
+++ b/app/src/androidTest/java/org/fdroid/fdroid/installer/ApkVerifierTest.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2016 Dominik Schürmann <dominik@dominikschuermann.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+package org.fdroid.fdroid.installer;
+
+import android.app.Instrumentation;
+import android.net.Uri;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.fdroid.fdroid.AssetUtils;
+import org.fdroid.fdroid.data.Apk;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.IOException;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * This test checks the ApkVerifier by parsing a repo from permissionsRepo.xml
+ * and checking the listed permissions against the ones specified in apks' AndroidManifest,
+ * which have been specifically generated for this test.
+ * - the apk file name must match the package name in the xml
+ * - the versionName of listed apks inside the repo have either a good or bad outcome.
+ * this must be defined in GOOD_VERSION_NAMES and BAD_VERSION_NAMES.
+ * <p/>
+ * NOTE: This androidTest cannot run as a Robolectric test because the
+ * required methods from PackageManger are not included in Robolectric's Android API.
+ * java.lang.NoClassDefFoundError: java/util/jar/StrictJarFile
+ * at android.content.pm.PackageManager.getPackageArchiveInfo(PackageManager.java:3545)
+ */
+@RunWith(AndroidJUnit4.class)
+public class ApkVerifierTest {
+
+    Instrumentation instrumentation;
+
+    File sdk14Apk;
+    File minMaxApk;
+
+    @Rule
+    public TemporaryFolder tempFolder = new TemporaryFolder();
+
+    @Before
+    public void setUp() {
+        instrumentation = InstrumentationRegistry.getInstrumentation();
+        File dir = null;
+        try {
+            dir = tempFolder.newFolder("apks");
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+        sdk14Apk = AssetUtils.copyAssetToDir(instrumentation.getContext(),
+                "org.fdroid.permissions.sdk14.apk",
+                dir
+        );
+        minMaxApk = AssetUtils.copyAssetToDir(instrumentation.getContext(),
+                "org.fdroid.permissions.minmax.apk",
+                dir
+        );
+        assertTrue(sdk14Apk.exists());
+        assertTrue(minMaxApk.exists());
+    }
+
+    @Test
+    public void testWithoutPrefix() {
+        Apk apk = new Apk();
+        apk.packageName = "org.fdroid.permissions.sdk14";
+        apk.targetSdkVersion = 14;
+        apk.permissions = new String[]{
+                "AUTHENTICATE_ACCOUNTS",
+                "MANAGE_ACCOUNTS",
+                "READ_PROFILE",
+                "WRITE_PROFILE",
+                "GET_ACCOUNTS",
+                "READ_CONTACTS",
+                "WRITE_CONTACTS",
+                "WRITE_EXTERNAL_STORAGE",
+                "READ_EXTERNAL_STORAGE",
+                "INTERNET",
+                "ACCESS_NETWORK_STATE",
+                "NFC",
+                "READ_SYNC_SETTINGS",
+                "WRITE_SYNC_SETTINGS",
+                "WRITE_CALL_LOG", // implied-permission!
+                "READ_CALL_LOG", // implied-permission!
+        };
+
+        Uri uri = Uri.fromFile(sdk14Apk);
+
+        ApkVerifier apkVerifier = new ApkVerifier(instrumentation.getContext(), uri, apk);
+
+        try {
+            apkVerifier.verifyApk();
+        } catch (ApkVerifier.ApkVerificationException | ApkVerifier.ApkPermissionUnequalException e) {
+            e.printStackTrace();
+            fail(e.getMessage());
+        }
+    }
+
+    @Test
+    public void testWithPrefix() {
+        Apk apk = new Apk();
+        apk.packageName = "org.fdroid.permissions.sdk14";
+        apk.targetSdkVersion = 14;
+        apk.permissions = new String[]{
+                "android.permission.AUTHENTICATE_ACCOUNTS",
+                "android.permission.MANAGE_ACCOUNTS",
+                "android.permission.READ_PROFILE",
+                "android.permission.WRITE_PROFILE",
+                "android.permission.GET_ACCOUNTS",
+                "android.permission.READ_CONTACTS",
+                "android.permission.WRITE_CONTACTS",
+                "android.permission.WRITE_EXTERNAL_STORAGE",
+                "android.permission.READ_EXTERNAL_STORAGE",
+                "android.permission.INTERNET",
+                "android.permission.ACCESS_NETWORK_STATE",
+                "android.permission.NFC",
+                "android.permission.READ_SYNC_SETTINGS",
+                "android.permission.WRITE_SYNC_SETTINGS",
+                "android.permission.WRITE_CALL_LOG", // implied-permission!
+                "android.permission.READ_CALL_LOG", // implied-permission!
+        };
+
+        Uri uri = Uri.fromFile(sdk14Apk);
+
+        ApkVerifier apkVerifier = new ApkVerifier(instrumentation.getContext(), uri, apk);
+
+        try {
+            apkVerifier.verifyApk();
+        } catch (ApkVerifier.ApkVerificationException | ApkVerifier.ApkPermissionUnequalException e) {
+            e.printStackTrace();
+            fail(e.getMessage());
+        }
+    }
+
+    /**
+     * Additional permissions are okay. The user is simply
+     * warned about a permission that is not used inside the apk
+     */
+    @Test
+    public void testAdditionalPermission() {
+        Apk apk = new Apk();
+        apk.packageName = "org.fdroid.permissions.sdk14";
+        apk.targetSdkVersion = 14;
+        apk.permissions = new String[]{
+                "android.permission.AUTHENTICATE_ACCOUNTS",
+                "android.permission.MANAGE_ACCOUNTS",
+                "android.permission.READ_PROFILE",
+                "android.permission.WRITE_PROFILE",
+                "android.permission.GET_ACCOUNTS",
+                "android.permission.READ_CONTACTS",
+                "android.permission.WRITE_CONTACTS",
+                "android.permission.WRITE_EXTERNAL_STORAGE",
+                "android.permission.READ_EXTERNAL_STORAGE",
+                "android.permission.INTERNET",
+                "android.permission.ACCESS_NETWORK_STATE",
+                "android.permission.NFC",
+                "android.permission.READ_SYNC_SETTINGS",
+                "android.permission.WRITE_SYNC_SETTINGS",
+                "android.permission.WRITE_CALL_LOG", // implied-permission!
+                "android.permission.READ_CALL_LOG", // implied-permission!
+                "NEW_PERMISSION",
+        };
+
+        Uri uri = Uri.fromFile(sdk14Apk);
+
+        ApkVerifier apkVerifier = new ApkVerifier(instrumentation.getContext(), uri, apk);
+
+        try {
+            apkVerifier.verifyApk();
+        } catch (ApkVerifier.ApkVerificationException | ApkVerifier.ApkPermissionUnequalException e) {
+            e.printStackTrace();
+            fail(e.getMessage());
+        }
+    }
+
+    /**
+     * Missing permissions are not okay!
+     * The user is then not warned about a permission that the apk uses!
+     */
+    @Test
+    public void testMissingPermission() {
+        Apk apk = new Apk();
+        apk.packageName = "org.fdroid.permissions.sdk14";
+        apk.targetSdkVersion = 14;
+        apk.permissions = new String[]{
+                //"android.permission.AUTHENTICATE_ACCOUNTS",
+                "android.permission.MANAGE_ACCOUNTS",
+                "android.permission.READ_PROFILE",
+                "android.permission.WRITE_PROFILE",
+                "android.permission.GET_ACCOUNTS",
+                "android.permission.READ_CONTACTS",
+                "android.permission.WRITE_CONTACTS",
+                "android.permission.WRITE_EXTERNAL_STORAGE",
+                "android.permission.READ_EXTERNAL_STORAGE",
+                "android.permission.INTERNET",
+                "android.permission.ACCESS_NETWORK_STATE",
+                "android.permission.NFC",
+                "android.permission.READ_SYNC_SETTINGS",
+                "android.permission.WRITE_SYNC_SETTINGS",
+                "android.permission.WRITE_CALL_LOG", // implied-permission!
+                "android.permission.READ_CALL_LOG", // implied-permission!
+        };
+
+        Uri uri = Uri.fromFile(sdk14Apk);
+
+        ApkVerifier apkVerifier = new ApkVerifier(instrumentation.getContext(), uri, apk);
+
+        try {
+            apkVerifier.verifyApk();
+            fail();
+        } catch (ApkVerifier.ApkVerificationException e) {
+            e.printStackTrace();
+            fail(e.getMessage());
+        } catch (ApkVerifier.ApkPermissionUnequalException e) {
+            e.printStackTrace();
+        }
+    }
+
+}
diff --git a/app/src/main/java/org/fdroid/fdroid/installer/ApkVerifier.java b/app/src/main/java/org/fdroid/fdroid/installer/ApkVerifier.java
index ebcd56b8d..76795df29 100644
--- a/app/src/main/java/org/fdroid/fdroid/installer/ApkVerifier.java
+++ b/app/src/main/java/org/fdroid/fdroid/installer/ApkVerifier.java
@@ -45,6 +45,10 @@ class ApkVerifier {
     private final Apk expectedApk;
     private final PackageManager pm;
 
+    /**
+     * IMPORTANT: localApkUri must be available as a File on the file system with an absolute path
+     * to be readable by Android's internal PackageParser.
+     */
     ApkVerifier(Context context, Uri localApkUri, Apk expectedApk) {
         this.localApkUri = localApkUri;
         this.expectedApk = expectedApk;
@@ -52,11 +56,18 @@ class ApkVerifier {
     }
 
     public void verifyApk() throws ApkVerificationException, ApkPermissionUnequalException {
+        Utils.debugLog(TAG, "localApkUri.getPath: " + localApkUri.getPath());
+
         // parse downloaded apk file locally
         PackageInfo localApkInfo = pm.getPackageArchiveInfo(
                 localApkUri.getPath(), PackageManager.GET_PERMISSIONS);
         if (localApkInfo == null) {
-            throw new ApkVerificationException("Parsing apk file failed!");
+            // Unfortunately, more specific errors are not forwarded to us
+            // but the internal PackageParser sometimes shows warnings in logcat such as
+            // "Requires newer sdk version #14 (current version is #11)"
+            throw new ApkVerificationException("Parsing apk file failed!" +
+                    "Maybe minSdk of apk is lower than current Sdk?" +
+                    "Look into logcat for more specific warnings of Android's PackageParser");
         }
 
         // check if the apk has the expected packageName