diff --git a/src/org/fdroid/fdroid/DB.java b/src/org/fdroid/fdroid/DB.java
index dbefca5b7..f9db98971 100644
--- a/src/org/fdroid/fdroid/DB.java
+++ b/src/org/fdroid/fdroid/DB.java
@@ -35,586 +35,586 @@ import android.util.Log;
 
 public class DB {
 
-	private static final String DATABASE_NAME = "fdroid";
-
-	private SQLiteDatabase db;
-
-	// The TABLE_APP table stores details of all the applications we know about.
-	// This information is retrieved from the repositories.
-	private static final String TABLE_APP = "fdroid_app";
-	private static final String CREATE_TABLE_APP = "create table " + TABLE_APP
-			+ " ( " + "id text not null, " + "name text not null, "
-			+ "summary text not null, " + "icon text, "
-			+ "description text not null, " + "license text not null, "
-			+ "webURL text, " + "trackerURL text, " + "sourceURL text, "
-			+ "installedVersion text," + "hasUpdates int not null,"
-			+ "primary key(id));";
-
-	public static class App {
-
-		public App() {
-			name = "Unknown";
-			summary = "Unknown application";
-			icon = "noicon.png";
-			id = "unknown";
-			license = "Unknown";
-			trackerURL = "";
-			sourceURL = "";
-			webURL = "";
-			antiFeatures = null;
-			hasUpdates = false;
-			updated = false;
-			apks = new Vector<Apk>();
-		}
-
-		public String id;
-		public String name;
-		public String summary;
-		public String icon;
-		public String description;
-		public String license;
-		public String webURL;
-		public String trackerURL;
-		public String sourceURL;
-		public String installedVersion;
-		public int installedVerCode;
-		public String marketVersion;
-		public int marketVercode;
-
-		// Comma-separated list of anti-features (as defined in the metadata
-		// documentation) or null if there aren't any.
-		public String antiFeatures;
-
-		// True if there are new versions (apks) that the user hasn't
-		// explicitly ignored. (We're currently not using the database
-		// field for this - we make the decision on the fly in getApps().
-		public boolean hasUpdates;
-
-		// Used internally for tracking during repo updates.
-		public boolean updated;
-
-		public Vector<Apk> apks;
-
-		// Get the current version - this will be one of the Apks from 'apks'.
-		// Can return null if there are no available versions.
-		// This should be the 'current' version, as in the most recent stable
-		// one, that most users would want by default. It might not be the
-		// most recent, if for example there are betas etc.
-		public Apk getCurrentVersion() {
-
-			// Try and return the version that's in Google's market first...
-			if (marketVersion != null && marketVercode > 0) {
-				for (Apk apk : apks) {
-					if (apk.vercode == marketVercode)
-						return apk;
-				}
-			}
-
-			// If we don't know the market version, or we don't have it, we
-			// return the most recent version we have...
-			int latestcode = -1;
-			Apk latestapk = null;
-			for (Apk apk : apks) {
-				if (apk.vercode > latestcode) {
-					latestapk = apk;
-					latestcode = apk.vercode;
-				}
-			}
-			return latestapk;
-		}
-
-	}
-
-	// The TABLE_APK table stores details of all the application versions we
-	// know about. Each relates directly back to an entry in TABLE_APP.
-	// This information is retrieved from the repositories.
-	private static final String TABLE_APK = "fdroid_apk";
-	private static final String CREATE_TABLE_APK = "create table " + TABLE_APK
-			+ " ( " + "id text not null, " + "version text not null, "
-			+ "server text not null, " + "hash text not null, "
-			+ "vercode int not null," + "apkName text not null, "
-			+ "size int not null," + "primary key(id,version));";
-
-	public static class Apk {
-
-		public Apk() {
-			updated = false;
-			size = 0;
-			apkSource = null;
-		}
-
-		public String id;
-		public String version;
-		public int vercode;
-		public int size; // Size in bytes - 0 means we don't know!
-		public String server;
-		public String hash;
-		public String apkName;
-
-		// If null, the apk comes from the same server as the repo index.
-		// Otherwise
-		// this is the complete URL to download the apk from.
-		public String apkSource;
-
-		// Used internally for tracking during repo updates.
-		public boolean updated;
-
-		public String getURL() {
-			String path = apkName.replace(" ", "%20");
-			return server + "/" + path;
-		}
-	}
-
-	// The TABLE_REPO table stores the details of the repositories in use.
-	private static final String TABLE_REPO = "fdroid_repo";
-	private static final String CREATE_TABLE_REPO = "create table "
-			+ TABLE_REPO + " (" + "address text primary key, "
-			+ "inuse integer not null, " + "priority integer not null);";
-
-	public static class Repo {
-		public String address;
-		public boolean inuse;
-		public int priority;
-	}
-
-	// SQL to update the database to versions beyond the first. Here is
-	// how the database works:
-	//
-	// * The SQL to create the database tables always creates version
-	// 1. This SQL will never be altered.
-	// * In the array below there is SQL for each subsequent version
-	// from 2 onwards.
-	// * For a new install, the database is always initialised to version
-	// 1.
-	// * Then, whether it's a new install or not, all the upgrade SQL in
-	// the array below is executed in order to bring the database up to
-	// the latest version.
-	// * The current version is tracked by an entry in the TABLE_VERSION
-	// table.
-	//
-	private static final String[][] DB_UPGRADES = {
-
-	// Version 2...
-			{ "alter table " + TABLE_APP + " add marketVersion text",
-					"alter table " + TABLE_APP + " add marketVercode integer" },
-
-			// Version 3...
-			{ "alter table " + TABLE_APK + " add apkSource text" },
-
-			// Version 4...
-			{ "alter table " + TABLE_APP + " add installedVerCode integer" },
-
-			// Version 5...
-			{ "alter table " + TABLE_APP + " add antiFeatures string" }
-
-	};
-
-	private class DBHelper extends SQLiteOpenHelper {
-
-		public DBHelper(Context context) {
-			super(context, DATABASE_NAME, null, DB_UPGRADES.length + 1);
-		}
-
-		@Override
-		public void onCreate(SQLiteDatabase db) {
-			db.execSQL(CREATE_TABLE_REPO);
-			db.execSQL(CREATE_TABLE_APP);
-			db.execSQL(CREATE_TABLE_APK);
-			ContentValues values = new ContentValues();
-			values.put("address", "http://f-droid.org/repo");
-			values.put("inuse", 1);
-			values.put("priority", 10);
-			db.insert(TABLE_REPO, null, values);
-			onUpgrade(db, 1, DB_UPGRADES.length + 1);
-		}
-
-		@Override
-		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-			for (int v = oldVersion + 1; v <= newVersion; v++)
-				for (int i = 0; i < DB_UPGRADES[v - 2].length; i++)
-					db.execSQL(DB_UPGRADES[v - 2][i]);
-		}
-
-	}
-
-	public static String getIconsPath() {
-		return "/sdcard/.fdroid/icons/";
-	}
-
-	private PackageManager mPm;
-
-	public DB(Context ctx) {
-
-		DBHelper h = new DBHelper(ctx);
-		db = h.getWritableDatabase();
-		mPm = ctx.getPackageManager();
-	}
-
-	public void close() {
-		db.close();
-		db = null;
-	}
-
-	// Delete the database, which should cause it to be re-created next time
-	// it's used.
-	public static void delete(Context ctx) {
-		try {
-			ctx.deleteDatabase(DATABASE_NAME);
-			// Also try and delete the old one, from versions 0.13 and earlier.
-			ctx.deleteDatabase("fdroid_db");
-		} catch (Exception ex) {
-			Log.d("FDroid", "Exception in DB.delete: " + ex.getMessage());
-		}
-	}
-
-	// Get the number of apps that have updates available.
-	public int getNumUpdates() {
-		Vector<App> apps = getApps(null, null, false);
-		int count = 0;
-		for (App app : apps) {
-			if (app.hasUpdates)
-				count++;
-		}
-		return count;
-	}
-
-	// Return a list of apps matching the given criteria.
-	// 'appid' - specific app id to retrieve, or null
-	// 'filter' - search text to filter on, or null
-	// 'update' - update installed version information from device, rather than
-	// simply using values cached in the database. Slower.
-	public Vector<App> getApps(String appid, String filter, boolean update) {
-		Vector<App> result = new Vector<App>();
-		Cursor c = null;
-		Cursor c2 = null;
-		try {
-
-			String query = "select * from " + TABLE_APP;
-			if (appid != null) {
-				query += " where id = '" + appid + "'";
-			} else if (filter != null) {
-				query += " where name like '%" + filter + "%'"
-						+ " or description like '%" + filter + "%'";
-			}
-			query += " order by name collate nocase";
-
-			c = db.rawQuery(query, null);
-			c.moveToFirst();
-			while (!c.isAfterLast()) {
-
-				App app = new App();
-				app.id = c.getString(c.getColumnIndex("id"));
-				app.name = c.getString(c.getColumnIndex("name"));
-				app.summary = c.getString(c.getColumnIndex("summary"));
-				app.icon = c.getString(c.getColumnIndex("icon"));
-				app.description = c.getString(c.getColumnIndex("description"));
-				app.license = c.getString(c.getColumnIndex("license"));
-				app.webURL = c.getString(c.getColumnIndex("webURL"));
-				app.trackerURL = c.getString(c.getColumnIndex("trackerURL"));
-				app.sourceURL = c.getString(c.getColumnIndex("sourceURL"));
-				app.installedVersion = c.getString(c
-						.getColumnIndex("installedVersion"));
-				app.installedVerCode = c.getInt(c
-						.getColumnIndex("installedVerCode"));
-				app.marketVersion = c.getString(c
-						.getColumnIndex("marketVersion"));
-				app.marketVercode = c.getInt(c.getColumnIndex("marketVercode"));
-				app.antiFeatures = c
-						.getString(c.getColumnIndex("antiFeatures"));
-				app.hasUpdates = false;
-
-				c2 = db.rawQuery("select * from " + TABLE_APK
-						+ " where id = ? order by vercode desc",
-						new String[] { app.id });
-				c2.moveToFirst();
-				while (!c2.isAfterLast()) {
-					Apk apk = new Apk();
-					apk.id = app.id;
-					apk.version = c2.getString(c2.getColumnIndex("version"));
-					apk.vercode = c2.getInt(c2.getColumnIndex("vercode"));
-					apk.server = c2.getString(c2.getColumnIndex("server"));
-					apk.hash = c2.getString(c2.getColumnIndex("hash"));
-					apk.size = c2.getInt(c2.getColumnIndex("size"));
-					apk.apkName = c2.getString(c2.getColumnIndex("apkName"));
-					apk.apkSource = c2
-							.getString(c2.getColumnIndex("apkSource"));
-					app.apks.add(apk);
-					c2.moveToNext();
-				}
-				c2.close();
-
-				result.add(app);
-				c.moveToNext();
-			}
-
-		} catch (Exception e) {
-			Log.d("FDroid", "Exception during database reading - "
-					+ e.getMessage() + " ... " + e.toString());
-		} finally {
-			if (c != null) {
-				c.close();
-			}
-			if (c2 != null) {
-				c2.close();
-			}
-		}
-
-		if (update) {
-			getUpdates(result);
-		}
-
-		// We'll say an application has updates if it's installed AND the
-		// installed version is not the 'current' one AND the installed
-		// version is older than the current one.
-		for (App app : result) {
-			Apk curver = app.getCurrentVersion();
-			if (curver != null && app.installedVersion != null
-					&& !app.installedVersion.equals(curver.version)) {
-				if (app.installedVerCode < curver.vercode)
-					app.hasUpdates = true;
-			}
-		}
-
-		return result;
-	}
-
-	// Verify installed status against the system's package list.
-	private void getUpdates(Vector<DB.App> apps) {
-		List<PackageInfo> installedPackages = mPm.getInstalledPackages(0);
-		Map<String, PackageInfo> systemApks = new HashMap<String, PackageInfo>();
-		Log.d("FDroid", "Reading installed packages");
-		for (PackageInfo appInfo : installedPackages) {
-			systemApks.put(appInfo.packageName, appInfo);
-		}
-
-		for (DB.App app : apps) {
-			if (systemApks.containsKey(app.id)) {
-				PackageInfo sysapk = systemApks.get(app.id);
-				String version = sysapk.versionName;
-				int vercode = sysapk.versionCode;
-				if (app.installedVersion == null
-						|| !app.installedVersion.equals(version)) {
-					setInstalledVersion(app.id, version, vercode);
-					app.installedVersion = version;
-				}
-			} else {
-				if (app.installedVersion != null) {
-					setInstalledVersion(app.id, null, 0);
-					app.installedVersion = null;
-				}
-			}
-		}
-	}
-
-	private Vector<App> updateApps = null;
-
-	// Called before a repo update starts.
-	public void beginUpdate() {
-		// Get a list of all apps. All the apps and apks in this list will
-		// have 'updated' set to false at this point, and we will only set
-		// it to true when we see the app/apk in a repository. Thus, at the
-		// end, any that are still false can be removed.
-		// TODO: Need to ensure that UI and UpdateService can't both be doing
-		// an update at the same time.
-		updateApps = getApps(null, null, true);
-		Log.d("FDroid", "AppUpdate: " + updateApps.size()
-				+ " apps before starting.");
-	}
-
-	// Called when a repo update ends. Any applications that have not been
-	// updated (by a call to updateApplication) are assumed to be no longer
-	// in the repos.
-	public void endUpdate() {
-		if (updateApps == null)
-			return;
-		for (App app : updateApps) {
-			if (!app.updated) {
-				// The application hasn't been updated, so it's no longer
-				// in the repos.
-				Log.d("FDroid", "AppUpdate: " + app.name
-						+ " is no longer in any repository - removing");
-				db.delete(TABLE_APP, "id = ?", new String[] { app.id });
-				db.delete(TABLE_APK, "id = ?", new String[] { app.id });
-			} else {
-				for (Apk apk : app.apks) {
-					if (!apk.updated) {
-						// The package hasn't been updated, so this is a
-						// version that's no longer available.
-						Log.d("FDroid", "AppUpdate: Package " + apk.id + "/"
-								+ apk.version
-								+ " is no longer in any repository - removing");
-						db.delete(TABLE_APK, "id = ? and version = ?",
-								new String[] { app.id, apk.version });
-					}
-				}
-			}
-		}
-		Log.d("FDroid", "AppUpdate: " + updateApps.size()
-				+ " apps on completion.");
-		updateApps = null;
-		return;
-	}
-
-	// Called during update to supply new details for an application (or
-	// details of a completely new one). Calls to this must be wrapped by
-	// a call to beginUpdate and a call to endUpdate.
-	public void updateApplication(App upapp) {
-
-		if (updateApps == null) {
-			return;
-		}
-
-		boolean found = false;
-		for (App app : updateApps) {
-			if (app.id.equals(upapp.id)) {
-				Log.d("FDroid", "AppUpdate: " + app.id
-						+ " is already in the database.");
-				updateAppIfDifferent(app, upapp);
-				app.updated = true;
-				found = true;
-				for (Apk upapk : upapp.apks) {
-					boolean afound = false;
-					for (Apk apk : app.apks) {
-						if (apk.version.equals(upapk.version)) {
-							Log.d("FDroid", "AppUpdate: " + apk.version
-									+ " is a known version.");
-							updateApkIfDifferent(apk, upapk);
-							apk.updated = true;
-							afound = true;
-							break;
-						}
-					}
-					if (!afound) {
-						// A new version of this application.
-						Log.d("FDroid", "AppUpdate: " + upapk.version
-								+ " is a new version.");
-						updateApkIfDifferent(null, upapk);
-						upapk.updated = true;
-						app.apks.add(upapk);
-					}
-				}
-				break;
-			}
-		}
-		if (!found) {
-			// It's a brand new application...
-			Log
-					.d("FDroid", "AppUpdate: " + upapp.id
-							+ " is a new application.");
-			updateAppIfDifferent(null, upapp);
-			for (Apk upapk : upapp.apks) {
-				updateApkIfDifferent(null, upapk);
-				upapk.updated = true;
-			}
-			upapp.updated = true;
-			updateApps.add(upapp);
-		}
-
-	}
-
-	// Update application details in the database, if different to the
-	// previous ones.
-	// 'oldapp' - previous details - i.e. what's in the database.
-	// If null, this app is not in the database at all and
-	// should be added.
-	// 'upapp' - updated details
-	private void updateAppIfDifferent(App oldapp, App upapp) {
-		ContentValues values = new ContentValues();
-		values.put("id", upapp.id);
-		values.put("name", upapp.name);
-		values.put("summary", upapp.summary);
-		values.put("icon", upapp.icon);
-		values.put("description", upapp.description);
-		values.put("license", upapp.license);
-		values.put("webURL", upapp.webURL);
-		values.put("trackerURL", upapp.trackerURL);
-		values.put("sourceURL", upapp.sourceURL);
-		values.put("installedVersion", upapp.installedVersion);
-		values.put("installedVerCode", upapp.installedVerCode);
-		values.put("marketVersion", upapp.marketVersion);
-		values.put("marketVercode", upapp.marketVercode);
-		values.put("antiFeatures", upapp.antiFeatures);
-		values.put("hasUpdates", upapp.hasUpdates ? 1 : 0);
-		if (oldapp != null) {
-			db.update(TABLE_APP, values, "id = ?", new String[] { oldapp.id });
-		} else {
-			db.insert(TABLE_APP, null, values);
-		}
-	}
-
-	// Update apk details in the database, if different to the
-	// previous ones.
-	// 'oldapk' - previous details - i.e. what's in the database.
-	// If null, this apk is not in the database at all and
-	// should be added.
-	// 'upapk' - updated details
-	private void updateApkIfDifferent(Apk oldapk, Apk upapk) {
-		ContentValues values = new ContentValues();
-		values.put("id", upapk.id);
-		values.put("version", upapk.version);
-		values.put("vercode", upapk.vercode);
-		values.put("server", upapk.server);
-		values.put("hash", upapk.hash);
-		values.put("size", upapk.size);
-		values.put("apkName", upapk.apkName);
-		values.put("apkSource", upapk.apkSource);
-		if (oldapk != null) {
-			db.update(TABLE_APK, values, "id = ? and version =?", new String[] {
-					oldapk.id, oldapk.version });
-		} else {
-			db.insert(TABLE_APK, null, values);
-		}
-	}
-
-	public void setInstalledVersion(String id, String version, int vercode) {
-		ContentValues values = new ContentValues();
-		values.put("installedVersion", version);
-		values.put("installedVerCode", vercode);
-		db.update(TABLE_APP, values, "id = ?", new String[] { id });
-	}
-
-	// Get a list of the configured repositories.
-	public Vector<Repo> getRepos() {
-		Vector<Repo> repos = new Vector<Repo>();
-		Cursor c = null;
-		try {
-			c = db.rawQuery("select address, inuse, priority from "
-					+ TABLE_REPO + " order by priority", null);
-			c.moveToFirst();
-			while (!c.isAfterLast()) {
-				Repo repo = new Repo();
-				repo.address = c.getString(0);
-				repo.inuse = (c.getInt(1) == 1);
-				repo.priority = c.getInt(2);
-				repos.add(repo);
-				c.moveToNext();
-			}
-		} catch (Exception e) {
-		} finally {
-			if (c != null) {
-				c.close();
-			}
-		}
-		return repos;
-	}
-
-	public void changeServerStatus(String address) {
-		db.rawQuery("update " + TABLE_REPO
-				+ " set inuse=1-inuse where address= ?",
-				new String[] { address });
-	}
-
-	public void addServer(String address, int priority) {
-		ContentValues values = new ContentValues();
-		values.put("address", address);
-		values.put("inuse", 1);
-		values.put("priority", priority);
-		db.insert(TABLE_REPO, null, values);
-	}
-
-	public void removeServers(Vector<String> addresses) {
-		for (String address : addresses) {
-			db.delete(TABLE_REPO, "address = ?", new String[] { address });
-		}
-	}
+    private static final String DATABASE_NAME = "fdroid";
+
+    private SQLiteDatabase db;
+
+    // The TABLE_APP table stores details of all the applications we know about.
+    // This information is retrieved from the repositories.
+    private static final String TABLE_APP = "fdroid_app";
+    private static final String CREATE_TABLE_APP = "create table " + TABLE_APP
+            + " ( " + "id text not null, " + "name text not null, "
+            + "summary text not null, " + "icon text, "
+            + "description text not null, " + "license text not null, "
+            + "webURL text, " + "trackerURL text, " + "sourceURL text, "
+            + "installedVersion text," + "hasUpdates int not null,"
+            + "primary key(id));";
+
+    public static class App {
+
+        public App() {
+            name = "Unknown";
+            summary = "Unknown application";
+            icon = "noicon.png";
+            id = "unknown";
+            license = "Unknown";
+            trackerURL = "";
+            sourceURL = "";
+            webURL = "";
+            antiFeatures = null;
+            hasUpdates = false;
+            updated = false;
+            apks = new Vector<Apk>();
+        }
+
+        public String id;
+        public String name;
+        public String summary;
+        public String icon;
+        public String description;
+        public String license;
+        public String webURL;
+        public String trackerURL;
+        public String sourceURL;
+        public String installedVersion;
+        public int installedVerCode;
+        public String marketVersion;
+        public int marketVercode;
+
+        // Comma-separated list of anti-features (as defined in the metadata
+        // documentation) or null if there aren't any.
+        public String antiFeatures;
+
+        // True if there are new versions (apks) that the user hasn't
+        // explicitly ignored. (We're currently not using the database
+        // field for this - we make the decision on the fly in getApps().
+        public boolean hasUpdates;
+
+        // Used internally for tracking during repo updates.
+        public boolean updated;
+
+        public Vector<Apk> apks;
+
+        // Get the current version - this will be one of the Apks from 'apks'.
+        // Can return null if there are no available versions.
+        // This should be the 'current' version, as in the most recent stable
+        // one, that most users would want by default. It might not be the
+        // most recent, if for example there are betas etc.
+        public Apk getCurrentVersion() {
+
+            // Try and return the version that's in Google's market first...
+            if (marketVersion != null && marketVercode > 0) {
+                for (Apk apk : apks) {
+                    if (apk.vercode == marketVercode)
+                        return apk;
+                }
+            }
+
+            // If we don't know the market version, or we don't have it, we
+            // return the most recent version we have...
+            int latestcode = -1;
+            Apk latestapk = null;
+            for (Apk apk : apks) {
+                if (apk.vercode > latestcode) {
+                    latestapk = apk;
+                    latestcode = apk.vercode;
+                }
+            }
+            return latestapk;
+        }
+
+    }
+
+    // The TABLE_APK table stores details of all the application versions we
+    // know about. Each relates directly back to an entry in TABLE_APP.
+    // This information is retrieved from the repositories.
+    private static final String TABLE_APK = "fdroid_apk";
+    private static final String CREATE_TABLE_APK = "create table " + TABLE_APK
+            + " ( " + "id text not null, " + "version text not null, "
+            + "server text not null, " + "hash text not null, "
+            + "vercode int not null," + "apkName text not null, "
+            + "size int not null," + "primary key(id,version));";
+
+    public static class Apk {
+
+        public Apk() {
+            updated = false;
+            size = 0;
+            apkSource = null;
+        }
+
+        public String id;
+        public String version;
+        public int vercode;
+        public int size; // Size in bytes - 0 means we don't know!
+        public String server;
+        public String hash;
+        public String apkName;
+
+        // If null, the apk comes from the same server as the repo index.
+        // Otherwise
+        // this is the complete URL to download the apk from.
+        public String apkSource;
+
+        // Used internally for tracking during repo updates.
+        public boolean updated;
+
+        public String getURL() {
+            String path = apkName.replace(" ", "%20");
+            return server + "/" + path;
+        }
+    }
+
+    // The TABLE_REPO table stores the details of the repositories in use.
+    private static final String TABLE_REPO = "fdroid_repo";
+    private static final String CREATE_TABLE_REPO = "create table "
+            + TABLE_REPO + " (" + "address text primary key, "
+            + "inuse integer not null, " + "priority integer not null);";
+
+    public static class Repo {
+        public String address;
+        public boolean inuse;
+        public int priority;
+    }
+
+    // SQL to update the database to versions beyond the first. Here is
+    // how the database works:
+    //
+    // * The SQL to create the database tables always creates version
+    // 1. This SQL will never be altered.
+    // * In the array below there is SQL for each subsequent version
+    // from 2 onwards.
+    // * For a new install, the database is always initialised to version
+    // 1.
+    // * Then, whether it's a new install or not, all the upgrade SQL in
+    // the array below is executed in order to bring the database up to
+    // the latest version.
+    // * The current version is tracked by an entry in the TABLE_VERSION
+    // table.
+    //
+    private static final String[][] DB_UPGRADES = {
+
+    // Version 2...
+            { "alter table " + TABLE_APP + " add marketVersion text",
+                    "alter table " + TABLE_APP + " add marketVercode integer" },
+
+            // Version 3...
+            { "alter table " + TABLE_APK + " add apkSource text" },
+
+            // Version 4...
+            { "alter table " + TABLE_APP + " add installedVerCode integer" },
+
+            // Version 5...
+            { "alter table " + TABLE_APP + " add antiFeatures string" }
+
+    };
+
+    private class DBHelper extends SQLiteOpenHelper {
+
+        public DBHelper(Context context) {
+            super(context, DATABASE_NAME, null, DB_UPGRADES.length + 1);
+        }
+
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            db.execSQL(CREATE_TABLE_REPO);
+            db.execSQL(CREATE_TABLE_APP);
+            db.execSQL(CREATE_TABLE_APK);
+            ContentValues values = new ContentValues();
+            values.put("address", "http://f-droid.org/repo");
+            values.put("inuse", 1);
+            values.put("priority", 10);
+            db.insert(TABLE_REPO, null, values);
+            onUpgrade(db, 1, DB_UPGRADES.length + 1);
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            for (int v = oldVersion + 1; v <= newVersion; v++)
+                for (int i = 0; i < DB_UPGRADES[v - 2].length; i++)
+                    db.execSQL(DB_UPGRADES[v - 2][i]);
+        }
+
+    }
+
+    public static String getIconsPath() {
+        return "/sdcard/.fdroid/icons/";
+    }
+
+    private PackageManager mPm;
+
+    public DB(Context ctx) {
+
+        DBHelper h = new DBHelper(ctx);
+        db = h.getWritableDatabase();
+        mPm = ctx.getPackageManager();
+    }
+
+    public void close() {
+        db.close();
+        db = null;
+    }
+
+    // Delete the database, which should cause it to be re-created next time
+    // it's used.
+    public static void delete(Context ctx) {
+        try {
+            ctx.deleteDatabase(DATABASE_NAME);
+            // Also try and delete the old one, from versions 0.13 and earlier.
+            ctx.deleteDatabase("fdroid_db");
+        } catch (Exception ex) {
+            Log.d("FDroid", "Exception in DB.delete: " + ex.getMessage());
+        }
+    }
+
+    // Get the number of apps that have updates available.
+    public int getNumUpdates() {
+        Vector<App> apps = getApps(null, null, false);
+        int count = 0;
+        for (App app : apps) {
+            if (app.hasUpdates)
+                count++;
+        }
+        return count;
+    }
+
+    // Return a list of apps matching the given criteria.
+    // 'appid' - specific app id to retrieve, or null
+    // 'filter' - search text to filter on, or null
+    // 'update' - update installed version information from device, rather than
+    // simply using values cached in the database. Slower.
+    public Vector<App> getApps(String appid, String filter, boolean update) {
+        Vector<App> result = new Vector<App>();
+        Cursor c = null;
+        Cursor c2 = null;
+        try {
+
+            String query = "select * from " + TABLE_APP;
+            if (appid != null) {
+                query += " where id = '" + appid + "'";
+            } else if (filter != null) {
+                query += " where name like '%" + filter + "%'"
+                        + " or description like '%" + filter + "%'";
+            }
+            query += " order by name collate nocase";
+
+            c = db.rawQuery(query, null);
+            c.moveToFirst();
+            while (!c.isAfterLast()) {
+
+                App app = new App();
+                app.id = c.getString(c.getColumnIndex("id"));
+                app.name = c.getString(c.getColumnIndex("name"));
+                app.summary = c.getString(c.getColumnIndex("summary"));
+                app.icon = c.getString(c.getColumnIndex("icon"));
+                app.description = c.getString(c.getColumnIndex("description"));
+                app.license = c.getString(c.getColumnIndex("license"));
+                app.webURL = c.getString(c.getColumnIndex("webURL"));
+                app.trackerURL = c.getString(c.getColumnIndex("trackerURL"));
+                app.sourceURL = c.getString(c.getColumnIndex("sourceURL"));
+                app.installedVersion = c.getString(c
+                        .getColumnIndex("installedVersion"));
+                app.installedVerCode = c.getInt(c
+                        .getColumnIndex("installedVerCode"));
+                app.marketVersion = c.getString(c
+                        .getColumnIndex("marketVersion"));
+                app.marketVercode = c.getInt(c.getColumnIndex("marketVercode"));
+                app.antiFeatures = c
+                        .getString(c.getColumnIndex("antiFeatures"));
+                app.hasUpdates = false;
+
+                c2 = db.rawQuery("select * from " + TABLE_APK
+                        + " where id = ? order by vercode desc",
+                        new String[] { app.id });
+                c2.moveToFirst();
+                while (!c2.isAfterLast()) {
+                    Apk apk = new Apk();
+                    apk.id = app.id;
+                    apk.version = c2.getString(c2.getColumnIndex("version"));
+                    apk.vercode = c2.getInt(c2.getColumnIndex("vercode"));
+                    apk.server = c2.getString(c2.getColumnIndex("server"));
+                    apk.hash = c2.getString(c2.getColumnIndex("hash"));
+                    apk.size = c2.getInt(c2.getColumnIndex("size"));
+                    apk.apkName = c2.getString(c2.getColumnIndex("apkName"));
+                    apk.apkSource = c2
+                            .getString(c2.getColumnIndex("apkSource"));
+                    app.apks.add(apk);
+                    c2.moveToNext();
+                }
+                c2.close();
+
+                result.add(app);
+                c.moveToNext();
+            }
+
+        } catch (Exception e) {
+            Log.d("FDroid", "Exception during database reading - "
+                    + e.getMessage() + " ... " + e.toString());
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+            if (c2 != null) {
+                c2.close();
+            }
+        }
+
+        if (update) {
+            getUpdates(result);
+        }
+
+        // We'll say an application has updates if it's installed AND the
+        // installed version is not the 'current' one AND the installed
+        // version is older than the current one.
+        for (App app : result) {
+            Apk curver = app.getCurrentVersion();
+            if (curver != null && app.installedVersion != null
+                    && !app.installedVersion.equals(curver.version)) {
+                if (app.installedVerCode < curver.vercode)
+                    app.hasUpdates = true;
+            }
+        }
+
+        return result;
+    }
+
+    // Verify installed status against the system's package list.
+    private void getUpdates(Vector<DB.App> apps) {
+        List<PackageInfo> installedPackages = mPm.getInstalledPackages(0);
+        Map<String, PackageInfo> systemApks = new HashMap<String, PackageInfo>();
+        Log.d("FDroid", "Reading installed packages");
+        for (PackageInfo appInfo : installedPackages) {
+            systemApks.put(appInfo.packageName, appInfo);
+        }
+
+        for (DB.App app : apps) {
+            if (systemApks.containsKey(app.id)) {
+                PackageInfo sysapk = systemApks.get(app.id);
+                String version = sysapk.versionName;
+                int vercode = sysapk.versionCode;
+                if (app.installedVersion == null
+                        || !app.installedVersion.equals(version)) {
+                    setInstalledVersion(app.id, version, vercode);
+                    app.installedVersion = version;
+                }
+            } else {
+                if (app.installedVersion != null) {
+                    setInstalledVersion(app.id, null, 0);
+                    app.installedVersion = null;
+                }
+            }
+        }
+    }
+
+    private Vector<App> updateApps = null;
+
+    // Called before a repo update starts.
+    public void beginUpdate() {
+        // Get a list of all apps. All the apps and apks in this list will
+        // have 'updated' set to false at this point, and we will only set
+        // it to true when we see the app/apk in a repository. Thus, at the
+        // end, any that are still false can be removed.
+        // TODO: Need to ensure that UI and UpdateService can't both be doing
+        // an update at the same time.
+        updateApps = getApps(null, null, true);
+        Log.d("FDroid", "AppUpdate: " + updateApps.size()
+                + " apps before starting.");
+    }
+
+    // Called when a repo update ends. Any applications that have not been
+    // updated (by a call to updateApplication) are assumed to be no longer
+    // in the repos.
+    public void endUpdate() {
+        if (updateApps == null)
+            return;
+        for (App app : updateApps) {
+            if (!app.updated) {
+                // The application hasn't been updated, so it's no longer
+                // in the repos.
+                Log.d("FDroid", "AppUpdate: " + app.name
+                        + " is no longer in any repository - removing");
+                db.delete(TABLE_APP, "id = ?", new String[] { app.id });
+                db.delete(TABLE_APK, "id = ?", new String[] { app.id });
+            } else {
+                for (Apk apk : app.apks) {
+                    if (!apk.updated) {
+                        // The package hasn't been updated, so this is a
+                        // version that's no longer available.
+                        Log.d("FDroid", "AppUpdate: Package " + apk.id + "/"
+                                + apk.version
+                                + " is no longer in any repository - removing");
+                        db.delete(TABLE_APK, "id = ? and version = ?",
+                                new String[] { app.id, apk.version });
+                    }
+                }
+            }
+        }
+        Log.d("FDroid", "AppUpdate: " + updateApps.size()
+                + " apps on completion.");
+        updateApps = null;
+        return;
+    }
+
+    // Called during update to supply new details for an application (or
+    // details of a completely new one). Calls to this must be wrapped by
+    // a call to beginUpdate and a call to endUpdate.
+    public void updateApplication(App upapp) {
+
+        if (updateApps == null) {
+            return;
+        }
+
+        boolean found = false;
+        for (App app : updateApps) {
+            if (app.id.equals(upapp.id)) {
+                Log.d("FDroid", "AppUpdate: " + app.id
+                        + " is already in the database.");
+                updateAppIfDifferent(app, upapp);
+                app.updated = true;
+                found = true;
+                for (Apk upapk : upapp.apks) {
+                    boolean afound = false;
+                    for (Apk apk : app.apks) {
+                        if (apk.version.equals(upapk.version)) {
+                            Log.d("FDroid", "AppUpdate: " + apk.version
+                                    + " is a known version.");
+                            updateApkIfDifferent(apk, upapk);
+                            apk.updated = true;
+                            afound = true;
+                            break;
+                        }
+                    }
+                    if (!afound) {
+                        // A new version of this application.
+                        Log.d("FDroid", "AppUpdate: " + upapk.version
+                                + " is a new version.");
+                        updateApkIfDifferent(null, upapk);
+                        upapk.updated = true;
+                        app.apks.add(upapk);
+                    }
+                }
+                break;
+            }
+        }
+        if (!found) {
+            // It's a brand new application...
+            Log
+                    .d("FDroid", "AppUpdate: " + upapp.id
+                            + " is a new application.");
+            updateAppIfDifferent(null, upapp);
+            for (Apk upapk : upapp.apks) {
+                updateApkIfDifferent(null, upapk);
+                upapk.updated = true;
+            }
+            upapp.updated = true;
+            updateApps.add(upapp);
+        }
+
+    }
+
+    // Update application details in the database, if different to the
+    // previous ones.
+    // 'oldapp' - previous details - i.e. what's in the database.
+    // If null, this app is not in the database at all and
+    // should be added.
+    // 'upapp' - updated details
+    private void updateAppIfDifferent(App oldapp, App upapp) {
+        ContentValues values = new ContentValues();
+        values.put("id", upapp.id);
+        values.put("name", upapp.name);
+        values.put("summary", upapp.summary);
+        values.put("icon", upapp.icon);
+        values.put("description", upapp.description);
+        values.put("license", upapp.license);
+        values.put("webURL", upapp.webURL);
+        values.put("trackerURL", upapp.trackerURL);
+        values.put("sourceURL", upapp.sourceURL);
+        values.put("installedVersion", upapp.installedVersion);
+        values.put("installedVerCode", upapp.installedVerCode);
+        values.put("marketVersion", upapp.marketVersion);
+        values.put("marketVercode", upapp.marketVercode);
+        values.put("antiFeatures", upapp.antiFeatures);
+        values.put("hasUpdates", upapp.hasUpdates ? 1 : 0);
+        if (oldapp != null) {
+            db.update(TABLE_APP, values, "id = ?", new String[] { oldapp.id });
+        } else {
+            db.insert(TABLE_APP, null, values);
+        }
+    }
+
+    // Update apk details in the database, if different to the
+    // previous ones.
+    // 'oldapk' - previous details - i.e. what's in the database.
+    // If null, this apk is not in the database at all and
+    // should be added.
+    // 'upapk' - updated details
+    private void updateApkIfDifferent(Apk oldapk, Apk upapk) {
+        ContentValues values = new ContentValues();
+        values.put("id", upapk.id);
+        values.put("version", upapk.version);
+        values.put("vercode", upapk.vercode);
+        values.put("server", upapk.server);
+        values.put("hash", upapk.hash);
+        values.put("size", upapk.size);
+        values.put("apkName", upapk.apkName);
+        values.put("apkSource", upapk.apkSource);
+        if (oldapk != null) {
+            db.update(TABLE_APK, values, "id = ? and version =?", new String[] {
+                    oldapk.id, oldapk.version });
+        } else {
+            db.insert(TABLE_APK, null, values);
+        }
+    }
+
+    public void setInstalledVersion(String id, String version, int vercode) {
+        ContentValues values = new ContentValues();
+        values.put("installedVersion", version);
+        values.put("installedVerCode", vercode);
+        db.update(TABLE_APP, values, "id = ?", new String[] { id });
+    }
+
+    // Get a list of the configured repositories.
+    public Vector<Repo> getRepos() {
+        Vector<Repo> repos = new Vector<Repo>();
+        Cursor c = null;
+        try {
+            c = db.rawQuery("select address, inuse, priority from "
+                    + TABLE_REPO + " order by priority", null);
+            c.moveToFirst();
+            while (!c.isAfterLast()) {
+                Repo repo = new Repo();
+                repo.address = c.getString(0);
+                repo.inuse = (c.getInt(1) == 1);
+                repo.priority = c.getInt(2);
+                repos.add(repo);
+                c.moveToNext();
+            }
+        } catch (Exception e) {
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+        return repos;
+    }
+
+    public void changeServerStatus(String address) {
+        db.rawQuery("update " + TABLE_REPO
+                + " set inuse=1-inuse where address= ?",
+                new String[] { address });
+    }
+
+    public void addServer(String address, int priority) {
+        ContentValues values = new ContentValues();
+        values.put("address", address);
+        values.put("inuse", 1);
+        values.put("priority", priority);
+        db.insert(TABLE_REPO, null, values);
+    }
+
+    public void removeServers(Vector<String> addresses) {
+        for (String address : addresses) {
+            db.delete(TABLE_REPO, "address = ?", new String[] { address });
+        }
+    }
 }
