From 0ea5325b8125fccce645c3345c96c15c5b076b4a Mon Sep 17 00:00:00 2001
From: Peter Serwylo <peter@serwylo.com>
Date: Thu, 30 Jun 2016 13:21:55 +1000
Subject: [PATCH] Extracted ApkProvider.DataColumns to Schema.ApkTable.Cols

---
 .../java/org/fdroid/fdroid/AppDetails.java    |  2 +-
 .../main/java/org/fdroid/fdroid/data/Apk.java | 83 ++++++++++---------
 .../org/fdroid/fdroid/data/ApkProvider.java   | 74 +++++------------
 .../org/fdroid/fdroid/data/AppProvider.java   |  3 +-
 .../java/org/fdroid/fdroid/data/DBHelper.java |  9 +-
 .../org/fdroid/fdroid/data/RepoPersister.java |  6 +-
 .../org/fdroid/fdroid/data/RepoProvider.java  |  2 +-
 .../java/org/fdroid/fdroid/data/Schema.java   | 35 +++++++-
 .../views/InstallConfirmActivity.java         |  3 +-
 .../test/java/org/fdroid/fdroid/Assert.java   | 17 ++--
 .../fdroid/fdroid/MultiRepoUpdaterTest.java   |  2 +-
 .../fdroid/ProperMultiRepoUpdaterTest.java    |  7 +-
 .../fdroid/fdroid/data/ApkProviderTest.java   | 39 ++++-----
 .../fdroid/fdroid/data/ProviderUriTests.java  |  4 +-
 14 files changed, 146 insertions(+), 140 deletions(-)

