diff --git a/F-Droid/res/values/strings.xml b/F-Droid/res/values/strings.xml
index ab9111cab..e6814af49 100644
--- a/F-Droid/res/values/strings.xml
+++ b/F-Droid/res/values/strings.xml
@@ -295,8 +295,10 @@
     <string name="root_access_denied_title">Root access denied</string>
     <string name="root_access_denied_body">Either your Android device is not rooted or you have denied root access for F-Droid.</string>
     <string name="update_all">Update all</string>
-    <string name="installer_error_title">(De-)Installation Error</string>
-    <string name="installer_error_body">The (de-)installation failed. If you are using F-Droid as a privileged app, try disabling this setting!</string>
+    <string name="install_error_title">Install error</string>
+    <string name="install_error_unknown">Failed to install due to an unknown error</string>
+    <string name="uninstall_error_title">Uninstall error</string>
+    <string name="uninstall_error_unknown">Failed to uninstall due to an unknown error</string>
     <string name="system_permission_denied_title">System permissions denied</string>
     <string name="system_permission_denied_body">This option is only available when F-Droid is installed as a privileged app.</string>
     <string name="system_permission_install_via_root">Install as a privileged app</string>
diff --git a/F-Droid/src/org/fdroid/fdroid/AppDetails.java b/F-Droid/src/org/fdroid/fdroid/AppDetails.java
index fb44dfa00..1e8f12b0c 100644
--- a/F-Droid/src/org/fdroid/fdroid/AppDetails.java
+++ b/F-Droid/src/org/fdroid/fdroid/AppDetails.java
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2010-12  Ciaran Gultnieks, ciaran@ciarang.com
+ * Copyright (C) 2013-15 Daniel Martí <mvdan@mvdan.cc>
  * Copyright (C) 2013 Stefan Völkel, bd@bc-bd.org
  * Copyright (C) 2015 Nico Alt, nicoalt@posteo.org
  *
@@ -585,7 +586,7 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
     private void setApp(App newApp) {
 
         if (newApp == null) {
-            Toast.makeText(this, getString(R.string.no_such_app), Toast.LENGTH_LONG).show();
+            Toast.makeText(this, R.string.no_such_app, Toast.LENGTH_LONG).show();
             finish();
             return;
         }
@@ -819,8 +820,8 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
 
         if (!apk.compatible) {
             AlertDialog.Builder ask_alrt = new AlertDialog.Builder(this);
-            ask_alrt.setMessage(getString(R.string.installIncompatible));
-            ask_alrt.setPositiveButton(getString(R.string.yes),
+            ask_alrt.setMessage(R.string.installIncompatible);
+            ask_alrt.setPositiveButton(R.string.yes,
                     new DialogInterface.OnClickListener() {
                         @Override
                         public void onClick(DialogInterface dialog,
@@ -828,7 +829,7 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
                             startDownload(apk, repoaddress);
                         }
                     });
-            ask_alrt.setNegativeButton(getString(R.string.no),
+            ask_alrt.setNegativeButton(R.string.no,
                     new DialogInterface.OnClickListener() {
                         @Override
                         public void onClick(DialogInterface dialog,
@@ -843,7 +844,7 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
                 && !apk.sig.equals(mInstalledSigID)) {
             AlertDialog.Builder builder = new AlertDialog.Builder(this);
             builder.setMessage(R.string.SignatureMismatch).setPositiveButton(
-                    getString(R.string.ok),
+                    R.string.ok,
                     new DialogInterface.OnClickListener() {
                         @Override
                         public void onClick(DialogInterface dialog, int id) {
@@ -909,22 +910,36 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
                         onAppChanged();
                     }
                 });
-            } else {
-                runOnUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        onAppChanged();
-
-                        Log.e(TAG, "Installer aborted with errorCode: " + errorCode);
-
-                        AlertDialog.Builder alertBuilder = new AlertDialog.Builder(AppDetails.this);
-                        alertBuilder.setTitle(R.string.installer_error_title);
-                        alertBuilder.setMessage(R.string.installer_error_title);
-                        alertBuilder.setNeutralButton(android.R.string.ok, null);
-                        alertBuilder.create().show();
-                    }
-                });
+                return;
             }
+            final int title, body;
+            if (operation == InstallerCallback.OPERATION_INSTALL) {
+                title = R.string.install_error_title;
+            } else {
+                title = R.string.uninstall_error_title;
+            }
+            switch (errorCode) {
+            default:
+                if (operation == InstallerCallback.OPERATION_INSTALL) {
+                    body = R.string.install_error_unknown;
+                } else {
+                    body = R.string.uninstall_error_unknown;
+                }
+            }
+            runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    onAppChanged();
+
+                    Log.e(TAG, "Installer aborted with errorCode: " + errorCode);
+
+                    AlertDialog.Builder alertBuilder = new AlertDialog.Builder(AppDetails.this);
+                    alertBuilder.setTitle(title);
+                    alertBuilder.setMessage(body);
+                    alertBuilder.setNeutralButton(android.R.string.ok, null);
+                    alertBuilder.create().show();
+                }
+            });
         }
     };
 