diff --git a/src/org/fdroid/fdroid/FDroid.java b/src/org/fdroid/fdroid/FDroid.java
index 7972ebc6e..36934d2ac 100644
--- a/src/org/fdroid/fdroid/FDroid.java
+++ b/src/org/fdroid/fdroid/FDroid.java
@@ -60,423 +60,423 @@ import android.widget.TabHost.TabSpec;
 
 public class FDroid extends TabActivity implements OnItemClickListener {
 
-	private class AppListAdapter extends BaseAdapter {
-
-		private List<DB.App> items = new ArrayList<DB.App>();
-
-		public AppListAdapter(Context context) {
-		}
-
-		public void addItem(DB.App app) {
-			items.add(app);
-		}
+    private class AppListAdapter extends BaseAdapter {
+
+        private List<DB.App> items = new ArrayList<DB.App>();
+
+        public AppListAdapter(Context context) {
+        }
+
+        public void addItem(DB.App app) {
+            items.add(app);
+        }
 
-		public void clear() {
-			items.clear();
-		}
+        public void clear() {
+            items.clear();
+        }
 
-		@Override
-		public int getCount() {
-			return items.size();
-		}
+        @Override
+        public int getCount() {
+            return items.size();
+        }
 
-		@Override
-		public Object getItem(int position) {
-			return items.get(position);
-		}
+        @Override
+        public Object getItem(int position) {
+            return items.get(position);
+        }
 
-		@Override
-		public long getItemId(int position) {
-			return position;
-		}
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
 
-		@Override
-		public View getView(int position, View convertView, ViewGroup parent) {
-			View v = convertView;
-			if (v == null) {
-				LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-				v = vi.inflate(R.layout.applistitem, null);
-			}
-			DB.App app = items.get(position);
-
-			TextView name = (TextView) v.findViewById(R.id.name);
-			name.setText(app.name);
-
-			String vs;
-			int numav = app.apks.size();
-			if (numav == 1)
-				vs = getString(R.string.n_version_available);
-			else
-				vs = getString(R.string.n_versions_available);
-			TextView status = (TextView) v.findViewById(R.id.status);
-			status.setText(String.format(vs, numav));
-
-			TextView license = (TextView) v.findViewById(R.id.license);
-			license.setText(app.license);
-
-			TextView summary = (TextView) v.findViewById(R.id.summary);
-			summary.setText(app.summary);
-
-			ImageView icon = (ImageView) v.findViewById(R.id.icon);
-			String iconpath = new String(DB.getIconsPath() + app.icon);
-			File icn = new File(iconpath);
-			if (icn.exists() && icn.length() > 0) {
-				new Uri.Builder().build();
-				icon.setImageURI(Uri.parse(iconpath));
-			} else {
-				icon.setImageResource(android.R.drawable.sym_def_app_icon);
-			}
-
-			return v;
-		}
-	}
-
-	private String LOCAL_PATH = "/sdcard/.fdroid";
-
-	private static final int REQUEST_APPDETAILS = 0;
-	private static final int REQUEST_MANAGEREPOS = 1;
-	private static final int REQUEST_PREFS = 2;
-
-	private static final int UPDATE_REPO = Menu.FIRST;
-	private static final int MANAGE_REPO = Menu.FIRST + 1;
-	private static final int PREFERENCES = Menu.FIRST + 2;
-	private static final int ABOUT = Menu.FIRST + 3;
-
-	private DB db = null;
-
-	// Apps that are available to be installed
-	private AppListAdapter apps_av = new AppListAdapter(this);
-
-	// Apps that are installed
-	private AppListAdapter apps_in = new AppListAdapter(this);
-
-	// Apps that can be upgraded
-	private AppListAdapter apps_up = new AppListAdapter(this);
-
-	private ProgressDialog pd;
-
-	private static final String TAB_IN = "INST";
-	private static final String TAB_UN = "UNIN";
-	private static final String TAB_UP = "UPDT";
-	private TabHost tabHost;
-	private TabSpec ts;
-	private TabSpec ts1;
-	private TabSpec tsUp;
-
-	private boolean triedEmptyUpdate;
-
-	@Override
-	protected void onCreate(Bundle savedInstanceState) {
-
-		super.onCreate(savedInstanceState);
-
-		setContentView(R.layout.fdroid);
-
-		File local_path = new File(LOCAL_PATH);
-		if (!local_path.exists())
-			local_path.mkdir();
-
-		File icon_path = new File(DB.getIconsPath());
-		if (!icon_path.exists())
-			icon_path.mkdir();
-
-		tabHost = getTabHost();
-		createTabs();
-
-		Intent i = getIntent();
-		if (i.hasExtra("uri")) {
-			Intent call = new Intent(this, ManageRepo.class);
-			call.putExtra("uri", i.getStringExtra("uri"));
-			startActivityForResult(call, REQUEST_MANAGEREPOS);
-		}
-
-	}
-
-	@Override
-	protected void onStart() {
-		super.onStart();
-		((FDroidApp) getApplication()).inActivity++;
-		db = new DB(this);
-		triedEmptyUpdate = false;
-		populateLists(true);
-	}
-
-	@Override
-	protected void onStop() {
-		db.close();
-		((FDroidApp) getApplication()).inActivity--;
-		super.onStop();
-	}
-
-	@Override
-	public boolean onCreateOptionsMenu(Menu menu) {
-
-		super.onCreateOptionsMenu(menu);
-		menu.add(Menu.NONE, UPDATE_REPO, 1, R.string.menu_update_repo).setIcon(
-				android.R.drawable.ic_menu_rotate);
-		menu.add(Menu.NONE, MANAGE_REPO, 2, R.string.menu_manage).setIcon(
-				android.R.drawable.ic_menu_agenda);
-		menu.add(Menu.NONE, PREFERENCES, 3, R.string.menu_preferences).setIcon(
-				android.R.drawable.ic_menu_preferences);
-		menu.add(Menu.NONE, ABOUT, 4, R.string.menu_about).setIcon(
-				android.R.drawable.ic_menu_help);
-		return true;
-	}
-
-	@Override
-	public boolean onOptionsItemSelected(MenuItem item) {
-
-		switch (item.getItemId()) {
-
-		case UPDATE_REPO:
-			updateRepos();
-			return true;
-
-		case MANAGE_REPO:
-			Intent i = new Intent(this, ManageRepo.class);
-			startActivityForResult(i, REQUEST_MANAGEREPOS);
-			return true;
-
-		case PREFERENCES:
-			Intent prefs = new Intent(getBaseContext(), Preferences.class);
-			startActivityForResult(prefs, REQUEST_PREFS);
-			return true;
-
-		case ABOUT:
-			LayoutInflater li = LayoutInflater.from(this);
-			View view = li.inflate(R.layout.about, null);
-
-			// Fill in the version...
-			TextView tv = (TextView) view.findViewById(R.id.version);
-			PackageManager pm = getPackageManager();
-			PackageInfo pi;
-			try {
-				pi = pm.getPackageInfo(
-						getApplicationContext().getPackageName(), 0);
-				tv.setText(pi.versionName);
-			} catch (Exception e) {
-			}
-
-			Builder p = new AlertDialog.Builder(this).setView(view);
-			final AlertDialog alrt = p.create();
-			alrt.setIcon(R.drawable.icon);
-			alrt.setTitle(getString(R.string.about_title));
-			alrt.setButton(AlertDialog.BUTTON_NEUTRAL,
-					getString(R.string.about_website),
-					new DialogInterface.OnClickListener() {
-						public void onClick(DialogInterface dialog,
-								int whichButton) {
-							Uri uri = Uri.parse("http://f-droid.org");
-							startActivity(new Intent(Intent.ACTION_VIEW, uri));
-						}
-					});
-			alrt.setButton(AlertDialog.BUTTON_NEGATIVE, getString(R.string.ok),
-					new DialogInterface.OnClickListener() {
-						public void onClick(DialogInterface dialog,
-								int whichButton) {
-						}
-					});
-			alrt.show();
-			return true;
-		}
-		return super.onOptionsItemSelected(item);
-	}
-
-	@Override
-	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-
-		switch (requestCode) {
-		case REQUEST_APPDETAILS:
-			break;
-		case REQUEST_MANAGEREPOS:
-			if (data.hasExtra("update")) {
-				AlertDialog.Builder ask_alrt = new AlertDialog.Builder(this);
-				ask_alrt.setTitle(getString(R.string.repo_update_title));
-				ask_alrt.setIcon(android.R.drawable.ic_menu_rotate);
-				ask_alrt.setMessage(getString(R.string.repo_alrt));
-				ask_alrt.setPositiveButton(getString(R.string.yes),
-						new DialogInterface.OnClickListener() {
-							public void onClick(DialogInterface dialog,
-									int whichButton) {
-								updateRepos();
-							}
-						});
-				ask_alrt.setNegativeButton(getString(R.string.no),
-						new DialogInterface.OnClickListener() {
-							public void onClick(DialogInterface dialog,
-									int whichButton) {
-								return;
-							}
-						});
-				AlertDialog alert = ask_alrt.create();
-				alert.show();
-			}
-			break;
-		case REQUEST_PREFS:
-			// The automatic update settings may have changed, so reschedule (or
-			// unschedule) the
-			// service accordingly. It's cheap, so no need to check if the
-			// particular setting has
-			// actually been changed.
-			UpdateService.schedule(getBaseContext());
-			break;
-
-		}
-	}
-
-	private void createTabs() {
-		tabHost.clearAllTabs();
-
-		// TabContentFactory that can generate the appropriate list for each
-		// tab...
-		TabHost.TabContentFactory tf = new TabHost.TabContentFactory() {
-			@Override
-			public View createTabContent(String tag) {
-
-				AppListAdapter ad;
-				if (tag.equals(TAB_IN))
-					ad = apps_in;
-				else if (tag.equals(TAB_UP))
-					ad = apps_up;
-				else
-					ad = apps_av;
-
-				ListView lst = new ListView(FDroid.this);
-				lst.setOnItemClickListener(FDroid.this);
-				lst.setAdapter(ad);
-				return lst;
-			}
-		};
-
-		// Create the tab of installed apps...
-		ts = tabHost.newTabSpec(TAB_IN);
-		ts.setIndicator(getString(R.string.tab_installed), getResources()
-				.getDrawable(drawable.star_off));
-		ts.setContent(tf);
-
-		// Create the tab of apps with updates...
-		tsUp = tabHost.newTabSpec(TAB_UP);
-		tsUp.setIndicator(getString(R.string.tab_updates), getResources()
-				.getDrawable(drawable.star_on));
-		tsUp.setContent(tf);
-
-		// Create the tab of available apps...
-		ts1 = tabHost.newTabSpec(TAB_UN);
-		ts1.setIndicator(getString(R.string.tab_noninstalled), getResources()
-				.getDrawable(drawable.ic_input_add));
-		ts1.setContent(tf);
-
-		tabHost.addTab(ts1);
-		tabHost.addTab(ts);
-		tabHost.addTab(tsUp);
-
-	}
-
-	// Populate the lists.
-	// 'update' - true to update the installed status of the applications
-	// by asking the system.
-	private void populateLists(boolean update) {
-
-		apps_in.clear();
-		apps_av.clear();
-		apps_up.clear();
-
-		Vector<DB.App> apps = db.getApps(null, null, update);
-		if (apps.isEmpty()) {
-			// Don't attempt this more than once - we may have invalid
-			// repositories.
-			if (triedEmptyUpdate)
-				return;
-			// If there are no apps, update from the repos - it must be a
-			// new installation.
-			Log.d("FDroid", "Empty app list forces repo update");
-			updateRepos();
-			triedEmptyUpdate = true;
-			return;
-		}
-		Log.d("FDroid", "Updating lists - " + apps.size() + " apps in total");
-
-		for (DB.App app : apps) {
-			if (app.installedVersion == null) {
-				apps_av.addItem(app);
-			} else {
-				apps_in.addItem(app);
-				if (app.hasUpdates)
-					apps_up.addItem(app);
-			}
-		}
-
-		// Update the count on the 'Updates' tab to show the number available.
-		// This is quite unpleasant, but seems to be the only way to do it.
-		TextView uptext = (TextView) tabHost.getTabWidget().getChildAt(2)
-				.findViewById(android.R.id.title);
-		uptext.setText(getString(R.string.tab_updates) + " ("
-				+ Integer.toString(apps_up.getCount()) + ")");
-
-		// Tell the lists that the data behind the adapter has changed, so
-		// they can refresh...
-		apps_av.notifyDataSetChanged();
-		apps_in.notifyDataSetChanged();
-		apps_up.notifyDataSetChanged();
-
-	}
-
-	public boolean updateRepos() {
-		pd = ProgressDialog.show(this, getString(R.string.process_wait_title),
-				getString(R.string.process_update_msg), true);
-		pd.setIcon(android.R.drawable.ic_dialog_info);
-
-		// Check for connection first!
-		ConnectivityManager netstate = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
-		if (netstate.getNetworkInfo(1).getState() == NetworkInfo.State.CONNECTED
-				|| netstate.getNetworkInfo(0).getState() == NetworkInfo.State.CONNECTED) {
-			new Thread() {
-				public void run() {
-					RepoXMLHandler.doUpdates(FDroid.this, db);
-					update_handler.sendEmptyMessage(0);
-				}
-			}.start();
-			return true;
-		} else {
-			pd.dismiss();
-			Toast.makeText(FDroid.this, getString(R.string.connection_error),
-					Toast.LENGTH_LONG).show();
-			return false;
-		}
-	}
-
-	/*
-	 * Handlers for thread functions that need to access GUI
-	 */
-	private Handler update_handler = new Handler() {
-		@Override
-		public void handleMessage(Message msg) {
-			populateLists(true);
-			if (pd.isShowing())
-				pd.dismiss();
-		}
-	};
-
-	// Handler for a click on one of the items in an application list. Pops
-	// up a dialog that shows the details of the application and all its
-	// available versions, with buttons to allow installation etc.
-	public void onItemClick(AdapterView<?> arg0, View arg1, final int arg2,
-			long arg3) {
-
-		final DB.App app;
-		String curtab = tabHost.getCurrentTabTag();
-		if (curtab.equalsIgnoreCase(TAB_IN)) {
-			app = (DB.App) apps_in.getItem(arg2);
-		} else if (curtab.equalsIgnoreCase(TAB_UP)) {
-			app = (DB.App) apps_up.getItem(arg2);
-		} else {
-			app = (DB.App) apps_av.getItem(arg2);
-		}
-
-		Intent intent = new Intent(this, AppDetails.class);
-		intent.putExtra("appid", app.id);
-		startActivityForResult(intent, REQUEST_APPDETAILS);
-
-	}
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            View v = convertView;
+            if (v == null) {
+                LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+                v = vi.inflate(R.layout.applistitem, null);
+            }
+            DB.App app = items.get(position);
+
+            TextView name = (TextView) v.findViewById(R.id.name);
+            name.setText(app.name);
+
+            String vs;
+            int numav = app.apks.size();
+            if (numav == 1)
+                vs = getString(R.string.n_version_available);
+            else
+                vs = getString(R.string.n_versions_available);
+            TextView status = (TextView) v.findViewById(R.id.status);
+            status.setText(String.format(vs, numav));
+
+            TextView license = (TextView) v.findViewById(R.id.license);
+            license.setText(app.license);
+
+            TextView summary = (TextView) v.findViewById(R.id.summary);
+            summary.setText(app.summary);
+
+            ImageView icon = (ImageView) v.findViewById(R.id.icon);
+            String iconpath = new String(DB.getIconsPath() + app.icon);
+            File icn = new File(iconpath);
+            if (icn.exists() && icn.length() > 0) {
+                new Uri.Builder().build();
+                icon.setImageURI(Uri.parse(iconpath));
+            } else {
+                icon.setImageResource(android.R.drawable.sym_def_app_icon);
+            }
+
+            return v;
+        }
+    }
+
+    private String LOCAL_PATH = "/sdcard/.fdroid";
+
+    private static final int REQUEST_APPDETAILS = 0;
+    private static final int REQUEST_MANAGEREPOS = 1;
+    private static final int REQUEST_PREFS = 2;
+
+    private static final int UPDATE_REPO = Menu.FIRST;
+    private static final int MANAGE_REPO = Menu.FIRST + 1;
+    private static final int PREFERENCES = Menu.FIRST + 2;
+    private static final int ABOUT = Menu.FIRST + 3;
+
+    private DB db = null;
+
+    // Apps that are available to be installed
+    private AppListAdapter apps_av = new AppListAdapter(this);
+
+    // Apps that are installed
+    private AppListAdapter apps_in = new AppListAdapter(this);
+
+    // Apps that can be upgraded
+    private AppListAdapter apps_up = new AppListAdapter(this);
+
+    private ProgressDialog pd;
+
+    private static final String TAB_IN = "INST";
+    private static final String TAB_UN = "UNIN";
+    private static final String TAB_UP = "UPDT";
+    private TabHost tabHost;
+    private TabSpec ts;
+    private TabSpec ts1;
+    private TabSpec tsUp;
+
+    private boolean triedEmptyUpdate;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.fdroid);
+
+        File local_path = new File(LOCAL_PATH);
+        if (!local_path.exists())
+            local_path.mkdir();
+
+        File icon_path = new File(DB.getIconsPath());
+        if (!icon_path.exists())
+            icon_path.mkdir();
+
+        tabHost = getTabHost();
+        createTabs();
+
+        Intent i = getIntent();
+        if (i.hasExtra("uri")) {
+            Intent call = new Intent(this, ManageRepo.class);
+            call.putExtra("uri", i.getStringExtra("uri"));
+            startActivityForResult(call, REQUEST_MANAGEREPOS);
+        }
+
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        ((FDroidApp) getApplication()).inActivity++;
+        db = new DB(this);
+        triedEmptyUpdate = false;
+        populateLists(true);
+    }
+
+    @Override
+    protected void onStop() {
+        db.close();
+        ((FDroidApp) getApplication()).inActivity--;
+        super.onStop();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+
+        super.onCreateOptionsMenu(menu);
+        menu.add(Menu.NONE, UPDATE_REPO, 1, R.string.menu_update_repo).setIcon(
+                android.R.drawable.ic_menu_rotate);
+        menu.add(Menu.NONE, MANAGE_REPO, 2, R.string.menu_manage).setIcon(
+                android.R.drawable.ic_menu_agenda);
+        menu.add(Menu.NONE, PREFERENCES, 3, R.string.menu_preferences).setIcon(
+                android.R.drawable.ic_menu_preferences);
+        menu.add(Menu.NONE, ABOUT, 4, R.string.menu_about).setIcon(
+                android.R.drawable.ic_menu_help);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+
+        switch (item.getItemId()) {
+
+        case UPDATE_REPO:
+            updateRepos();
+            return true;
+
+        case MANAGE_REPO:
+            Intent i = new Intent(this, ManageRepo.class);
+            startActivityForResult(i, REQUEST_MANAGEREPOS);
+            return true;
+
+        case PREFERENCES:
+            Intent prefs = new Intent(getBaseContext(), Preferences.class);
+            startActivityForResult(prefs, REQUEST_PREFS);
+            return true;
+
+        case ABOUT:
+            LayoutInflater li = LayoutInflater.from(this);
+            View view = li.inflate(R.layout.about, null);
+
+            // Fill in the version...
+            TextView tv = (TextView) view.findViewById(R.id.version);
+            PackageManager pm = getPackageManager();
+            PackageInfo pi;
+            try {
+                pi = pm.getPackageInfo(
+                        getApplicationContext().getPackageName(), 0);
+                tv.setText(pi.versionName);
+            } catch (Exception e) {
+            }
+
+            Builder p = new AlertDialog.Builder(this).setView(view);
+            final AlertDialog alrt = p.create();
+            alrt.setIcon(R.drawable.icon);
+            alrt.setTitle(getString(R.string.about_title));
+            alrt.setButton(AlertDialog.BUTTON_NEUTRAL,
+                    getString(R.string.about_website),
+                    new DialogInterface.OnClickListener() {
+                        public void onClick(DialogInterface dialog,
+                                int whichButton) {
+                            Uri uri = Uri.parse("http://f-droid.org");
+                            startActivity(new Intent(Intent.ACTION_VIEW, uri));
+                        }
+                    });
+            alrt.setButton(AlertDialog.BUTTON_NEGATIVE, getString(R.string.ok),
+                    new DialogInterface.OnClickListener() {
+                        public void onClick(DialogInterface dialog,
+                                int whichButton) {
+                        }
+                    });
+            alrt.show();
+            return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+
+        switch (requestCode) {
+        case REQUEST_APPDETAILS:
+            break;
+        case REQUEST_MANAGEREPOS:
+            if (data.hasExtra("update")) {
+                AlertDialog.Builder ask_alrt = new AlertDialog.Builder(this);
+                ask_alrt.setTitle(getString(R.string.repo_update_title));
+                ask_alrt.setIcon(android.R.drawable.ic_menu_rotate);
+                ask_alrt.setMessage(getString(R.string.repo_alrt));
+                ask_alrt.setPositiveButton(getString(R.string.yes),
+                        new DialogInterface.OnClickListener() {
+                            public void onClick(DialogInterface dialog,
+                                    int whichButton) {
+                                updateRepos();
+                            }
+                        });
+                ask_alrt.setNegativeButton(getString(R.string.no),
+                        new DialogInterface.OnClickListener() {
+                            public void onClick(DialogInterface dialog,
+                                    int whichButton) {
+                                return;
+                            }
+                        });
+                AlertDialog alert = ask_alrt.create();
+                alert.show();
+            }
+            break;
+        case REQUEST_PREFS:
+            // The automatic update settings may have changed, so reschedule (or
+            // unschedule) the
+            // service accordingly. It's cheap, so no need to check if the
+            // particular setting has
+            // actually been changed.
+            UpdateService.schedule(getBaseContext());
+            break;
+
+        }
+    }
+
+    private void createTabs() {
+        tabHost.clearAllTabs();
+
+        // TabContentFactory that can generate the appropriate list for each
+        // tab...
+        TabHost.TabContentFactory tf = new TabHost.TabContentFactory() {
+            @Override
+            public View createTabContent(String tag) {
+
+                AppListAdapter ad;
+                if (tag.equals(TAB_IN))
+                    ad = apps_in;
+                else if (tag.equals(TAB_UP))
+                    ad = apps_up;
+                else
+                    ad = apps_av;
+
+                ListView lst = new ListView(FDroid.this);
+                lst.setOnItemClickListener(FDroid.this);
+                lst.setAdapter(ad);
+                return lst;
+            }
+        };
+
+        // Create the tab of installed apps...
+        ts = tabHost.newTabSpec(TAB_IN);
+        ts.setIndicator(getString(R.string.tab_installed), getResources()
+                .getDrawable(drawable.star_off));
+        ts.setContent(tf);
+
+        // Create the tab of apps with updates...
+        tsUp = tabHost.newTabSpec(TAB_UP);
+        tsUp.setIndicator(getString(R.string.tab_updates), getResources()
+                .getDrawable(drawable.star_on));
+        tsUp.setContent(tf);
+
+        // Create the tab of available apps...
+        ts1 = tabHost.newTabSpec(TAB_UN);
+        ts1.setIndicator(getString(R.string.tab_noninstalled), getResources()
+                .getDrawable(drawable.ic_input_add));
+        ts1.setContent(tf);
+
+        tabHost.addTab(ts1);
+        tabHost.addTab(ts);
+        tabHost.addTab(tsUp);
+
+    }
+
+    // Populate the lists.
+    // 'update' - true to update the installed status of the applications
+    // by asking the system.
+    private void populateLists(boolean update) {
+
+        apps_in.clear();
+        apps_av.clear();
+        apps_up.clear();
+
+        Vector<DB.App> apps = db.getApps(null, null, update);
+        if (apps.isEmpty()) {
+            // Don't attempt this more than once - we may have invalid
+            // repositories.
+            if (triedEmptyUpdate)
+                return;
+            // If there are no apps, update from the repos - it must be a
+            // new installation.
+            Log.d("FDroid", "Empty app list forces repo update");
+            updateRepos();
+            triedEmptyUpdate = true;
+            return;
+        }
+        Log.d("FDroid", "Updating lists - " + apps.size() + " apps in total");
+
+        for (DB.App app : apps) {
+            if (app.installedVersion == null) {
+                apps_av.addItem(app);
+            } else {
+                apps_in.addItem(app);
+                if (app.hasUpdates)
+                    apps_up.addItem(app);
+            }
+        }
+
+        // Update the count on the 'Updates' tab to show the number available.
+        // This is quite unpleasant, but seems to be the only way to do it.
+        TextView uptext = (TextView) tabHost.getTabWidget().getChildAt(2)
+                .findViewById(android.R.id.title);
+        uptext.setText(getString(R.string.tab_updates) + " ("
+                + Integer.toString(apps_up.getCount()) + ")");
+
+        // Tell the lists that the data behind the adapter has changed, so
+        // they can refresh...
+        apps_av.notifyDataSetChanged();
+        apps_in.notifyDataSetChanged();
+        apps_up.notifyDataSetChanged();
+
+    }
+
+    public boolean updateRepos() {
+        pd = ProgressDialog.show(this, getString(R.string.process_wait_title),
+                getString(R.string.process_update_msg), true);
+        pd.setIcon(android.R.drawable.ic_dialog_info);
+
+        // Check for connection first!
+        ConnectivityManager netstate = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
+        if (netstate.getNetworkInfo(1).getState() == NetworkInfo.State.CONNECTED
+                || netstate.getNetworkInfo(0).getState() == NetworkInfo.State.CONNECTED) {
+            new Thread() {
+                public void run() {
+                    RepoXMLHandler.doUpdates(FDroid.this, db);
+                    update_handler.sendEmptyMessage(0);
+                }
+            }.start();
+            return true;
+        } else {
+            pd.dismiss();
+            Toast.makeText(FDroid.this, getString(R.string.connection_error),
+                    Toast.LENGTH_LONG).show();
+            return false;
+        }
+    }
+
+    /*
+     * Handlers for thread functions that need to access GUI
+     */
+    private Handler update_handler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            populateLists(true);
+            if (pd.isShowing())
+                pd.dismiss();
+        }
+    };
+
+    // Handler for a click on one of the items in an application list. Pops
+    // up a dialog that shows the details of the application and all its
+    // available versions, with buttons to allow installation etc.
+    public void onItemClick(AdapterView<?> arg0, View arg1, final int arg2,
+            long arg3) {
+
+        final DB.App app;
+        String curtab = tabHost.getCurrentTabTag();
+        if (curtab.equalsIgnoreCase(TAB_IN)) {
+            app = (DB.App) apps_in.getItem(arg2);
+        } else if (curtab.equalsIgnoreCase(TAB_UP)) {
+            app = (DB.App) apps_up.getItem(arg2);
+        } else {
+            app = (DB.App) apps_av.getItem(arg2);
+        }
+
+        Intent intent = new Intent(this, AppDetails.class);
+        intent.putExtra("appid", app.id);
+        startActivityForResult(intent, REQUEST_APPDETAILS);
+
+    }
 
 }
