From fc0df0dcf4dd0d5f13de82d7cd9254b2b48cb62d Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 5 Apr 2016 10:59:08 +0200 Subject: [PATCH 1/7] make db maxSdkValues values use Byte.MAX_VALUE as max not 0 Having 0 mean max makes the logic confusing when maxSdkValue is used in variable. This sanitizes the data so that maxSdkValue is always just a plain int value that can be used to test against. It does this by defaulting to Byte.MAX_VALUE (127) if it is not explicitly set. At the rate of 24 SDK numbers in 8 years, that gives us about 24 years before we have to think about setting it to Short.MAX_VALUE. This fixes an issue created by e021eb5ca7e8f05dbce7c1b87833722542138302 --- app/src/main/java/org/fdroid/fdroid/data/Apk.java | 2 +- .../main/java/org/fdroid/fdroid/data/DBHelper.java | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) 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 72f26c7d9..09f694bf0 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/Apk.java +++ b/app/src/main/java/org/fdroid/fdroid/data/Apk.java @@ -19,7 +19,7 @@ public class Apk extends ValueObject implements Comparable { public String hash; public String hashType; public int minSdkVersion; // 0 if unknown - public int maxSdkVersion; // 0 if none + public int maxSdkVersion = Byte.MAX_VALUE; // "infinity" if not set public Date added; public Utils.CommaSeparatedList permissions; // null if empty or // unknown 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 1f0fe24f3..200cdcb65 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java +++ b/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java @@ -106,7 +106,7 @@ class DBHelper extends SQLiteOpenHelper { + " );"; private static final String DROP_TABLE_INSTALLED_APP = "DROP TABLE " + TABLE_INSTALLED_APP + ";"; - private static final int DB_VERSION = 53; + private static final int DB_VERSION = 54; private final Context context; @@ -291,6 +291,7 @@ class DBHelper extends SQLiteOpenHelper { recreateInstalledCache(db, oldVersion); addCredentialsToRepo(db, oldVersion); addAuthorToApp(db, oldVersion); + useMaxValueInMaxSdkVersion(db, oldVersion); } /** @@ -475,6 +476,15 @@ class DBHelper extends SQLiteOpenHelper { } } + private void useMaxValueInMaxSdkVersion(SQLiteDatabase db, int oldVersion) { + if (oldVersion < 54) { + 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); + } + } + /** * By clearing the etags stored in the repo table, it means that next time the user updates * their repos (either manually or on a scheduled task), they will update regardless of whether From 70864e347930e8c04888db91f78cea1d583e0dbb Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 4 Apr 2016 11:59:35 +0200 Subject: [PATCH 2/7] use custom proguard config for running tests The new Android Testing Support library stuff causes proguard to freak out, so make proguard ignore all that stuff when running tests. --- app/build.gradle | 1 + app/src/androidTest/proguard-rules.pro | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 app/src/androidTest/proguard-rules.pro diff --git a/app/build.gradle b/app/build.gradle index 2eaebe349..ae3c59e49 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -132,6 +132,7 @@ android { minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + testProguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro', 'src/androidTest/proguard-rules.pro' } debug { testCoverageEnabled = true diff --git a/app/src/androidTest/proguard-rules.pro b/app/src/androidTest/proguard-rules.pro new file mode 100644 index 000000000..ef824638a --- /dev/null +++ b/app/src/androidTest/proguard-rules.pro @@ -0,0 +1,16 @@ +-dontwarn android.test.** +-dontwarn android.support.test.** +-dontnote junit.framework.** +-dontnote junit.runner.** + +# Uncomment this if you use Mockito +#-dontwarn org.mockito.** + +-keep class org.hamcrest.** { *; } +-dontwarn org.hamcrest.** + +-keep class org.junit.** { *; } +-dontwarn org.junit.** + +-keep class junit.** { *; } +-dontwarn junit.** From 0e1584f083d3ae014c85db35af35e948ab3a0509 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 5 Apr 2016 09:13:08 +0200 Subject: [PATCH 3/7] ignore gradle.properties This file is generated by Android Studio whenever I'm using a proxy like Tor. Its not used otherwise, and should not be checked into git. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 159567062..91d7c59a9 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ build.xml # Gradle files .gradle/ build/ +gradle.properties # Local configuration file (sdk path, etc) local.properties From 9d6909860577c6ae7109c4de408bf7c8dd861bd7 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 5 Apr 2016 11:58:25 +0200 Subject: [PATCH 4/7] purge unused code from Installer classes --- .../fdroid/installer/DefaultInstaller.java | 12 -------- .../installer/DefaultSdk14Installer.java | 12 -------- .../fdroid/fdroid/installer/Installer.java | 29 ------------------- .../fdroid/installer/PrivilegedInstaller.java | 12 -------- 4 files changed, 65 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/installer/DefaultInstaller.java b/app/src/main/java/org/fdroid/fdroid/installer/DefaultInstaller.java index b25009ffc..34c214a88 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/DefaultInstaller.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/DefaultInstaller.java @@ -27,7 +27,6 @@ import android.content.pm.PackageManager; import android.net.Uri; import java.io.File; -import java.util.List; /** * For Android < 4: Default Installer using the public PackageManager API of @@ -61,11 +60,6 @@ public class DefaultInstaller extends Installer { } } - @Override - protected void installPackageInternal(List apkFiles) throws AndroidNotCompatibleException { - // not used - } - @Override protected void deletePackageInternal(String packageName) throws AndroidNotCompatibleException { try { @@ -103,10 +97,4 @@ public class DefaultInstaller extends Installer { return false; } } - - @Override - public boolean supportsUnattendedOperations() { - return false; - } - } diff --git a/app/src/main/java/org/fdroid/fdroid/installer/DefaultSdk14Installer.java b/app/src/main/java/org/fdroid/fdroid/installer/DefaultSdk14Installer.java index b498a8076..6f4d18f4d 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/DefaultSdk14Installer.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/DefaultSdk14Installer.java @@ -29,7 +29,6 @@ import android.net.Uri; import android.os.Build; import java.io.File; -import java.util.List; /** * For Android >= 4.0: Default Installer using the public PackageManager API of @@ -73,11 +72,6 @@ public class DefaultSdk14Installer extends Installer { } } - @Override - protected void installPackageInternal(List apkFiles) throws AndroidNotCompatibleException { - // not used - } - @Override protected void deletePackageInternal(String packageName) throws AndroidNotCompatibleException { try { @@ -129,10 +123,4 @@ public class DefaultSdk14Installer extends Installer { return false; } } - - @Override - public boolean supportsUnattendedOperations() { - return false; - } - } diff --git a/app/src/main/java/org/fdroid/fdroid/installer/Installer.java b/app/src/main/java/org/fdroid/fdroid/installer/Installer.java index e038ae7bf..c12bf9667 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/Installer.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/Installer.java @@ -30,7 +30,6 @@ import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.privileged.install.InstallExtensionDialogActivity; import java.io.File; -import java.util.List; /** * Abstract Installer class. Also provides static methods to automatically @@ -53,20 +52,9 @@ public abstract class Installer { private static final long serialVersionUID = -8343133906463328027L; - public AndroidNotCompatibleException() { - } - - public AndroidNotCompatibleException(String message) { - super(message); - } - public AndroidNotCompatibleException(Throwable cause) { super(cause); } - - public AndroidNotCompatibleException(String message, Throwable cause) { - super(message, cause); - } } /** @@ -175,18 +163,6 @@ public abstract class Installer { installPackageInternal(apkFile); } - public void installPackage(List apkFiles) throws AndroidNotCompatibleException { - // check if files exist... - for (File apkFile : apkFiles) { - if (!apkFile.exists()) { - Log.e(TAG, "Couldn't find file " + apkFile + " to install."); - return; - } - } - - installPackageInternal(apkFiles); - } - public void deletePackage(String packageName) throws AndroidNotCompatibleException { // check if package exists before proceeding... try { @@ -218,13 +194,8 @@ public abstract class Installer { protected abstract void installPackageInternal(File apkFile) throws AndroidNotCompatibleException; - protected abstract void installPackageInternal(List apkFiles) - throws AndroidNotCompatibleException; - protected abstract void deletePackageInternal(String packageName) throws AndroidNotCompatibleException; public abstract boolean handleOnActivityResult(int requestCode, int resultCode, Intent data); - - public abstract boolean supportsUnattendedOperations(); } diff --git a/app/src/main/java/org/fdroid/fdroid/installer/PrivilegedInstaller.java b/app/src/main/java/org/fdroid/fdroid/installer/PrivilegedInstaller.java index f447b29e4..887115124 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/PrivilegedInstaller.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/PrivilegedInstaller.java @@ -44,7 +44,6 @@ import org.fdroid.fdroid.privileged.views.AppSecurityPermissions; import org.fdroid.fdroid.privileged.views.InstallConfirmActivity; import java.io.File; -import java.util.List; /** * Installer based on using internal hidden APIs of the Android OS, which are @@ -237,12 +236,6 @@ public class PrivilegedInstaller extends Installer { Context.BIND_AUTO_CREATE); } - @Override - protected void installPackageInternal(List apkFiles) - throws AndroidNotCompatibleException { - // not used - } - @Override protected void deletePackageInternal(final String packageName) throws AndroidNotCompatibleException { @@ -368,11 +361,6 @@ public class PrivilegedInstaller extends Installer { } } - @Override - public boolean supportsUnattendedOperations() { - return false; - } - public static final int INSTALL_REPLACE_EXISTING = 2; /** From 514e83e60448cf68747a14fa1ef2b6f4708f48fe Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sat, 2 Apr 2016 23:38:52 +0200 Subject: [PATCH 5/7] convert Downloader's outputFile to a read-only property Since Downloader's outputFile variable is final, it can safely be used as a public property variable. This makes it simple to use in subclasses. Making it a public final variable rather than a getter also communicates that the value does not change since there is no getter method that could potentially change it. http://binkley.blogspot.com/2005/01/read-only-properties-in-java.html --- app/src/main/java/org/fdroid/fdroid/RepoUpdater.java | 8 ++++---- .../main/java/org/fdroid/fdroid/net/Downloader.java | 11 +---------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/RepoUpdater.java b/app/src/main/java/org/fdroid/fdroid/RepoUpdater.java index 2c75c06bd..653e975b2 100644 --- a/app/src/main/java/org/fdroid/fdroid/RepoUpdater.java +++ b/app/src/main/java/org/fdroid/fdroid/RepoUpdater.java @@ -106,9 +106,9 @@ public class RepoUpdater { } } catch (IOException e) { - if (downloader != null && downloader.getFile() != null) { - if (!downloader.getFile().delete()) { - Log.w(TAG, "Couldn't delete file: " + downloader.getFile().getAbsolutePath()); + if (downloader != null && downloader.outputFile != null) { + if (!downloader.outputFile.delete()) { + Log.w(TAG, "Couldn't delete file: " + downloader.outputFile.getAbsolutePath()); } } @@ -136,7 +136,7 @@ public class RepoUpdater { // Don't worry about checking the status code for 200. If it was a // successful download, then we will have a file ready to use: cacheTag = downloader.getCacheTag(); - processDownloadedFile(downloader.getFile()); + processDownloadedFile(downloader.outputFile); } } diff --git a/app/src/main/java/org/fdroid/fdroid/net/Downloader.java b/app/src/main/java/org/fdroid/fdroid/net/Downloader.java index 61b6af116..45ba5b884 100644 --- a/app/src/main/java/org/fdroid/fdroid/net/Downloader.java +++ b/app/src/main/java/org/fdroid/fdroid/net/Downloader.java @@ -27,7 +27,7 @@ public abstract class Downloader { private final OutputStream outputStream; - private final File outputFile; + public final File outputFile; protected final URL sourceUrl; protected String cacheTag; @@ -78,15 +78,6 @@ public abstract class Downloader { return cacheTag != null; } - /** - * Only available if you passed a context object into the constructor - * (rather than an outputStream, which may or may not be associated with - * a file). - */ - public File getFile() { - return outputFile; - } - public abstract boolean hasChanged(); protected abstract int totalDownloadSize(); From fd51fad73b09922e80271ee429214109b6e035a0 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 31 Mar 2016 21:44:58 +0200 Subject: [PATCH 6/7] keep the core Downloader classes pure Java for easy testing --- .../main/java/org/fdroid/fdroid/net/Downloader.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/net/Downloader.java b/app/src/main/java/org/fdroid/fdroid/net/Downloader.java index 45ba5b884..f3ed8e207 100644 --- a/app/src/main/java/org/fdroid/fdroid/net/Downloader.java +++ b/app/src/main/java/org/fdroid/fdroid/net/Downloader.java @@ -1,7 +1,5 @@ package org.fdroid.fdroid.net; -import android.support.annotation.NonNull; - import org.fdroid.fdroid.Utils; import java.io.File; @@ -32,6 +30,11 @@ public abstract class Downloader { protected final URL sourceUrl; protected String cacheTag; + /** + * This is meant only to send progress to {@link DownloaderService}. This + * also keeps this class pure Java so that it can be tested on the JVM, + * without requiring an Android device or emulator. + */ interface DownloaderProgressListener { void sendProgress(URL sourceUrl, int bytesRead, int totalBytes); } @@ -213,12 +216,12 @@ public abstract class Downloader { } @Override - public int read(@NonNull byte[] buffer) throws IOException { + public int read(byte[] buffer) throws IOException { return toWrap.read(buffer); } @Override - public int read(@NonNull byte[] buffer, int byteOffset, int byteCount) throws IOException { + public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException { return toWrap.read(buffer, byteOffset, byteCount); } From 35c2ef8c1c3acae108df4322f057f1f300bea3ed Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 21 Mar 2016 11:45:20 +0100 Subject: [PATCH 7/7] re-add SNI support to guardianproject.info repo Apparently, it uses SNI, but does not always fail without SNI support. --- app/src/main/java/org/fdroid/fdroid/net/HttpDownloader.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/net/HttpDownloader.java b/app/src/main/java/org/fdroid/fdroid/net/HttpDownloader.java index 8550d9eaf..f9d7ece2b 100644 --- a/app/src/main/java/org/fdroid/fdroid/net/HttpDownloader.java +++ b/app/src/main/java/org/fdroid/fdroid/net/HttpDownloader.java @@ -114,8 +114,7 @@ public class HttpDownloader extends Downloader { // workaround until NetCipher supports HTTPS SNI // https://gitlab.com/fdroid/fdroidclient/issues/431 if (connection instanceof HttpsURLConnection - && "f-droid.org".equals(sourceUrl.getHost()) - && "guardianproject.info".equals(sourceUrl.getHost())) { + && "f-droid.org".equals(sourceUrl.getHost())) { ((HttpsURLConnection) connection).setSSLSocketFactory(HttpsURLConnection.getDefaultSSLSocketFactory()); }