diff --git a/app/src/main/java/org/fdroid/fdroid/AppDetails.java b/app/src/main/java/org/fdroid/fdroid/AppDetails.java
index 50b0d634a..8bc60b6dc 100644
--- a/app/src/main/java/org/fdroid/fdroid/AppDetails.java
+++ b/app/src/main/java/org/fdroid/fdroid/AppDetails.java
@@ -1033,7 +1033,7 @@ public class AppDetails extends AppCompatActivity {
             case REQUEST_PERMISSION_DIALOG:
                 if (resultCode == Activity.RESULT_OK) {
                     Uri uri = data.getData();
-                    Apk apk = ApkProvider.Helper.find(this, uri, ApkProvider.DataColumns.ALL);
+                    Apk apk = ApkProvider.Helper.find(this, uri, Schema.ApkTable.Cols.ALL);
                     startInstall(apk);
                 }
                 break;
diff --git a/app/src/main/java/org/fdroid/fdroid/data/Apk.java b/app/src/main/java/org/fdroid/fdroid/data/Apk.java
index 36d5db4e8..04b626d3e 100644
--- a/app/src/main/java/org/fdroid/fdroid/data/Apk.java
+++ b/app/src/main/java/org/fdroid/fdroid/data/Apk.java
@@ -7,6 +7,7 @@ import android.os.Build;
 import android.os.Parcelable;
 
 import org.fdroid.fdroid.Utils;
+import org.fdroid.fdroid.data.Schema.ApkTable.Cols;
 
 import java.util.ArrayList;
 import java.util.Date;
@@ -73,67 +74,67 @@ public class Apk extends ValueObject implements Comparable<Apk> {
 
         for (int i = 0; i < cursor.getColumnCount(); i++) {
             switch (cursor.getColumnName(i)) {
-                case ApkProvider.DataColumns.HASH:
+                case Cols.HASH:
                     hash = cursor.getString(i);
                     break;
-                case ApkProvider.DataColumns.HASH_TYPE:
+                case Cols.HASH_TYPE:
                     hashType = cursor.getString(i);
                     break;
-                case ApkProvider.DataColumns.ADDED_DATE:
+                case Cols.ADDED_DATE:
                     added = Utils.parseDate(cursor.getString(i), null);
                     break;
-                case ApkProvider.DataColumns.FEATURES:
+                case Cols.FEATURES:
                     features = Utils.parseCommaSeparatedString(cursor.getString(i));
                     break;
-                case ApkProvider.DataColumns.PACKAGE_NAME:
+                case Cols.PACKAGE_NAME:
                     packageName = cursor.getString(i);
                     break;
-                case ApkProvider.DataColumns.IS_COMPATIBLE:
+                case Cols.IS_COMPATIBLE:
                     compatible = cursor.getInt(i) == 1;
                     break;
-                case ApkProvider.DataColumns.MIN_SDK_VERSION:
+                case Cols.MIN_SDK_VERSION:
                     minSdkVersion = cursor.getInt(i);
                     break;
-                case ApkProvider.DataColumns.TARGET_SDK_VERSION:
+                case Cols.TARGET_SDK_VERSION:
                     targetSdkVersion = cursor.getInt(i);
                     break;
-                case ApkProvider.DataColumns.MAX_SDK_VERSION:
+                case Cols.MAX_SDK_VERSION:
                     maxSdkVersion = cursor.getInt(i);
                     break;
-                case ApkProvider.DataColumns.NAME:
+                case Cols.NAME:
                     apkName = cursor.getString(i);
                     break;
-                case ApkProvider.DataColumns.PERMISSIONS:
+                case Cols.PERMISSIONS:
                     permissions = Utils.parseCommaSeparatedString(cursor.getString(i));
                     break;
-                case ApkProvider.DataColumns.NATIVE_CODE:
+                case Cols.NATIVE_CODE:
                     nativecode = Utils.parseCommaSeparatedString(cursor.getString(i));
                     break;
-                case ApkProvider.DataColumns.INCOMPATIBLE_REASONS:
+                case Cols.INCOMPATIBLE_REASONS:
                     incompatibleReasons = Utils.parseCommaSeparatedString(cursor.getString(i));
                     break;
-                case ApkProvider.DataColumns.REPO_ID:
+                case Cols.REPO_ID:
                     repo = cursor.getInt(i);
                     break;
-                case ApkProvider.DataColumns.SIGNATURE:
+                case Cols.SIGNATURE:
                     sig = cursor.getString(i);
                     break;
-                case ApkProvider.DataColumns.SIZE:
+                case Cols.SIZE:
                     size = cursor.getInt(i);
                     break;
-                case ApkProvider.DataColumns.SOURCE_NAME:
+                case Cols.SOURCE_NAME:
                     srcname = cursor.getString(i);
                     break;
-                case ApkProvider.DataColumns.VERSION_NAME:
+                case Cols.VERSION_NAME:
                     versionName = cursor.getString(i);
                     break;
-                case ApkProvider.DataColumns.VERSION_CODE:
+                case Cols.VERSION_CODE:
                     versionCode = cursor.getInt(i);
                     break;
-                case ApkProvider.DataColumns.REPO_VERSION:
+                case Cols.REPO_VERSION:
                     repoVersion = cursor.getInt(i);
                     break;
-                case ApkProvider.DataColumns.REPO_ADDRESS:
+                case Cols.REPO_ADDRESS:
                     repoAddress = cursor.getString(i);
                     break;
             }
@@ -142,7 +143,7 @@ public class Apk extends ValueObject implements Comparable<Apk> {
 
     public String getUrl() {
         if (repoAddress == null || apkName == null) {
-            throw new IllegalStateException("Apk needs to have both ApkProvider.DataColumns.REPO_ADDRESS and ApkProvider.DataColumns.NAME set in order to calculate URL.");
+            throw new IllegalStateException("Apk needs to have both Schema.ApkTable.Cols.REPO_ADDRESS and Schema.ApkTable.Cols.NAME set in order to calculate URL.");
         }
         return repoAddress + "/" + apkName.replace(" ", "%20");
     }
@@ -191,25 +192,25 @@ public class Apk extends ValueObject implements Comparable<Apk> {
 
     public ContentValues toContentValues() {
         ContentValues values = new ContentValues();
-        values.put(ApkProvider.DataColumns.PACKAGE_NAME, packageName);
-        values.put(ApkProvider.DataColumns.VERSION_NAME, versionName);
-        values.put(ApkProvider.DataColumns.VERSION_CODE, versionCode);
-        values.put(ApkProvider.DataColumns.REPO_ID, repo);
-        values.put(ApkProvider.DataColumns.HASH, hash);
-        values.put(ApkProvider.DataColumns.HASH_TYPE, hashType);
-        values.put(ApkProvider.DataColumns.SIGNATURE, sig);
-        values.put(ApkProvider.DataColumns.SOURCE_NAME, srcname);
-        values.put(ApkProvider.DataColumns.SIZE, size);
-        values.put(ApkProvider.DataColumns.NAME, apkName);
-        values.put(ApkProvider.DataColumns.MIN_SDK_VERSION, minSdkVersion);
-        values.put(ApkProvider.DataColumns.TARGET_SDK_VERSION, targetSdkVersion);
-        values.put(ApkProvider.DataColumns.MAX_SDK_VERSION, maxSdkVersion);
-        values.put(ApkProvider.DataColumns.ADDED_DATE, Utils.formatDate(added, ""));
-        values.put(ApkProvider.DataColumns.PERMISSIONS, Utils.serializeCommaSeparatedString(permissions));
-        values.put(ApkProvider.DataColumns.FEATURES, Utils.serializeCommaSeparatedString(features));
-        values.put(ApkProvider.DataColumns.NATIVE_CODE, Utils.serializeCommaSeparatedString(nativecode));
-        values.put(ApkProvider.DataColumns.INCOMPATIBLE_REASONS, Utils.serializeCommaSeparatedString(incompatibleReasons));
-        values.put(ApkProvider.DataColumns.IS_COMPATIBLE, compatible ? 1 : 0);
+        values.put(Cols.PACKAGE_NAME, packageName);
+        values.put(Cols.VERSION_NAME, versionName);
+        values.put(Cols.VERSION_CODE, versionCode);
+        values.put(Cols.REPO_ID, repo);
+        values.put(Cols.HASH, hash);
+        values.put(Cols.HASH_TYPE, hashType);
+        values.put(Cols.SIGNATURE, sig);
+        values.put(Cols.SOURCE_NAME, srcname);
+        values.put(Cols.SIZE, size);
+        values.put(Cols.NAME, apkName);
+        values.put(Cols.MIN_SDK_VERSION, minSdkVersion);
+        values.put(Cols.TARGET_SDK_VERSION, targetSdkVersion);
+        values.put(Cols.MAX_SDK_VERSION, maxSdkVersion);
+        values.put(Cols.ADDED_DATE, Utils.formatDate(added, ""));
+        values.put(Cols.PERMISSIONS, Utils.serializeCommaSeparatedString(permissions));
+        values.put(Cols.FEATURES, Utils.serializeCommaSeparatedString(features));
+        values.put(Cols.NATIVE_CODE, Utils.serializeCommaSeparatedString(nativecode));
+        values.put(Cols.INCOMPATIBLE_REASONS, Utils.serializeCommaSeparatedString(incompatibleReasons));
+        values.put(Cols.IS_COMPATIBLE, compatible ? 1 : 0);
         return values;
     }
 
diff --git a/app/src/main/java/org/fdroid/fdroid/data/ApkProvider.java b/app/src/main/java/org/fdroid/fdroid/data/ApkProvider.java
index a69dc5155..93165edcb 100644
--- a/app/src/main/java/org/fdroid/fdroid/data/ApkProvider.java
+++ b/app/src/main/java/org/fdroid/fdroid/data/ApkProvider.java
@@ -6,10 +6,10 @@ import android.content.Context;
 import android.content.UriMatcher;
 import android.database.Cursor;
 import android.net.Uri;
-import android.provider.BaseColumns;
 import android.util.Log;
 
 import org.fdroid.fdroid.Utils;
+import org.fdroid.fdroid.data.Schema.ApkTable.Cols;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -85,7 +85,7 @@ public class ApkProvider extends FDroidProvider {
         }
 
         public static Apk find(Context context, String packageName, int versionCode) {
-            return find(context, packageName, versionCode, DataColumns.ALL);
+            return find(context, packageName, versionCode, Cols.ALL);
         }
 
         /**
@@ -103,7 +103,7 @@ public class ApkProvider extends FDroidProvider {
          * @see org.fdroid.fdroid.data.ApkProvider.Helper#find(Context, Repo, List, String[])
          */
         public static List<Apk> find(Context context, Repo repo, List<App> apps) {
-            return find(context, repo, apps, DataColumns.ALL);
+            return find(context, repo, apps, Cols.ALL);
         }
 
         public static Apk find(Context context, String packageName, int versionCode, String[] projection) {
@@ -126,14 +126,14 @@ public class ApkProvider extends FDroidProvider {
         }
 
         public static List<Apk> findByPackageName(Context context, String packageName) {
-            return findByPackageName(context, packageName, ApkProvider.DataColumns.ALL);
+            return findByPackageName(context, packageName, Cols.ALL);
         }
 
         public static List<Apk> findByPackageName(Context context,
                                                   String packageName, String[] projection) {
             ContentResolver resolver = context.getContentResolver();
             final Uri uri = getAppUri(packageName);
-            final String sort = ApkProvider.DataColumns.VERSION_CODE + " DESC";
+            final String sort = Cols.VERSION_CODE + " DESC";
             Cursor cursor = resolver.query(uri, projection, null, null, sort);
             return cursorToList(cursor);
         }
@@ -176,7 +176,7 @@ public class ApkProvider extends FDroidProvider {
         }
 
         public static Apk get(Context context, Uri uri) {
-            return get(context, uri, DataColumns.ALL);
+            return get(context, uri, Cols.ALL);
         }
 
         public static Apk get(Context context, Uri uri, String[] fields) {
@@ -194,40 +194,6 @@ public class ApkProvider extends FDroidProvider {
         }
     }
 
-    public interface DataColumns extends BaseColumns {
-
-        String _COUNT_DISTINCT_ID = "countDistinct";
-
-        String PACKAGE_NAME    = "id";
-        String VERSION_NAME    = "version";
-        String REPO_ID         = "repo";
-        String HASH            = "hash";
-        String VERSION_CODE    = "vercode";
-        String NAME            = "apkName";
-        String SIZE            = "size";
-        String SIGNATURE       = "sig";
-        String SOURCE_NAME     = "srcname";
-        String MIN_SDK_VERSION = "minSdkVersion";
-        String TARGET_SDK_VERSION = "targetSdkVersion";
-        String MAX_SDK_VERSION = "maxSdkVersion";
-        String PERMISSIONS     = "permissions";
-        String FEATURES        = "features";
-        String NATIVE_CODE     = "nativecode";
-        String HASH_TYPE       = "hashType";
-        String ADDED_DATE      = "added";
-        String IS_COMPATIBLE   = "compatible";
-        String INCOMPATIBLE_REASONS = "incompatibleReasons";
-        String REPO_VERSION    = "repoVersion";
-        String REPO_ADDRESS    = "repoAddress";
-
-        String[] ALL = {
-            _ID, PACKAGE_NAME, VERSION_NAME, REPO_ID, HASH, VERSION_CODE, NAME,
-            SIZE, SIGNATURE, SOURCE_NAME, MIN_SDK_VERSION, TARGET_SDK_VERSION, MAX_SDK_VERSION,
-            PERMISSIONS, FEATURES, NATIVE_CODE, HASH_TYPE, ADDED_DATE,
-            IS_COMPATIBLE, REPO_VERSION, REPO_ADDRESS, INCOMPATIBLE_REASONS,
-        };
-    }
-
     private static final int CODE_APP = CODE_SINGLE + 1;
     private static final int CODE_REPO = CODE_APP + 1;
     private static final int CODE_APKS = CODE_REPO + 1;
@@ -247,8 +213,8 @@ public class ApkProvider extends FDroidProvider {
     private static final Map<String, String> REPO_FIELDS = new HashMap<>();
 
     static {
-        REPO_FIELDS.put(DataColumns.REPO_VERSION, RepoProvider.DataColumns.VERSION);
-        REPO_FIELDS.put(DataColumns.REPO_ADDRESS, RepoProvider.DataColumns.ADDRESS);
+        REPO_FIELDS.put(Cols.REPO_VERSION, RepoProvider.DataColumns.VERSION);
+        REPO_FIELDS.put(Cols.REPO_ADDRESS, RepoProvider.DataColumns.ADDRESS);
 
         MATCHER.addURI(getAuthority(), PATH_REPO + "/#", CODE_REPO);
         MATCHER.addURI(getAuthority(), PATH_APK + "/#/*", CODE_SINGLE);
@@ -378,12 +344,12 @@ public class ApkProvider extends FDroidProvider {
         public void addField(String field) {
             if (REPO_FIELDS.containsKey(field)) {
                 addRepoField(REPO_FIELDS.get(field), field);
-            } else if (field.equals(DataColumns._ID)) {
+            } else if (field.equals(Cols._ID)) {
                 appendField("rowid", "apk", "_id");
-            } else if (field.equals(DataColumns._COUNT)) {
-                appendField("COUNT(*) AS " + DataColumns._COUNT);
-            } else if (field.equals(DataColumns._COUNT_DISTINCT_ID)) {
-                appendField("COUNT(DISTINCT apk.id) AS " + DataColumns._COUNT_DISTINCT_ID);
+            } else if (field.equals(Cols._COUNT)) {
+                appendField("COUNT(*) AS " + Cols._COUNT);
+            } else if (field.equals(Cols._COUNT_DISTINCT_ID)) {
+                appendField("COUNT(DISTINCT apk.id) AS " + Cols._COUNT_DISTINCT_ID);
             } else {
                 appendField(field, "apk");
             }
@@ -400,7 +366,7 @@ public class ApkProvider extends FDroidProvider {
     }
 
     private QuerySelection queryApp(String packageName) {
-        final String selection = DataColumns.PACKAGE_NAME + " = ? ";
+        final String selection = Cols.PACKAGE_NAME + " = ? ";
         final String[] args = {packageName};
         return new QuerySelection(selection, args);
     }
@@ -417,13 +383,13 @@ public class ApkProvider extends FDroidProvider {
     }
 
     protected QuerySelection queryRepo(long repoId) {
-        final String selection = DataColumns.REPO_ID + " = ? ";
+        final String selection = Cols.REPO_ID + " = ? ";
         final String[] args = {Long.toString(repoId)};
         return new QuerySelection(selection, args);
     }
 
     private QuerySelection queryRepoApps(long repoId, String packageNames) {
-        return queryRepo(repoId).add(AppProvider.queryApps(packageNames, DataColumns.PACKAGE_NAME));
+        return queryRepo(repoId).add(AppProvider.queryApps(packageNames, Cols.PACKAGE_NAME));
     }
 
     protected QuerySelection queryApks(String apkKeys) {
@@ -511,14 +477,14 @@ public class ApkProvider extends FDroidProvider {
     @Override
     public Uri insert(Uri uri, ContentValues values) {
         removeRepoFields(values);
-        validateFields(DataColumns.ALL, values);
+        validateFields(Cols.ALL, values);
         db().insertOrThrow(getTableName(), null, values);
         if (!isApplyingBatch()) {
             getContext().getContentResolver().notifyChange(uri, null);
         }
         return getContentUri(
-            values.getAsString(DataColumns.PACKAGE_NAME),
-            values.getAsInteger(DataColumns.VERSION_CODE));
+            values.getAsString(Cols.PACKAGE_NAME),
+            values.getAsInteger(Cols.VERSION_CODE));
 
     }
 
@@ -573,7 +539,7 @@ public class ApkProvider extends FDroidProvider {
     }
 
     protected int performUpdateUnchecked(Uri uri, ContentValues values, String where, String[] whereArgs) {
-        validateFields(DataColumns.ALL, values);
+        validateFields(Cols.ALL, values);
         removeRepoFields(values);
 
         QuerySelection query = new QuerySelection(where, whereArgs);
diff --git a/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java b/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java
index 870090644..eeb9c13d1 100644
--- a/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java
+++ b/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java
@@ -13,6 +13,7 @@ import android.util.Log;
 import org.fdroid.fdroid.Preferences;
 import org.fdroid.fdroid.R;
 import org.fdroid.fdroid.Utils;
+import org.fdroid.fdroid.data.Schema.ApkTable;
 import org.fdroid.fdroid.data.Schema.AppTable.Cols;
 
 import java.util.ArrayList;
@@ -321,7 +322,7 @@ public class AppProvider extends FDroidProvider {
 
         private void addSuggestedApkVersionField() {
             addSuggestedApkField(
-                    ApkProvider.DataColumns.VERSION_NAME,
+                    ApkTable.Cols.VERSION_NAME,
                     Cols.SuggestedApk.VERSION_NAME);
         }
 
diff --git a/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java b/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java
index 209905a27..f0857d130 100644
--- a/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java
+++ b/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java
@@ -9,6 +9,7 @@ import android.util.Log;
 
 import org.fdroid.fdroid.R;
 import org.fdroid.fdroid.Utils;
+import org.fdroid.fdroid.data.Schema.ApkTable;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -505,8 +506,8 @@ class DBHelper extends SQLiteOpenHelper {
         }
         Utils.debugLog(TAG, "Converting maxSdkVersion value 0 to " + Byte.MAX_VALUE);
         ContentValues values = new ContentValues();
-        values.put(ApkProvider.DataColumns.MAX_SDK_VERSION, Byte.MAX_VALUE);
-        db.update(TABLE_APK, values, ApkProvider.DataColumns.MAX_SDK_VERSION + " < 1", null);
+        values.put(ApkTable.Cols.MAX_SDK_VERSION, Byte.MAX_VALUE);
+        db.update(TABLE_APK, values, ApkTable.Cols.MAX_SDK_VERSION + " < 1", null);
     }
 
     /**
@@ -578,10 +579,10 @@ class DBHelper extends SQLiteOpenHelper {
         if (oldVersion >= 57) {
             return;
         }
-        Utils.debugLog(TAG, "Adding " + ApkProvider.DataColumns.TARGET_SDK_VERSION
+        Utils.debugLog(TAG, "Adding " + ApkTable.Cols.TARGET_SDK_VERSION
                 + " columns to " + TABLE_APK);
         db.execSQL("alter table " + TABLE_APK + " add column "
-                + ApkProvider.DataColumns.TARGET_SDK_VERSION + " integer");
+                + ApkTable.Cols.TARGET_SDK_VERSION + " integer");
     }
 
     private static boolean columnExists(SQLiteDatabase db,
diff --git a/app/src/main/java/org/fdroid/fdroid/data/RepoPersister.java b/app/src/main/java/org/fdroid/fdroid/data/RepoPersister.java
index 416cbc51d..ff34ffe53 100644
--- a/app/src/main/java/org/fdroid/fdroid/data/RepoPersister.java
+++ b/app/src/main/java/org/fdroid/fdroid/data/RepoPersister.java
@@ -159,8 +159,8 @@ public class RepoPersister {
      */
     private ArrayList<ContentProviderOperation> insertOrUpdateApks(List<Apk> packages) {
         String[] projection = new String[]{
-            ApkProvider.DataColumns.PACKAGE_NAME,
-            ApkProvider.DataColumns.VERSION_CODE,
+                Schema.ApkTable.Cols.PACKAGE_NAME,
+                Schema.ApkTable.Cols.VERSION_CODE,
         };
         List<Apk> existingApks = ApkProvider.Helper.knownApks(context, packages, projection);
         ArrayList<ContentProviderOperation> operations = new ArrayList<>(packages.size());
@@ -245,7 +245,7 @@ public class RepoPersister {
      */
     @Nullable
     private ContentProviderOperation deleteOrphanedApks(List<App> apps, Map<String, List<Apk>> packages) {
-        String[] projection = new String[]{ApkProvider.DataColumns.PACKAGE_NAME, ApkProvider.DataColumns.VERSION_CODE};
+        String[] projection = new String[]{Schema.ApkTable.Cols.PACKAGE_NAME, Schema.ApkTable.Cols.VERSION_CODE};
         List<Apk> existing = ApkProvider.Helper.find(context, repo, apps, projection);
         List<Apk> toDelete = new ArrayList<>();
 
diff --git a/app/src/main/java/org/fdroid/fdroid/data/RepoProvider.java b/app/src/main/java/org/fdroid/fdroid/data/RepoProvider.java
index 3d1e76ac1..31036aaf9 100644
--- a/app/src/main/java/org/fdroid/fdroid/data/RepoProvider.java
+++ b/app/src/main/java/org/fdroid/fdroid/data/RepoProvider.java
@@ -194,7 +194,7 @@ public class RepoProvider extends FDroidProvider {
 
         public static int countAppsForRepo(Context context, long repoId) {
             ContentResolver resolver = context.getContentResolver();
-            final String[] projection = {ApkProvider.DataColumns._COUNT_DISTINCT_ID};
+            final String[] projection = {Schema.ApkTable.Cols._COUNT_DISTINCT_ID};
             Uri apkUri = ApkProvider.getRepoUri(repoId);
             Cursor cursor = resolver.query(apkUri, projection, null, null, null);
             int count = 0;
diff --git a/app/src/main/java/org/fdroid/fdroid/data/Schema.java b/app/src/main/java/org/fdroid/fdroid/data/Schema.java
index 97265d208..3b5a663ad 100644
--- a/app/src/main/java/org/fdroid/fdroid/data/Schema.java
+++ b/app/src/main/java/org/fdroid/fdroid/data/Schema.java
@@ -1,5 +1,7 @@
 package org.fdroid.fdroid.data;
 
+import android.provider.BaseColumns;
+
 /**
  * The authoritative reference to each table/column which should exist in the database.
  * Constants from this interface should be used in preference to string literals when referring to
@@ -70,7 +72,38 @@ public interface Schema {
 
     interface ApkTable {
         String NAME = DBHelper.TABLE_APK;
-        interface Cols extends ApkProvider.DataColumns {}
+        interface Cols extends BaseColumns {
+            String _COUNT_DISTINCT_ID = "countDistinct";
+
+            String PACKAGE_NAME    = "id";
+            String VERSION_NAME    = "version";
+            String REPO_ID         = "repo";
+            String HASH            = "hash";
+            String VERSION_CODE    = "vercode";
+            String NAME            = "apkName";
+            String SIZE            = "size";
+            String SIGNATURE       = "sig";
+            String SOURCE_NAME     = "srcname";
+            String MIN_SDK_VERSION = "minSdkVersion";
+            String TARGET_SDK_VERSION = "targetSdkVersion";
+            String MAX_SDK_VERSION = "maxSdkVersion";
+            String PERMISSIONS     = "permissions";
+            String FEATURES        = "features";
+            String NATIVE_CODE     = "nativecode";
+            String HASH_TYPE       = "hashType";
+            String ADDED_DATE      = "added";
+            String IS_COMPATIBLE   = "compatible";
+            String INCOMPATIBLE_REASONS = "incompatibleReasons";
+            String REPO_VERSION    = "repoVersion";
+            String REPO_ADDRESS    = "repoAddress";
+
+            String[] ALL = {
+                    _ID, PACKAGE_NAME, VERSION_NAME, REPO_ID, HASH, VERSION_CODE, NAME,
+                    SIZE, SIGNATURE, SOURCE_NAME, MIN_SDK_VERSION, TARGET_SDK_VERSION, MAX_SDK_VERSION,
+                    PERMISSIONS, FEATURES, NATIVE_CODE, HASH_TYPE, ADDED_DATE,
+                    IS_COMPATIBLE, REPO_VERSION, REPO_ADDRESS, INCOMPATIBLE_REASONS,
+            };
+        }
     }
 
     interface RepoTable {
diff --git a/app/src/main/java/org/fdroid/fdroid/privileged/views/InstallConfirmActivity.java b/app/src/main/java/org/fdroid/fdroid/privileged/views/InstallConfirmActivity.java
index e4cc05053..766fe316f 100644
--- a/app/src/main/java/org/fdroid/fdroid/privileged/views/InstallConfirmActivity.java
+++ b/app/src/main/java/org/fdroid/fdroid/privileged/views/InstallConfirmActivity.java
@@ -47,6 +47,7 @@ import org.fdroid.fdroid.data.Apk;
 import org.fdroid.fdroid.data.ApkProvider;
 import org.fdroid.fdroid.data.App;
 import org.fdroid.fdroid.data.AppProvider;
+import org.fdroid.fdroid.data.Schema;
 
 /**
  * NOTES:
@@ -191,7 +192,7 @@ public class InstallConfirmActivity extends FragmentActivity implements OnCancel
 
         intent = getIntent();
         Uri uri = intent.getData();
-        Apk apk = ApkProvider.Helper.find(this, uri, ApkProvider.DataColumns.ALL);
+        Apk apk = ApkProvider.Helper.find(this, uri, Schema.ApkTable.Cols.ALL);
         app = AppProvider.Helper.findByPackageName(getContentResolver(), apk.packageName);
 
         appDiff = new AppDiff(getPackageManager(), apk);
diff --git a/app/src/test/java/org/fdroid/fdroid/Assert.java b/app/src/test/java/org/fdroid/fdroid/Assert.java
index 301e0affc..520101ed8 100644
--- a/app/src/test/java/org/fdroid/fdroid/Assert.java
+++ b/app/src/test/java/org/fdroid/fdroid/Assert.java
@@ -10,6 +10,7 @@ import org.fdroid.fdroid.data.ApkProvider;
 import org.fdroid.fdroid.data.AppProvider;
 import org.fdroid.fdroid.data.InstalledAppProvider;
 import org.fdroid.fdroid.data.Schema;
+import org.fdroid.fdroid.data.Schema.ApkTable;
 import org.fdroid.fdroid.data.Schema.AppTable;
 import org.robolectric.shadows.ShadowContentResolver;
 
@@ -206,16 +207,16 @@ public class Assert {
 
         ContentValues values = new ContentValues();
 
-        values.put(ApkProvider.DataColumns.PACKAGE_NAME, id);
-        values.put(ApkProvider.DataColumns.VERSION_CODE, versionCode);
+        values.put(ApkTable.Cols.PACKAGE_NAME, id);
+        values.put(ApkTable.Cols.VERSION_CODE, versionCode);
 
         // Required fields (NOT NULL in the database).
-        values.put(ApkProvider.DataColumns.REPO_ID, 1);
-        values.put(ApkProvider.DataColumns.VERSION_NAME, "The good one");
-        values.put(ApkProvider.DataColumns.HASH, "11111111aaaaaaaa");
-        values.put(ApkProvider.DataColumns.NAME, "Test Apk");
-        values.put(ApkProvider.DataColumns.SIZE, 10000);
-        values.put(ApkProvider.DataColumns.IS_COMPATIBLE, 1);
+        values.put(ApkTable.Cols.REPO_ID, 1);
+        values.put(ApkTable.Cols.VERSION_NAME, "The good one");
+        values.put(ApkTable.Cols.HASH, "11111111aaaaaaaa");
+        values.put(ApkTable.Cols.NAME, "Test Apk");
+        values.put(ApkTable.Cols.SIZE, 10000);
+        values.put(ApkTable.Cols.IS_COMPATIBLE, 1);
 
         values.putAll(additionalValues);
 
diff --git a/app/src/test/java/org/fdroid/fdroid/MultiRepoUpdaterTest.java b/app/src/test/java/org/fdroid/fdroid/MultiRepoUpdaterTest.java
index 2da14d8eb..8e1583b8c 100644
--- a/app/src/test/java/org/fdroid/fdroid/MultiRepoUpdaterTest.java
+++ b/app/src/test/java/org/fdroid/fdroid/MultiRepoUpdaterTest.java
@@ -91,7 +91,7 @@ public abstract class MultiRepoUpdaterTest extends FDroidProviderTest {
     }
 
     protected void assertApp(String packageName, int[] versionCodes) {
-        List<Apk> apks = ApkProvider.Helper.findByPackageName(context, packageName, ApkProvider.DataColumns.ALL);
+        List<Apk> apks = ApkProvider.Helper.findByPackageName(context, packageName);
         assertApksExist(apks, packageName, versionCodes);
     }
 
diff --git a/app/src/test/java/org/fdroid/fdroid/ProperMultiRepoUpdaterTest.java b/app/src/test/java/org/fdroid/fdroid/ProperMultiRepoUpdaterTest.java
index b0e992854..3d6e18abd 100644
--- a/app/src/test/java/org/fdroid/fdroid/ProperMultiRepoUpdaterTest.java
+++ b/app/src/test/java/org/fdroid/fdroid/ProperMultiRepoUpdaterTest.java
@@ -7,6 +7,7 @@ import org.fdroid.fdroid.data.Apk;
 import org.fdroid.fdroid.data.ApkProvider;
 import org.fdroid.fdroid.data.Repo;
 import org.fdroid.fdroid.data.RepoProvider;
+import org.fdroid.fdroid.data.Schema;
 
 import java.util.List;
 
@@ -101,7 +102,7 @@ public class ProperMultiRepoUpdaterTest extends MultiRepoUpdaterTest {
     private void assertMainRepo(List<Repo> allRepos) {
         Repo repo = findRepo(REPO_MAIN, allRepos);
 
-        List<Apk> apks = ApkProvider.Helper.findByRepo(context, repo, ApkProvider.DataColumns.ALL);
+        List<Apk> apks = ApkProvider.Helper.findByRepo(context, repo, Schema.ApkTable.Cols.ALL);
         assertEquals("Apks for main repo", apks.size(), 6);
         assertApksExist(apks, "com.uberspot.a2048", new int[]{18, 19});
         assertApksExist(apks, "org.adaway", new int[]{52, 53, 54});
@@ -127,7 +128,7 @@ public class ProperMultiRepoUpdaterTest extends MultiRepoUpdaterTest {
     private void assertMainArchiveRepo(List<Repo> allRepos) {
         Repo repo = findRepo(REPO_ARCHIVE, allRepos);
 
-        List<Apk> apks = ApkProvider.Helper.findByRepo(context, repo, ApkProvider.DataColumns.ALL);
+        List<Apk> apks = ApkProvider.Helper.findByRepo(context, repo, Schema.ApkTable.Cols.ALL);
         assertEquals("Apks for main archive repo", 13, apks.size());
         assertApksExist(apks, "org.adaway", new int[]{35, 36, 37, 38, 40, 42, 45, 46, 47, 48, 49, 50, 51});
     }
@@ -145,7 +146,7 @@ public class ProperMultiRepoUpdaterTest extends MultiRepoUpdaterTest {
     private void assertConflictingRepo(List<Repo> allRepos) {
         Repo repo = findRepo(REPO_CONFLICTING, allRepos);
 
-        List<Apk> apks = ApkProvider.Helper.findByRepo(context, repo, ApkProvider.DataColumns.ALL);
+        List<Apk> apks = ApkProvider.Helper.findByRepo(context, repo, Schema.ApkTable.Cols.ALL);
         assertEquals("Apks for main repo", 6, apks.size());
         assertApksExist(apks, "org.adaway", new int[]{50, 51, 52, 53});
         assertApksExist(apks, "org.dgtale.icsimport", new int[]{2, 3});
diff --git a/app/src/test/java/org/fdroid/fdroid/data/ApkProviderTest.java b/app/src/test/java/org/fdroid/fdroid/data/ApkProviderTest.java
index d6fcd1b03..cf66909e1 100644
--- a/app/src/test/java/org/fdroid/fdroid/data/ApkProviderTest.java
+++ b/app/src/test/java/org/fdroid/fdroid/data/ApkProviderTest.java
@@ -7,6 +7,7 @@ import android.net.Uri;
 
 import org.fdroid.fdroid.Assert;
 import org.fdroid.fdroid.BuildConfig;
+import org.fdroid.fdroid.data.Schema.ApkTable.Cols;
 import org.fdroid.fdroid.mock.MockApk;
 import org.fdroid.fdroid.mock.MockApp;
 import org.fdroid.fdroid.mock.MockRepo;
@@ -32,7 +33,7 @@ import static org.junit.Assert.fail;
 @RunWith(RobolectricGradleTestRunner.class)
 public class ApkProviderTest extends FDroidProviderTest {
 
-    private static final String[] PROJ = ApkProvider.DataColumns.ALL;
+    private static final String[] PROJ = Cols.ALL;
 
     @Test
     public void testAppApks() {
@@ -89,7 +90,7 @@ public class ApkProviderTest extends FDroidProviderTest {
             "com.example.five",
         };
 
-        List<Apk> all = ApkProvider.Helper.findByRepo(context, new MockRepo(10), ApkProvider.DataColumns.ALL);
+        List<Apk> all = ApkProvider.Helper.findByRepo(context, new MockRepo(10), Cols.ALL);
         List<String> actualIds = new ArrayList<>();
         for (Apk apk : all) {
             actualIds.add(apk.packageName);
@@ -105,7 +106,7 @@ public class ApkProviderTest extends FDroidProviderTest {
 
         assertTotalApkCount(2);
 
-        List<Apk> allRemaining = ApkProvider.Helper.findByRepo(context, new MockRepo(10), ApkProvider.DataColumns.ALL);
+        List<Apk> allRemaining = ApkProvider.Helper.findByRepo(context, new MockRepo(10), Cols.ALL);
         List<String> actualRemainingIds = new ArrayList<>();
         for (Apk apk : allRemaining) {
             actualRemainingIds.add(apk.packageName);
@@ -211,7 +212,7 @@ public class ApkProviderTest extends FDroidProviderTest {
 
     @Test
     public void testCount() {
-        String[] projectionCount = new String[] {ApkProvider.DataColumns._COUNT};
+        String[] projectionCount = new String[] {Cols._COUNT};
 
         for (int i = 0; i < 13; i++) {
             Assert.insertApk(contentResolver, "com.example", i);
@@ -226,7 +227,7 @@ public class ApkProviderTest extends FDroidProviderTest {
         assertResultCount(1, allWithCount);
 
         allWithCount.moveToFirst();
-        int countColumn = allWithCount.getColumnIndex(ApkProvider.DataColumns._COUNT);
+        int countColumn = allWithCount.getColumnIndex(Cols._COUNT);
         assertEquals(13, allWithCount.getInt(countColumn));
         allWithCount.close();
     }
@@ -268,15 +269,15 @@ public class ApkProviderTest extends FDroidProviderTest {
         assertResultCount(0, queryAllApks());
 
         ContentValues values = new ContentValues();
-        values.put(ApkProvider.DataColumns.REPO_ID, 10);
-        values.put(ApkProvider.DataColumns.REPO_ADDRESS, "http://example.com");
-        values.put(ApkProvider.DataColumns.REPO_VERSION, 3);
-        values.put(ApkProvider.DataColumns.FEATURES, "Some features");
+        values.put(Cols.REPO_ID, 10);
+        values.put(Cols.REPO_ADDRESS, "http://example.com");
+        values.put(Cols.REPO_VERSION, 3);
+        values.put(Cols.FEATURES, "Some features");
         Uri uri = Assert.insertApk(contentResolver, "com.example.com", 1, values);
 
         assertResultCount(1, queryAllApks());
 
-        String[] projections = ApkProvider.DataColumns.ALL;
+        String[] projections = Cols.ALL;
         Cursor cursor = contentResolver.query(uri, projections, null, null, null);
         cursor.moveToFirst();
         Apk apk = new Apk(cursor);
@@ -340,8 +341,8 @@ public class ApkProviderTest extends FDroidProviderTest {
         Collections.addAll(apksToCheck, unknown);
 
         String[] projection = {
-            ApkProvider.DataColumns.PACKAGE_NAME,
-            ApkProvider.DataColumns.VERSION_CODE,
+            Cols.PACKAGE_NAME,
+            Cols.VERSION_CODE,
         };
 
         List<Apk> knownApks = ApkProvider.Helper.knownApks(context, apksToCheck, projection);
@@ -394,7 +395,7 @@ public class ApkProviderTest extends FDroidProviderTest {
 
         Uri apkUri = Assert.insertApk(contentResolver, "com.example", 10);
 
-        String[] allFields = ApkProvider.DataColumns.ALL;
+        String[] allFields = Cols.ALL;
         Cursor cursor = contentResolver.query(apkUri, allFields, null, null, null);
         assertResultCount(1, cursor);
 
@@ -455,9 +456,9 @@ public class ApkProviderTest extends FDroidProviderTest {
         }
 
         ContentValues values = new ContentValues();
-        values.put(ApkProvider.DataColumns.VERSION_NAME, "v1.1");
-        values.put(ApkProvider.DataColumns.HASH, "xxxxyyyy");
-        values.put(ApkProvider.DataColumns.HASH_TYPE, "a hash type");
+        values.put(Cols.VERSION_NAME, "v1.1");
+        values.put(Cols.HASH, "xxxxyyyy");
+        values.put(Cols.HASH_TYPE, "a hash type");
         Assert.insertApk(contentResolver, "com.example", 11, values);
 
         // ...and a few more for good measure...
@@ -478,8 +479,8 @@ public class ApkProviderTest extends FDroidProviderTest {
         assertEquals("a hash type", apk.hashType);
 
         String[] projection = {
-            ApkProvider.DataColumns.PACKAGE_NAME,
-            ApkProvider.DataColumns.HASH,
+            Cols.PACKAGE_NAME,
+            Cols.HASH,
         };
 
         Apk apkLessFields = ApkProvider.Helper.find(context, "com.example", 11, projection);
@@ -537,7 +538,7 @@ public class ApkProviderTest extends FDroidProviderTest {
 
     protected Apk insertApkForRepo(String id, int versionCode, long repoId) {
         ContentValues additionalValues = new ContentValues();
-        additionalValues.put(ApkProvider.DataColumns.REPO_ID, repoId);
+        additionalValues.put(Cols.REPO_ID, repoId);
         Uri uri = Assert.insertApk(contentResolver, id, versionCode, additionalValues);
         return ApkProvider.Helper.get(context, uri);
     }
diff --git a/app/src/test/java/org/fdroid/fdroid/data/ProviderUriTests.java b/app/src/test/java/org/fdroid/fdroid/data/ProviderUriTests.java
index 7a1fb6f77..6aeb9e52d 100644
--- a/app/src/test/java/org/fdroid/fdroid/data/ProviderUriTests.java
+++ b/app/src/test/java/org/fdroid/fdroid/data/ProviderUriTests.java
@@ -110,7 +110,7 @@ public class ProviderUriTests {
     @Test
     public void validApkProviderUris() {
         ShadowContentResolver.registerProvider(ApkProvider.getAuthority(), new ApkProvider());
-        String[] projection = new String[] {ApkProvider.DataColumns._ID};
+        String[] projection = new String[] {Schema.ApkTable.Cols._ID};
 
         List<Apk> apks = new ArrayList<>(10);
         for (int i = 0; i < 10; i++) {
@@ -127,7 +127,7 @@ public class ProviderUriTests {
 
     @Test(expected = IllegalArgumentException.class)
     public void invalidApkUrisWithTooManyApks() {
-        String[] projection = ApkProvider.DataColumns.ALL;
+        String[] projection = Schema.ApkTable.Cols.ALL;
 
         List<Apk> manyApks = new ArrayList<>(ApkProvider.MAX_APKS_TO_QUERY - 5);
         for (int i = 0; i < ApkProvider.MAX_APKS_TO_QUERY - 1; i++) {