diff --git a/src/org/fdroid/fdroid/FDroidApp.java b/src/org/fdroid/fdroid/FDroidApp.java
index ac4242bec..3670466dc 100644
--- a/src/org/fdroid/fdroid/FDroidApp.java
+++ b/src/org/fdroid/fdroid/FDroidApp.java
@@ -26,6 +26,6 @@ public class FDroidApp extends Application {
     // don't want a database update to run. Incremented when entering
     // one, and decremented when leaving, so if it's 0 it ought to be
     // ok!
-    public int inActivity=0;
+    public int inActivity = 0;
 
 }
diff --git a/src/org/fdroid/fdroid/RepoXMLHandler.java b/src/org/fdroid/fdroid/RepoXMLHandler.java
index 6013a43a5..7a34a5af3 100644
--- a/src/org/fdroid/fdroid/RepoXMLHandler.java
+++ b/src/org/fdroid/fdroid/RepoXMLHandler.java
@@ -42,203 +42,203 @@ import android.util.Log;
 
 public class RepoXMLHandler extends DefaultHandler {
 
-	String mserver;
+    String mserver;
 
-	private DB db;
+    private DB db;
 
-	private DB.App curapp = null;
-	private DB.Apk curapk = null;
-	private String curchars = null;
+    private DB.App curapp = null;
+    private DB.Apk curapk = null;
+    private String curchars = null;
 
-	public RepoXMLHandler(String srv, DB db) {
-		mserver = srv;
-		this.db = db;
-	}
+    public RepoXMLHandler(String srv, DB db) {
+        mserver = srv;
+        this.db = db;
+    }
 
-	@Override
-	public void characters(char[] ch, int start, int length)
-			throws SAXException {
+    @Override
+    public void characters(char[] ch, int start, int length)
+            throws SAXException {
 
-		super.characters(ch, start, length);
+        super.characters(ch, start, length);
 
-		String str = new String(ch).substring(start, start + length);
-		if (curchars == null)
-			curchars = str;
-		else
-			curchars += str;
-	}
+        String str = new String(ch).substring(start, start + length);
+        if (curchars == null)
+            curchars = str;
+        else
+            curchars += str;
+    }
 
-	@Override
-	public void endElement(String uri, String localName, String qName)
-			throws SAXException {
+    @Override
+    public void endElement(String uri, String localName, String qName)
+            throws SAXException {
 
-		super.endElement(uri, localName, qName);
-		String curel = localName;
-		String str = curchars;
+        super.endElement(uri, localName, qName);
+        String curel = localName;
+        String str = curchars;
 
-		if (curel == "application" && curapp != null) {
-			Log.d("FDroid", "Repo: Updating application " + curapp.id);
-			db.updateApplication(curapp);
-			getIcon(curapp);
-			curapp = null;
-		} else if (curel == "package" && curapk != null && curapp != null) {
-			Log.d("FDroid", "Repo: Package added (" + curapk.version + ")");
-			curapp.apks.add(curapk);
-			curapk = null;
-		} else if (curapk != null && str != null) {
-			if (curel == "version") {
-				curapk.version = str;
-			} else if (curel == "versioncode") {
-				try {
-					curapk.vercode = Integer.parseInt(str);
-				} catch (NumberFormatException ex) {
-					curapk.vercode = 0;
-				}
-			} else if (curel == "size") {
-				try {
-					curapk.size = Integer.parseInt(str);
-				} catch (NumberFormatException ex) {
-					curapk.size = 0;
-				}
-			} else if (curel == "hash") {
-				curapk.hash = str;
-			} else if (curel == "apkname") {
-				curapk.apkName = str;
-			} else if (curel == "apksource") {
-				curapk.apkSource = str;
-			}
-		} else if (curapp != null && str != null) {
-			if (curel == "id") {
-				Log.d("FDroid", "App id is " + str);
-				curapp.id = str;
-			} else if (curel == "name") {
-				curapp.name = str;
-			} else if (curel == "icon") {
-				curapp.icon = str;
-			} else if (curel == "description") {
-				curapp.description = str;
-			} else if (curel == "summary") {
-				curapp.summary = str;
-			} else if (curel == "license") {
-				curapp.license = str;
-			} else if (curel == "source") {
-				curapp.sourceURL = str;
-			} else if (curel == "web") {
-				curapp.webURL = str;
-			} else if (curel == "tracker") {
-				curapp.trackerURL = str;
-			} else if (curel == "marketversion") {
-				curapp.marketVersion = str;
-			} else if (curel == "marketvercode") {
-				try {
-					curapp.marketVercode = Integer.parseInt(str);
-				} catch (NumberFormatException ex) {
-					curapp.marketVercode = 0;
-				}
-			} else if (curel == "antifeatures") {
-				curapp.antiFeatures = str;
-			}
-		}
+        if (curel == "application" && curapp != null) {
+            Log.d("FDroid", "Repo: Updating application " + curapp.id);
+            db.updateApplication(curapp);
+            getIcon(curapp);
+            curapp = null;
+        } else if (curel == "package" && curapk != null && curapp != null) {
+            Log.d("FDroid", "Repo: Package added (" + curapk.version + ")");
+            curapp.apks.add(curapk);
+            curapk = null;
+        } else if (curapk != null && str != null) {
+            if (curel == "version") {
+                curapk.version = str;
+            } else if (curel == "versioncode") {
+                try {
+                    curapk.vercode = Integer.parseInt(str);
+                } catch (NumberFormatException ex) {
+                    curapk.vercode = 0;
+                }
+            } else if (curel == "size") {
+                try {
+                    curapk.size = Integer.parseInt(str);
+                } catch (NumberFormatException ex) {
+                    curapk.size = 0;
+                }
+            } else if (curel == "hash") {
+                curapk.hash = str;
+            } else if (curel == "apkname") {
+                curapk.apkName = str;
+            } else if (curel == "apksource") {
+                curapk.apkSource = str;
+            }
+        } else if (curapp != null && str != null) {
+            if (curel == "id") {
+                Log.d("FDroid", "App id is " + str);
+                curapp.id = str;
+            } else if (curel == "name") {
+                curapp.name = str;
+            } else if (curel == "icon") {
+                curapp.icon = str;
+            } else if (curel == "description") {
+                curapp.description = str;
+            } else if (curel == "summary") {
+                curapp.summary = str;
+            } else if (curel == "license") {
+                curapp.license = str;
+            } else if (curel == "source") {
+                curapp.sourceURL = str;
+            } else if (curel == "web") {
+                curapp.webURL = str;
+            } else if (curel == "tracker") {
+                curapp.trackerURL = str;
+            } else if (curel == "marketversion") {
+                curapp.marketVersion = str;
+            } else if (curel == "marketvercode") {
+                try {
+                    curapp.marketVercode = Integer.parseInt(str);
+                } catch (NumberFormatException ex) {
+                    curapp.marketVercode = 0;
+                }
+            } else if (curel == "antifeatures") {
+                curapp.antiFeatures = str;
+            }
+        }
 
-	}
+    }
 
-	@Override
-	public void startElement(String uri, String localName, String qName,
-			Attributes attributes) throws SAXException {
+    @Override
+    public void startElement(String uri, String localName, String qName,
+            Attributes attributes) throws SAXException {
 
-		super.startElement(uri, localName, qName, attributes);
-		if (localName == "application" && curapp == null) {
-			Log.d("FDroid", "Repo: Found application at " + mserver);
-			curapp = new DB.App();
-		} else if (localName == "package" && curapp != null && curapk == null) {
-			Log.d("FDroid", "Repo: Found package for " + curapp.id);
-			curapk = new DB.Apk();
-			curapk.id = curapp.id;
-			curapk.server = mserver;
-		}
-		curchars = null;
-	}
+        super.startElement(uri, localName, qName, attributes);
+        if (localName == "application" && curapp == null) {
+            Log.d("FDroid", "Repo: Found application at " + mserver);
+            curapp = new DB.App();
+        } else if (localName == "package" && curapp != null && curapk == null) {
+            Log.d("FDroid", "Repo: Found package for " + curapp.id);
+            curapk = new DB.Apk();
+            curapk.id = curapp.id;
+            curapk.server = mserver;
+        }
+        curchars = null;
+    }
 
-	private void getIcon(DB.App app) {
-		try {
+    private void getIcon(DB.App app) {
+        try {
 
-			String destpath = DB.getIconsPath() + app.icon;
-			File f = new File(destpath);
-			if (f.exists())
-				return;
+            String destpath = DB.getIconsPath() + app.icon;
+            File f = new File(destpath);
+            if (f.exists())
+                return;
 
-			BufferedInputStream getit = new BufferedInputStream(new URL(mserver
-					+ "/icons/" + app.icon).openStream());
-			FileOutputStream saveit = new FileOutputStream(destpath);
-			BufferedOutputStream bout = new BufferedOutputStream(saveit, 1024);
-			byte data[] = new byte[1024];
+            BufferedInputStream getit = new BufferedInputStream(new URL(mserver
+                    + "/icons/" + app.icon).openStream());
+            FileOutputStream saveit = new FileOutputStream(destpath);
+            BufferedOutputStream bout = new BufferedOutputStream(saveit, 1024);
+            byte data[] = new byte[1024];
 
-			int readed = getit.read(data, 0, 1024);
-			while (readed != -1) {
-				bout.write(data, 0, readed);
-				readed = getit.read(data, 0, 1024);
-			}
-			bout.close();
-			getit.close();
-			saveit.close();
-		} catch (Exception e) {
+            int readed = getit.read(data, 0, 1024);
+            while (readed != -1) {
+                bout.write(data, 0, readed);
+                readed = getit.read(data, 0, 1024);
+            }
+            bout.close();
+            getit.close();
+            saveit.close();
+        } catch (Exception e) {
 
-		}
-	}
+        }
+    }
 
-	public static void doUpdates(Context ctx, DB db) {
-		db.beginUpdate();
-		Vector<DB.Repo> repos = db.getRepos();
-		for (DB.Repo repo : repos) {
-			if (repo.inuse) {
+    public static void doUpdates(Context ctx, DB db) {
+        db.beginUpdate();
+        Vector<DB.Repo> repos = db.getRepos();
+        for (DB.Repo repo : repos) {
+            if (repo.inuse) {
 
-				try {
+                try {
 
-					FileOutputStream f = ctx.openFileOutput("tempindex.xml",
-							Context.MODE_PRIVATE);
+                    FileOutputStream f = ctx.openFileOutput("tempindex.xml",
+                            Context.MODE_PRIVATE);
 
-					// Download the index file from the repo...
-					BufferedInputStream getit = new BufferedInputStream(
-							new URL(repo.address + "/index.xml").openStream());
+                    // Download the index file from the repo...
+                    BufferedInputStream getit = new BufferedInputStream(
+                            new URL(repo.address + "/index.xml").openStream());
 
-					BufferedOutputStream bout = new BufferedOutputStream(f,
-							1024);
-					byte data[] = new byte[1024];
+                    BufferedOutputStream bout = new BufferedOutputStream(f,
+                            1024);
+                    byte data[] = new byte[1024];
 
-					int readed = getit.read(data, 0, 1024);
-					while (readed != -1) {
-						bout.write(data, 0, readed);
-						readed = getit.read(data, 0, 1024);
-					}
-					bout.close();
-					getit.close();
-					f.close();
+                    int readed = getit.read(data, 0, 1024);
+                    while (readed != -1) {
+                        bout.write(data, 0, readed);
+                        readed = getit.read(data, 0, 1024);
+                    }
+                    bout.close();
+                    getit.close();
+                    f.close();
 
-					// Process the index...
-					SAXParserFactory spf = SAXParserFactory.newInstance();
-					SAXParser sp = spf.newSAXParser();
-					XMLReader xr = sp.getXMLReader();
-					RepoXMLHandler handler = new RepoXMLHandler(repo.address,
-							db);
-					xr.setContentHandler(handler);
+                    // Process the index...
+                    SAXParserFactory spf = SAXParserFactory.newInstance();
+                    SAXParser sp = spf.newSAXParser();
+                    XMLReader xr = sp.getXMLReader();
+                    RepoXMLHandler handler = new RepoXMLHandler(repo.address,
+                            db);
+                    xr.setContentHandler(handler);
 
-					InputStreamReader isr = new FileReader(new File(ctx
-							.getFilesDir()
-							+ "/tempindex.xml"));
-					InputSource is = new InputSource(isr);
-					xr.parse(is);
+                    InputStreamReader isr = new FileReader(new File(ctx
+                            .getFilesDir()
+                            + "/tempindex.xml"));
+                    InputSource is = new InputSource(isr);
+                    xr.parse(is);
 
-				} catch (Exception e) {
-					Log.d("FDroid", "Exception updating from " + repo.address
-							+ " - " + e.getMessage());
-				} finally {
-					ctx.deleteFile("tempindex.xml");
-				}
+                } catch (Exception e) {
+                    Log.d("FDroid", "Exception updating from " + repo.address
+                            + " - " + e.getMessage());
+                } finally {
+                    ctx.deleteFile("tempindex.xml");
+                }
 
-			}
-		}
-		db.endUpdate();
+            }
+        }
+        db.endUpdate();
 
-	}
+    }
 
 }
