From d54748ff39ee9701d867788579dee7b5d4d20c3d Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 23 May 2016 18:23:31 +0200 Subject: [PATCH 1/4] SuppressLint("ParcelCreator") on MockApplicationInfo Apparently, the CREATOR field is not (yet?) needed in the tests, since they work without it. This gets us closer to making lint errors fail the CI builds. closes #580 --- app/src/androidTest/java/mock/MockApplicationInfo.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/androidTest/java/mock/MockApplicationInfo.java b/app/src/androidTest/java/mock/MockApplicationInfo.java index abd6c2e22..4d88d3f9b 100644 --- a/app/src/androidTest/java/mock/MockApplicationInfo.java +++ b/app/src/androidTest/java/mock/MockApplicationInfo.java @@ -1,9 +1,11 @@ package mock; +import android.annotation.SuppressLint; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +@SuppressLint("ParcelCreator") public class MockApplicationInfo extends ApplicationInfo { private final PackageInfo info; From 02d98826a935db79dc3c141a317dcb3f52608a7f Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 23 May 2016 16:05:57 +0200 Subject: [PATCH 2/4] when parsing APKs for the local repo, correctly set maxSdkVersion The original logic had maxSdkVersion=0 meaning infinity. That was changed to be a very large value SDK_VERSION_MAX_VALUE, but getMinMaxSdkVersion() was still returning 0 for APKs where maxSdkVersion was not set. This is a follow up on fc0df0dcf4dd0d5f13de82d7cd9254b2b48cb62d --- .../main/java/org/fdroid/fdroid/RepoXMLHandler.java | 8 ++++++-- app/src/main/java/org/fdroid/fdroid/Utils.java | 11 ++++++----- app/src/main/java/org/fdroid/fdroid/data/Apk.java | 3 ++- .../org/fdroid/fdroid/localrepo/LocalRepoManager.java | 9 +++++++-- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/RepoXMLHandler.java b/app/src/main/java/org/fdroid/fdroid/RepoXMLHandler.java index ca2d5ed9c..521ce3764 100644 --- a/app/src/main/java/org/fdroid/fdroid/RepoXMLHandler.java +++ b/app/src/main/java/org/fdroid/fdroid/RepoXMLHandler.java @@ -126,10 +126,14 @@ public class RepoXMLHandler extends DefaultHandler { curapk.apkName = str; break; case "sdkver": - curapk.minSdkVersion = Utils.parseInt(str, 0); + curapk.minSdkVersion = Utils.parseInt(str, Apk.SDK_VERSION_MIN_VALUE); break; case "maxsdkver": - curapk.maxSdkVersion = Utils.parseInt(str, 0); + curapk.maxSdkVersion = Utils.parseInt(str, Apk.SDK_VERSION_MAX_VALUE); + if (curapk.maxSdkVersion == 0) { + // before fc0df0dcf4dd0d5f13de82d7cd9254b2b48cb62d, this could be 0 + curapk.maxSdkVersion = Apk.SDK_VERSION_MAX_VALUE; + } break; case "added": curapk.added = Utils.parseDate(str, null); diff --git a/app/src/main/java/org/fdroid/fdroid/Utils.java b/app/src/main/java/org/fdroid/fdroid/Utils.java index 733280f52..a190af20b 100644 --- a/app/src/main/java/org/fdroid/fdroid/Utils.java +++ b/app/src/main/java/org/fdroid/fdroid/Utils.java @@ -39,6 +39,7 @@ import com.nostra13.universalimageloader.utils.StorageUtils; import org.apache.commons.io.FileUtils; import org.fdroid.fdroid.compat.FileCompat; +import org.fdroid.fdroid.data.Apk; import org.fdroid.fdroid.data.Repo; import org.fdroid.fdroid.data.SanitizedFile; import org.xml.sax.XMLReader; @@ -226,8 +227,8 @@ public final class Utils { /* PackageManager doesn't give us the min and max sdk versions, so we have * to parse it */ - private static int getMinMaxSdkVersion(Context context, String packageName, - String attrName) { + private static int getSdkVersion(Context context, String packageName, + String attrName, final int defaultValue) { try { AssetManager am = context.createPackageContext(packageName, 0).getAssets(); XmlResourceParser xml = am.openXmlResourceParser("AndroidManifest.xml"); @@ -245,15 +246,15 @@ public final class Utils { } catch (PackageManager.NameNotFoundException | IOException | XmlPullParserException e) { Log.e(TAG, "Could not get min/max sdk version", e); } - return 0; + return defaultValue; } public static int getMinSdkVersion(Context context, String packageName) { - return getMinMaxSdkVersion(context, packageName, "minSdkVersion"); + return getSdkVersion(context, packageName, "minSdkVersion", Apk.SDK_VERSION_MIN_VALUE); } public static int getMaxSdkVersion(Context context, String packageName) { - return getMinMaxSdkVersion(context, packageName, "maxSdkVersion"); + return getSdkVersion(context, packageName, "maxSdkVersion", Apk.SDK_VERSION_MAX_VALUE); } // return a fingerprint formatted for display 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 377bf37bf..98844f15b 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/Apk.java +++ b/app/src/main/java/org/fdroid/fdroid/data/Apk.java @@ -14,6 +14,7 @@ public class Apk extends ValueObject implements Comparable { // Using only byte-range keeps it only 8-bits in the SQLite database public static final int SDK_VERSION_MAX_VALUE = Byte.MAX_VALUE; + public static final int SDK_VERSION_MIN_VALUE = 0; public String packageName; public String versionName; @@ -22,7 +23,7 @@ public class Apk extends ValueObject implements Comparable { public long repo; // ID of the repo it comes from public String hash; public String hashType; - public int minSdkVersion; // 0 if unknown + public int minSdkVersion = SDK_VERSION_MIN_VALUE; // 0 if unknown public int maxSdkVersion = SDK_VERSION_MAX_VALUE; // "infinity" if not set public Date added; public Utils.CommaSeparatedList permissions; // null if empty or diff --git a/app/src/main/java/org/fdroid/fdroid/localrepo/LocalRepoManager.java b/app/src/main/java/org/fdroid/fdroid/localrepo/LocalRepoManager.java index 5826ba062..9b49f0ba1 100644 --- a/app/src/main/java/org/fdroid/fdroid/localrepo/LocalRepoManager.java +++ b/app/src/main/java/org/fdroid/fdroid/localrepo/LocalRepoManager.java @@ -23,6 +23,7 @@ import org.fdroid.fdroid.Hasher; import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.R; import org.fdroid.fdroid.Utils; +import org.fdroid.fdroid.data.Apk; import org.fdroid.fdroid.data.App; import org.fdroid.fdroid.data.SanitizedFile; import org.xmlpull.v1.XmlPullParserException; @@ -452,9 +453,13 @@ public final class LocalRepoManager { tagHash(app); tag("sig", app.installedApk.sig.toLowerCase(Locale.US)); tag("size", app.installedApk.installedFile.length()); - tag("sdkver", app.installedApk.minSdkVersion); - tag("maxsdkver", app.installedApk.maxSdkVersion); tag("added", app.installedApk.added); + if (app.installedApk.minSdkVersion > Apk.SDK_VERSION_MIN_VALUE) { + tag("sdkver", app.installedApk.minSdkVersion); + } + if (app.installedApk.maxSdkVersion < Apk.SDK_VERSION_MAX_VALUE) { + tag("maxsdkver", app.installedApk.maxSdkVersion); + } tagFeatures(app); tagPermissions(app); tagNativecode(app); From f08f8cb53d8918c39c5ce04331c67815a6ed79c1 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 23 May 2016 14:26:52 +0200 Subject: [PATCH 3/4] only parse once when looking for min/max SDK version When building APK instances from installed apps, the minSdkVersion and maxSdkVersion needs to be parsed directly from the APK's Android Manifest, since PackageManager does not provide a method to get it how we need it. Previously, the whole AndroidManifest.xml file was parsed entirely twice, once for minSdkVersion then for maxSdkVersion. --- .../main/java/org/fdroid/fdroid/Utils.java | 37 ------------------ .../main/java/org/fdroid/fdroid/data/App.java | 39 ++++++++++++++++++- 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/Utils.java b/app/src/main/java/org/fdroid/fdroid/Utils.java index a190af20b..c93a6e466 100644 --- a/app/src/main/java/org/fdroid/fdroid/Utils.java +++ b/app/src/main/java/org/fdroid/fdroid/Utils.java @@ -20,8 +20,6 @@ package org.fdroid.fdroid; import android.content.Context; import android.content.pm.PackageManager; -import android.content.res.AssetManager; -import android.content.res.XmlResourceParser; import android.graphics.Bitmap; import android.net.Uri; import android.support.annotation.NonNull; @@ -39,12 +37,9 @@ import com.nostra13.universalimageloader.utils.StorageUtils; import org.apache.commons.io.FileUtils; import org.fdroid.fdroid.compat.FileCompat; -import org.fdroid.fdroid.data.Apk; import org.fdroid.fdroid.data.Repo; import org.fdroid.fdroid.data.SanitizedFile; import org.xml.sax.XMLReader; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; import java.io.BufferedInputStream; import java.io.Closeable; @@ -225,38 +220,6 @@ public final class Utils { return ANDROID_VERSION_NAMES[sdkLevel]; } - /* PackageManager doesn't give us the min and max sdk versions, so we have - * to parse it */ - private static int getSdkVersion(Context context, String packageName, - String attrName, final int defaultValue) { - try { - AssetManager am = context.createPackageContext(packageName, 0).getAssets(); - XmlResourceParser xml = am.openXmlResourceParser("AndroidManifest.xml"); - int eventType = xml.getEventType(); - while (eventType != XmlPullParser.END_DOCUMENT) { - if (eventType == XmlPullParser.START_TAG && "uses-sdk".equals(xml.getName())) { - for (int j = 0; j < xml.getAttributeCount(); j++) { - if (xml.getAttributeName(j).equals(attrName)) { - return Integer.parseInt(xml.getAttributeValue(j)); - } - } - } - eventType = xml.nextToken(); - } - } catch (PackageManager.NameNotFoundException | IOException | XmlPullParserException e) { - Log.e(TAG, "Could not get min/max sdk version", e); - } - return defaultValue; - } - - public static int getMinSdkVersion(Context context, String packageName) { - return getSdkVersion(context, packageName, "minSdkVersion", Apk.SDK_VERSION_MIN_VALUE); - } - - public static int getMaxSdkVersion(Context context, String packageName) { - return getSdkVersion(context, packageName, "maxSdkVersion", Apk.SDK_VERSION_MAX_VALUE); - } - // return a fingerprint formatted for display public static String formatFingerprint(Context context, String fingerprint) { if (TextUtils.isEmpty(fingerprint) diff --git a/app/src/main/java/org/fdroid/fdroid/data/App.java b/app/src/main/java/org/fdroid/fdroid/data/App.java index 94e1af011..5e68d540b 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/App.java +++ b/app/src/main/java/org/fdroid/fdroid/data/App.java @@ -7,6 +7,8 @@ import android.content.pm.ApplicationInfo; import android.content.pm.FeatureInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.res.AssetManager; +import android.content.res.XmlResourceParser; import android.database.Cursor; import android.os.Parcelable; import android.text.TextUtils; @@ -15,6 +17,8 @@ import android.util.Log; import org.fdroid.fdroid.AppFilter; import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.Utils; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; import java.io.File; import java.io.IOException; @@ -293,8 +297,9 @@ public class App extends ValueObject implements Comparable { apk.versionName = packageInfo.versionName; apk.versionCode = packageInfo.versionCode; apk.added = this.added; - apk.minSdkVersion = Utils.getMinSdkVersion(context, packageName); - apk.maxSdkVersion = Utils.getMaxSdkVersion(context, packageName); + int[] minMaxSdkVersions = getMinMaxSdkVersions(context, packageName); + apk.minSdkVersion = minMaxSdkVersions[0]; + apk.maxSdkVersion = minMaxSdkVersions[1]; apk.packageName = this.packageName; apk.permissions = Utils.CommaSeparatedList.make(packageInfo.requestedPermissions); apk.apkName = apk.packageName + "_" + apk.versionCode + ".apk"; @@ -476,4 +481,34 @@ public class App extends ValueObject implements Comparable { public String getSuggestedVersionName() { return suggestedVersionName; } + + /** + * {@link PackageManager} doesn't give us {@code minSdkVersion} and {@code maxSdkVersion}, + * so we have to parse it straight from {@code } in {@code AndroidManifest.xml}. + */ + private static int[] getMinMaxSdkVersions(Context context, String packageName) { + int minSdkVersion = Apk.SDK_VERSION_MIN_VALUE; + int maxSdkVersion = Apk.SDK_VERSION_MAX_VALUE; + try { + AssetManager am = context.createPackageContext(packageName, 0).getAssets(); + XmlResourceParser xml = am.openXmlResourceParser("AndroidManifest.xml"); + int eventType = xml.getEventType(); + while (eventType != XmlPullParser.END_DOCUMENT) { + if (eventType == XmlPullParser.START_TAG && "uses-sdk".equals(xml.getName())) { + for (int j = 0; j < xml.getAttributeCount(); j++) { + if (xml.getAttributeName(j).equals("minSdkVersion")) { + minSdkVersion = Integer.parseInt(xml.getAttributeValue(j)); + } else if (xml.getAttributeName(j).equals("maxSdkVersion")) { + maxSdkVersion = Integer.parseInt(xml.getAttributeValue(j)); + } + } + break; + } + eventType = xml.nextToken(); + } + } catch (PackageManager.NameNotFoundException | IOException | XmlPullParserException e) { + Log.e(TAG, "Could not get min/max sdk version", e); + } + return new int[]{minSdkVersion, maxSdkVersion}; + } } From 5f623e0c4a0bf0bd2ce4319aa6d43217333b98a7 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 23 May 2016 22:32:03 +0200 Subject: [PATCH 4/4] after downloading is complete, update notification to "Tap to install" f9a30d2e1c9d95302e8f4dd0e733d019f70bed66 broke the "Tap to install" aspect. --- .../installer/InstallManagerService.java | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/installer/InstallManagerService.java b/app/src/main/java/org/fdroid/fdroid/installer/InstallManagerService.java index 809825921..144eeef95 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/InstallManagerService.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/InstallManagerService.java @@ -240,7 +240,7 @@ public class InstallManagerService extends Service { if (AppDetails.isAppVisible(apk.packageName)) { cancelNotification(urlString); } else { - notifyDownloadComplete(urlString, builder, apk); + notifyDownloadComplete(urlString, apk); } unregisterDownloaderReceivers(urlString); } @@ -312,9 +312,14 @@ public class InstallManagerService extends Service { /** * Post a notification about a completed download. {@code packageName} must be a valid - * and currently in the app index database. + * and currently in the app index database. This must create a new {@code Builder} + * instance otherwise the progress/cancel stuff does not go away. + * + * @see Issue 47809: + * Removing the progress bar from a notification should cause the notification's content + * text to return to normal size */ - private void notifyDownloadComplete(String urlString, NotificationCompat.Builder builder, Apk apk) { + private void notifyDownloadComplete(String urlString, Apk apk) { String title; try { PackageManager pm = getPackageManager(); @@ -325,12 +330,16 @@ public class InstallManagerService extends Service { } int downloadUrlId = urlString.hashCode(); - builder.setAutoCancel(true) + notificationManager.cancel(downloadUrlId); + Notification notification = new NotificationCompat.Builder(this) + .setAutoCancel(true) .setOngoing(false) .setContentTitle(title) + .setContentIntent(getAppDetailsIntent(downloadUrlId, apk)) .setSmallIcon(android.R.drawable.stat_sys_download_done) - .setContentText(getString(R.string.tap_to_install)); - notificationManager.notify(downloadUrlId, builder.build()); + .setContentText(getString(R.string.tap_to_install)) + .build(); + notificationManager.notify(downloadUrlId, notification); } /**