@@ -960,13 +975,13 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
         boolean finished = false;
         switch (event.type) {
         case ApkDownloader.EVENT_ERROR:
-            final String text;
+            final int res;
             if (event.getData().getInt(ApkDownloader.EVENT_DATA_ERROR_TYPE) == ApkDownloader.ERROR_HASH_MISMATCH)
-                text = getString(R.string.corrupt_download);
+                res = R.string.corrupt_download;
             else
-                text = getString(R.string.details_notinstalled);
+                res = R.string.details_notinstalled;
             // this must be on the main UI thread
-            Toast.makeText(this, text, Toast.LENGTH_LONG).show();
+            Toast.makeText(this, res, Toast.LENGTH_LONG).show();
             cleanUpFinishedDownload();
             finished = true;
             break;
@@ -1074,8 +1089,7 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
 
                         view_more_description.setImageResource(R.drawable.ic_expand_more_grey600);
                         view_more_description.setOnClickListener(expander_description);
-                    }
-                    else {
+                    } else {
                         view_more_description.setVisibility(View.GONE);
                     }
                 }
@@ -1226,7 +1240,7 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
 
         private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
             public void onClick(View v) {
-                switch(v.getId()) {
+                switch (v.getId()) {
                     case R.id.website:
                         ((AppDetails) getActivity()).tryOpenUri(getApp().webURL);
                         break;
@@ -1310,7 +1324,7 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
                     view_all_permissions = false;
                     CommaSeparatedList permsList = getApks().getItem(0).permissions;
                     if (permsList == null) {
-                        permissionListView.setText(getString(R.string.no_permissions));
+                        permissionListView.setText(R.string.no_permissions);
                     } else {
                         Iterator<String> permissions = permsList.iterator();
                         StringBuilder sb = new StringBuilder();
@@ -1522,36 +1536,34 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
             if (activity.downloadHandler != null) {
                 btMain.setText(R.string.downloading);
                 btMain.setEnabled(false);
-            }
-            /*
-            Check count > 0 due to incompatible apps resulting in an empty list.
-            If App isn't installed
-             */
-            else if (!getApp().isInstalled() && getApp().suggestedVercode > 0 &&
+            // Check count > 0 due to incompatible apps resulting in an empty list.
+            // If App isn't installed
+            } else if (!getApp().isInstalled() && getApp().suggestedVercode > 0 &&
                     ((AppDetails)getActivity()).adapter.getCount() > 0) {
                 installed = false;
-                statusView.setText(getString(R.string.details_notinstalled));
+                statusView.setText(R.string.details_notinstalled);
                 NfcHelper.disableAndroidBeam(getActivity());
                 // Set Install button and hide second button
                 btMain.setText(R.string.menu_install);
                 btMain.setOnClickListener(mOnClickListener);
                 btMain.setEnabled(true);
-            }
             // If App is installed
-            else if (getApp().isInstalled()) {
+            } else if (getApp().isInstalled()) {
                 installed = true;
                 statusView.setText(getString(R.string.details_installed, getApp().installedVersionName));
                 NfcHelper.setAndroidBeam(getActivity(), getApp().id);
                 if (getApp().canAndWantToUpdate()) {
                     updateWanted = true;
                     btMain.setText(R.string.menu_upgrade);
-                }else {
+                } else {
                     updateWanted = false;
                     if (((AppDetails)getActivity()).mPm.getLaunchIntentForPackage(getApp().id) != null){
                         btMain.setText(R.string.menu_launch);
-                    }
-                    else {
+                    } else {
                         btMain.setText(R.string.menu_uninstall);
+                        if (!getApp().uninstallable) {
+                            btMain.setVisibility(View.GONE);
+                        }
                     }
                 }
                 btMain.setOnClickListener(mOnClickListener);
@@ -1560,7 +1572,7 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
             TextView currentVersion = (TextView) view.findViewById(R.id.current_version);
             if (!getApks().isEmpty()) {
                 currentVersion.setText(getApks().getItem(0).version);
-            }else {
+            } else {
                 currentVersion.setVisibility(View.GONE);
                 btMain.setVisibility(View.GONE);
             }
@@ -1581,14 +1593,11 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
                     // If "launchable", launch
                     if (((AppDetails)getActivity()).mPm.getLaunchIntentForPackage(getApp().id) != null) {
                         ((AppDetails)getActivity()).launchApk(getApp().id);
-                    }
-                    else {
+                    } else {
                         ((AppDetails)getActivity()).removeApk(getApp().id);
                     }
-                }
-
                 // If not installed, install
-                else if (getApp().suggestedVercode > 0) {
+                } else if (getApp().suggestedVercode > 0) {
                     btMain.setEnabled(false);
                     btMain.setText(R.string.system_install_installing);
                     final Apk apkToInstall = ApkProvider.Helper.find(getActivity(), getApp().id, getApp().suggestedVercode);
@@ -1656,8 +1665,8 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
                 remove();
             } else if (getApp().installedVersionCode > apk.vercode) {
                 AlertDialog.Builder ask_alrt = new AlertDialog.Builder(getActivity());
-                ask_alrt.setMessage(getString(R.string.installDowngrade));
-                ask_alrt.setPositiveButton(getString(R.string.yes),
+                ask_alrt.setMessage(R.string.installDowngrade);
+                ask_alrt.setPositiveButton(R.string.yes,
                         new DialogInterface.OnClickListener() {
                             @Override
                             public void onClick(DialogInterface dialog,
@@ -1665,7 +1674,7 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
                                 install(apk);
                             }
                         });
-                ask_alrt.setNegativeButton(getString(R.string.no),
+                ask_alrt.setNegativeButton(R.string.no,
                         new DialogInterface.OnClickListener() {
                             @Override
                             public void onClick(DialogInterface dialog,
diff --git a/F-Droid/src/org/fdroid/fdroid/FDroid.java b/F-Droid/src/org/fdroid/fdroid/FDroid.java
index 92c8cbd8a..60eae6fc3 100644
--- a/F-Droid/src/org/fdroid/fdroid/FDroid.java
+++ b/F-Droid/src/org/fdroid/fdroid/FDroid.java
@@ -288,7 +288,7 @@ public class FDroid extends ActionBarActivity {
 
             AlertDialog.Builder builder = new AlertDialog.Builder(this).setView(view);
             final AlertDialog alrt = builder.create();
-            alrt.setTitle(getString(R.string.about_title));
+            alrt.setTitle(R.string.about_title);
             alrt.setButton(AlertDialog.BUTTON_NEUTRAL,
                     getString(R.string.about_website),
                     new DialogInterface.OnClickListener() {
diff --git a/F-Droid/src/org/fdroid/fdroid/data/App.java b/F-Droid/src/org/fdroid/fdroid/data/App.java
index 2ed33f98b..71357118c 100644
--- a/F-Droid/src/org/fdroid/fdroid/data/App.java
+++ b/F-Droid/src/org/fdroid/fdroid/data/App.java
@@ -102,6 +102,11 @@ public class App extends ValueObject implements Comparable<App> {
 
     public Apk installedApk; // might be null if not installed
 
+    public boolean system;
+    public boolean updatedSystemApp;
+
+    public boolean uninstallable;
+
     @Override
     public int compareTo(App app) {
         return name.compareToIgnoreCase(app.name);
@@ -340,6 +345,9 @@ public class App extends ValueObject implements Comparable<App> {
         apk.sig = Utils.hashBytes(fdroidSig, "md5");
 
         this.installedApk = apk;
+        this.system = ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
+        this.updatedSystemApp = ((appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
+        this.uninstallable = !this.system || this.updatedSystemApp;
     }
 
     public boolean isValid() {
diff --git a/F-Droid/src/org/fdroid/fdroid/installer/SystemInstaller.java b/F-Droid/src/org/fdroid/fdroid/installer/SystemInstaller.java
index 0a1cd08e2..ddd713418 100644
--- a/F-Droid/src/org/fdroid/fdroid/installer/SystemInstaller.java
+++ b/F-Droid/src/org/fdroid/fdroid/installer/SystemInstaller.java
@@ -193,7 +193,16 @@ public class SystemInstaller extends Installer {
             return;
         }
 
+        final boolean isSystem = ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
         final boolean isUpdate = ((appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
+
+        if (isSystem && !isUpdate) {
+            // Cannot remove system apps unless we're uninstalling updates
+            mCallback.onError(InstallerCallback.OPERATION_DELETE,
+                    InstallerCallback.ERROR_CODE_OTHER);
+            return;
+        }
+
         int messageId;
         if (isUpdate) {
             messageId = R.string.uninstall_update_confirm;
@@ -268,69 +277,59 @@ public class SystemInstaller extends Installer {
     public final int INSTALL_REPLACE_EXISTING = 2;
 
     /**
-     * Following return codes are copied from Android 4.3 source code
+     * Following return codes are copied from Android 5.1 source code
      */
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} on
-     * success.
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} on success.
      */
     public static final int INSTALL_SUCCEEDED = 1;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the package is already installed.
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if the package is
+     * already installed.
      */
     public static final int INSTALL_FAILED_ALREADY_EXISTS = -1;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the package archive file is invalid.
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if the package archive
+     * file is invalid.
      */
     public static final int INSTALL_FAILED_INVALID_APK = -2;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the URI passed in is invalid.
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if the URI passed in
+     * is invalid.
      */
     public static final int INSTALL_FAILED_INVALID_URI = -3;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the package manager service found that the device didn't have enough
-     * storage space to install the app.
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if the package manager
+     * service found that the device didn't have enough storage space to install the app.
      */
     public static final int INSTALL_FAILED_INSUFFICIENT_STORAGE = -4;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * a package is already installed with the same name.
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if a
+     * package is already installed with the same name.
      */
     public static final int INSTALL_FAILED_DUPLICATE_PACKAGE = -5;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} by
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
      * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
      * the requested shared user does not exist.
      */
     public static final int INSTALL_FAILED_NO_SHARED_USER = -6;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} by
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
      * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
      * a previously installed package of the same name has a different signature
      * than the new package (and the old package's data was not removed).
@@ -338,33 +337,29 @@ public class SystemInstaller extends Installer {
     public static final int INSTALL_FAILED_UPDATE_INCOMPATIBLE = -7;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} by
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
      * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the new package is requested a shared user which is already installed on
-     * the device and does not have matching signature.
+     * the new package is requested a shared user which is already installed on the
+     * device and does not have matching signature.
      */
     public static final int INSTALL_FAILED_SHARED_USER_INCOMPATIBLE = -8;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} by
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
      * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
      * the new package uses a shared library that is not available.
      */
     public static final int INSTALL_FAILED_MISSING_SHARED_LIBRARY = -9;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} by
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
      * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
      * the new package uses a shared library that is not available.
      */
     public static final int INSTALL_FAILED_REPLACE_COULDNT_DELETE = -10;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} by
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
      * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
      * the new package failed while optimizing and validating its dex files,
      * either because there was not enough storage or the validation failed.
@@ -372,17 +367,15 @@ public class SystemInstaller extends Installer {
     public static final int INSTALL_FAILED_DEXOPT = -11;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} by
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
      * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the new package failed because the current SDK version is older than that
-     * required by the package.
+     * the new package failed because the current SDK version is older than
+     * that required by the package.
      */
     public static final int INSTALL_FAILED_OLDER_SDK = -12;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} by
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
      * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
      * the new package failed because it contains a content provider with the
      * same authority as a provider already installed in the system.
@@ -390,17 +383,15 @@ public class SystemInstaller extends Installer {
     public static final int INSTALL_FAILED_CONFLICTING_PROVIDER = -13;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} by
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
      * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the new package failed because the current SDK version is newer than that
-     * required by the package.
+     * the new package failed because the current SDK version is newer than
+     * that required by the package.
      */
     public static final int INSTALL_FAILED_NEWER_SDK = -14;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} by
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
      * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
      * the new package failed because it has specified that it is a test-only
      * package and the caller has not supplied the {@link #INSTALL_ALLOW_TEST}
@@ -409,17 +400,15 @@ public class SystemInstaller extends Installer {
     public static final int INSTALL_FAILED_TEST_ONLY = -15;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} by
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
      * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
      * the package being installed contains native code, but none that is
-     * compatible with the the device's CPU_ABI.
+     * compatible with the device's CPU_ABI.
      */
     public static final int INSTALL_FAILED_CPU_ABI_INCOMPATIBLE = -16;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} by
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
      * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
      * the new package uses a feature that is not available.
      */
@@ -427,121 +416,181 @@ public class SystemInstaller extends Installer {
 
     // ------ Errors related to sdcard
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} by
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
      * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
      * a secure container mount point couldn't be accessed on external media.
      */
     public static final int INSTALL_FAILED_CONTAINER_ERROR = -18;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} by
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
      * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the new package couldn't be installed in the specified install location.
+     * the new package couldn't be installed in the specified install
+     * location.
      */
     public static final int INSTALL_FAILED_INVALID_INSTALL_LOCATION = -19;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} by
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
      * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the new package couldn't be installed in the specified install location
-     * because the media is not available.
+     * the new package couldn't be installed in the specified install
+     * location because the media is not available.
      */
     public static final int INSTALL_FAILED_MEDIA_UNAVAILABLE = -20;
 
     /**
-     * Installation parse return code: this is passed to the
-     * {@link IPackageInstallObserver} by
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
      * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the parser was given a path that is not a file, or does not end with the
-     * expected '.apk' extension.
+     * the new package couldn't be installed because the verification timed out.
+     */
+    public static final int INSTALL_FAILED_VERIFICATION_TIMEOUT = -21;
+
+    /**
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
+     * the new package couldn't be installed because the verification did not succeed.
+     */
+    public static final int INSTALL_FAILED_VERIFICATION_FAILURE = -22;
+
+    /**
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
+     * the package changed from what the calling program expected.
+     */
+    public static final int INSTALL_FAILED_PACKAGE_CHANGED = -23;
+
+    /**
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
+     * the new package is assigned a different UID than it previously held.
+     */
+    public static final int INSTALL_FAILED_UID_CHANGED = -24;
+
+    /**
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
+     * the new package has an older version code than the currently installed package.
+     */
+    public static final int INSTALL_FAILED_VERSION_DOWNGRADE = -25;
+
+    /**
+     * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+     * if the parser was given a path that is not a file, or does not end with the expected
+     * '.apk' extension.
      */
     public static final int INSTALL_PARSE_FAILED_NOT_APK = -100;
 
     /**
-     * Installation parse return code: this is passed to the
-     * {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the parser was unable to retrieve the AndroidManifest.xml file.
+     * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+     * if the parser was unable to retrieve the AndroidManifest.xml file.
      */
     public static final int INSTALL_PARSE_FAILED_BAD_MANIFEST = -101;
 
     /**
-     * Installation parse return code: this is passed to the
-     * {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the parser encountered an unexpected exception.
+     * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+     * if the parser encountered an unexpected exception.
      */
     public static final int INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION = -102;
 
     /**
-     * Installation parse return code: this is passed to the
-     * {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the parser did not find any certificates in the .apk.
+     * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+     * if the parser did not find any certificates in the .apk.
      */
     public static final int INSTALL_PARSE_FAILED_NO_CERTIFICATES = -103;
 
     /**
-     * Installation parse return code: this is passed to the
-     * {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the parser found inconsistent certificates on the files in the .apk.
+     * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+     * if the parser found inconsistent certificates on the files in the .apk.
      */
     public static final int INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES = -104;
 
     /**
-     * Installation parse return code: this is passed to the
-     * {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the parser encountered a CertificateEncodingException in one of the files
-     * in the .apk.
+     * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+     * if the parser encountered a CertificateEncodingException in one of the
+     * files in the .apk.
      */
     public static final int INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING = -105;
 
     /**
-     * Installation parse return code: this is passed to the
-     * {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the parser encountered a bad or missing package name in the manifest.
+     * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+     * if the parser encountered a bad or missing package name in the manifest.
      */
     public static final int INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME = -106;
 
     /**
-     * Installation parse return code: this is passed to the
-     * {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the parser encountered a bad shared user id name in the manifest.
+     * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+     * if the parser encountered a bad shared user id name in the manifest.
      */
     public static final int INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID = -107;
 
     /**
-     * Installation parse return code: this is passed to the
-     * {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the parser encountered some structural problem in the manifest.
+     * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+     * if the parser encountered some structural problem in the manifest.
      */
     public static final int INSTALL_PARSE_FAILED_MANIFEST_MALFORMED = -108;
 
     /**
-     * Installation parse return code: this is passed to the
-     * {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the parser did not find any actionable tags (instrumentation or
-     * application) in the manifest.
+     * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+     * if the parser did not find any actionable tags (instrumentation or application)
+     * in the manifest.
      */
     public static final int INSTALL_PARSE_FAILED_MANIFEST_EMPTY = -109;
 
     /**
-     * Installation failed return code: this is passed to the
-     * {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the system failed to install the package because of system issues.
+     * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+     * if the system failed to install the package because of system issues.
      */
     public static final int INSTALL_FAILED_INTERNAL_ERROR = -110;
 
+    /**
+     * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+     * if the system failed to install the package because the user is restricted from installing
+     * apps.
+     */
+    public static final int INSTALL_FAILED_USER_RESTRICTED = -111;
+
+    /**
+     * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+     * if the system failed to install the package because it is attempting to define a
+     * permission that is already defined by some existing package.
+     *
+     * <p>The package name of the app which has already defined the permission is passed to
+     * a {@link PackageInstallObserver}, if any, as the {@link #EXTRA_EXISTING_PACKAGE}
+     * string extra; and the name of the permission being redefined is passed in the
+     * {@link #EXTRA_EXISTING_PERMISSION} string extra.
+     */
+    public static final int INSTALL_FAILED_DUPLICATE_PERMISSION = -112;
+
+    /**
+     * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+     * if the system failed to install the package because its packaged native code did not
+     * match any of the ABIs supported by the system.
+     */
+    public static final int INSTALL_FAILED_NO_MATCHING_ABIS = -113;
+
+    /**
+     * Internal return code for NativeLibraryHelper methods to indicate that the package
+     * being processed did not contain any native code. This is placed here only so that
+     * it can belong to the same value space as the other install failure codes.
+     */
+    public static final int NO_NATIVE_LIBRARIES = -114;
+
+    public static final int INSTALL_FAILED_ABORTED = -115;
+
     /**
      * Return code for when package deletion succeeds. This is passed to the
      * {@link IPackageDeleteObserver} by {@link #deletePackage()} if the system
@@ -571,4 +620,14 @@ public class SystemInstaller extends Installer {
      */
     public static final int DELETE_FAILED_USER_RESTRICTED = -3;
 
+    /**
+     * Deletion failed return code: this is passed to the
+     * {@link IPackageDeleteObserver} by {@link #deletePackage()} if the system
+     * failed to delete the package because a profile
+     * or device owner has marked the package as uninstallable.
+     */
+    public static final int DELETE_FAILED_OWNER_BLOCKED = -4;
+
+    public static final int DELETE_FAILED_ABORTED = -5;
+
 }
diff --git a/F-Droid/src/org/fdroid/fdroid/views/ManageReposActivity.java b/F-Droid/src/org/fdroid/fdroid/views/ManageReposActivity.java
index 20ae144bd..9937d968b 100644
--- a/F-Droid/src/org/fdroid/fdroid/views/ManageReposActivity.java
+++ b/F-Droid/src/org/fdroid/fdroid/views/ManageReposActivity.java
@@ -292,7 +292,7 @@ public class ManageReposActivity extends ActionBarActivity {
             final EditText uriEditText = (EditText) view.findViewById(R.id.edit_uri);
             final EditText fingerprintEditText = (EditText) view.findViewById(R.id.edit_fingerprint);
 
-            addRepoDialog.setTitle(getString(R.string.repo_add_title));
+            addRepoDialog.setTitle(R.string.repo_add_title);
             addRepoDialog.setButton(DialogInterface.BUTTON_NEGATIVE,
                 getString(R.string.cancel),
                 new DialogInterface.OnClickListener() {
@@ -566,7 +566,7 @@ public class ManageReposActivity extends ActionBarActivity {
             };
 
             Button skip = addRepoDialog.getButton(AlertDialog.BUTTON_NEGATIVE);
-            skip.setText(getString(R.string.skip));
+            skip.setText(R.string.skip);
             skip.setOnClickListener(new View.OnClickListener() {
                 @Override
                 public void onClick(View v) {