diff --git a/src/org/fdroid/fdroid/UpdateService.java b/src/org/fdroid/fdroid/UpdateService.java
index 29e785c2f..a10c925f6 100644
--- a/src/org/fdroid/fdroid/UpdateService.java
+++ b/src/org/fdroid/fdroid/UpdateService.java
@@ -35,129 +35,129 @@ import android.util.Log;
 
 public class UpdateService extends Service {
 
-	// Schedule (or cancel schedule for) this service, according to the
-	// current preferences. Should be called a) at boot, or b) if the preference
-	// is changed.
-	// TODO: What if we get upgraded?
-	public static void schedule(Context ctx) {
+    // Schedule (or cancel schedule for) this service, according to the
+    // current preferences. Should be called a) at boot, or b) if the preference
+    // is changed.
+    // TODO: What if we get upgraded?
+    public static void schedule(Context ctx) {
 
-		SharedPreferences prefs = PreferenceManager
-				.getDefaultSharedPreferences(ctx);
-		String sint = prefs.getString("updateInterval", "0");
-		int interval = Integer.parseInt(sint);
+        SharedPreferences prefs = PreferenceManager
+                .getDefaultSharedPreferences(ctx);
+        String sint = prefs.getString("updateInterval", "0");
+        int interval = Integer.parseInt(sint);
 
-		Intent intent = new Intent(ctx, UpdateService.class);
-		PendingIntent pending = PendingIntent.getService(ctx, 0, intent, 0);
+        Intent intent = new Intent(ctx, UpdateService.class);
+        PendingIntent pending = PendingIntent.getService(ctx, 0, intent, 0);
 
-		AlarmManager alarm = (AlarmManager) ctx
-				.getSystemService(Context.ALARM_SERVICE);
-		alarm.cancel(pending);
-		if (interval > 0) {
-			alarm.setInexactRepeating(AlarmManager.ELAPSED_REALTIME,
-					SystemClock.elapsedRealtime() + 5000,
-					AlarmManager.INTERVAL_HOUR, pending);
-		}
+        AlarmManager alarm = (AlarmManager) ctx
+                .getSystemService(Context.ALARM_SERVICE);
+        alarm.cancel(pending);
+        if (interval > 0) {
+            alarm.setInexactRepeating(AlarmManager.ELAPSED_REALTIME,
+                    SystemClock.elapsedRealtime() + 5000,
+                    AlarmManager.INTERVAL_HOUR, pending);
+        }
 
-	}
+    }
 
-	// For API levels <5
-	@Override
-	public void onStart(Intent intent, int startId) {
-		handleCommand();
-	}
+    // For API levels <5
+    @Override
+    public void onStart(Intent intent, int startId) {
+        handleCommand();
+    }
 
-	// For API levels >=5
-	@Override
-	public int onStartCommand(Intent intent, int flags, int startId) {
-		handleCommand();
-		return START_REDELIVER_INTENT;
-	}
+    // For API levels >=5
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        handleCommand();
+        return START_REDELIVER_INTENT;
+    }
 
-	private void handleCommand() {
+    private void handleCommand() {
 
-		new Thread() {
-			public void run() {
+        new Thread() {
+            public void run() {
 
-				// If we're in one of our list activities, we don't want
-				// to run an update because the database will be out of
-				// sync with the display.
-				if (((FDroidApp) getApplication()).inActivity != 0)
-					return;
+                // If we're in one of our list activities, we don't want
+                // to run an update because the database will be out of
+                // sync with the display.
+                if (((FDroidApp) getApplication()).inActivity != 0)
+                    return;
 
-				// See if it's time to actually do anything yet...
-				SharedPreferences prefs = PreferenceManager
-						.getDefaultSharedPreferences(getBaseContext());
-				long lastUpdate = prefs.getLong("lastUpdateCheck", 0);
-				String sint = prefs.getString("updateInterval", "0");
-				int interval = Integer.parseInt(sint);
-				if (interval == 0)
-					return;
-				if (lastUpdate + (interval * 60 * 60) > System
-						.currentTimeMillis())
-					return;
+                // See if it's time to actually do anything yet...
+                SharedPreferences prefs = PreferenceManager
+                        .getDefaultSharedPreferences(getBaseContext());
+                long lastUpdate = prefs.getLong("lastUpdateCheck", 0);
+                String sint = prefs.getString("updateInterval", "0");
+                int interval = Integer.parseInt(sint);
+                if (interval == 0)
+                    return;
+                if (lastUpdate + (interval * 60 * 60) > System
+                        .currentTimeMillis())
+                    return;
 
-				// Make sure we have a connection...
-				ConnectivityManager netstate = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
-				if (netstate.getNetworkInfo(1).getState() != NetworkInfo.State.CONNECTED
-						&& netstate.getNetworkInfo(0).getState() != NetworkInfo.State.CONNECTED)
-					return;
+                // Make sure we have a connection...
+                ConnectivityManager netstate = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
+                if (netstate.getNetworkInfo(1).getState() != NetworkInfo.State.CONNECTED
+                        && netstate.getNetworkInfo(0).getState() != NetworkInfo.State.CONNECTED)
+                    return;
 
-				// Do the update...
-				DB db = null;
-				try {
-					db = new DB(getBaseContext());
-					boolean notify = prefs.getBoolean("updateNotify", false);
+                // Do the update...
+                DB db = null;
+                try {
+                    db = new DB(getBaseContext());
+                    boolean notify = prefs.getBoolean("updateNotify", false);
 
-					// Get the number of updates available before we
-					// start, so we can notify if there are new ones.
-					// (But avoid doing it if the user doesn't want
-					// notifications, since it may be time consuming)
-					int prevUpdates = 0;
-					if (notify)
-						prevUpdates = db.getNumUpdates();
+                    // Get the number of updates available before we
+                    // start, so we can notify if there are new ones.
+                    // (But avoid doing it if the user doesn't want
+                    // notifications, since it may be time consuming)
+                    int prevUpdates = 0;
+                    if (notify)
+                        prevUpdates = db.getNumUpdates();
 
-					RepoXMLHandler.doUpdates(getBaseContext(), db);
+                    RepoXMLHandler.doUpdates(getBaseContext(), db);
 
-					if (notify) {
-						if (db.getNumUpdates() > prevUpdates) {
-							// And the user wants to know.
-							NotificationManager n = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
-							Notification notification = new Notification(
-									R.drawable.icon,
-									"FDroid Updates Available", System
-											.currentTimeMillis());
-							Context context = getApplicationContext();
-							CharSequence contentTitle = "FDroid";
-							CharSequence contentText = "Updates are available.";
-							Intent notificationIntent = new Intent(
-									UpdateService.this, FDroid.class);
-							PendingIntent contentIntent = PendingIntent
-									.getActivity(UpdateService.this, 0,
-											notificationIntent, 0);
-							notification.setLatestEventInfo(context,
-									contentTitle, contentText, contentIntent);
-							notification.flags |= Notification.FLAG_AUTO_CANCEL;
-							n.notify(1, notification);
-						}
-					}
+                    if (notify) {
+                        if (db.getNumUpdates() > prevUpdates) {
+                            // And the user wants to know.
+                            NotificationManager n = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+                            Notification notification = new Notification(
+                                    R.drawable.icon,
+                                    "FDroid Updates Available", System
+                                            .currentTimeMillis());
+                            Context context = getApplicationContext();
+                            CharSequence contentTitle = "FDroid";
+                            CharSequence contentText = "Updates are available.";
+                            Intent notificationIntent = new Intent(
+                                    UpdateService.this, FDroid.class);
+                            PendingIntent contentIntent = PendingIntent
+                                    .getActivity(UpdateService.this, 0,
+                                            notificationIntent, 0);
+                            notification.setLatestEventInfo(context,
+                                    contentTitle, contentText, contentIntent);
+                            notification.flags |= Notification.FLAG_AUTO_CANCEL;
+                            n.notify(1, notification);
+                        }
+                    }
 
-				} catch (Exception e) {
-					Log.d("FDroid", "Exception during handleCommand() - "
-							+ e.getMessage());
-				} finally {
-					if (db != null)
-						db.close();
-					stopSelf();
-				}
+                } catch (Exception e) {
+                    Log.d("FDroid", "Exception during handleCommand() - "
+                            + e.getMessage());
+                } finally {
+                    if (db != null)
+                        db.close();
+                    stopSelf();
+                }
 
-			}
-		}.start();
+            }
+        }.start();
 
-	}
+    }
 
-	@Override
-	public IBinder onBind(Intent intent) {
-		return null;
-	}
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
 
 }