From 34dbf49f6c162e1f6c93d2647e92e824a55a3932 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 24 Feb 2017 22:20:02 +0100 Subject: [PATCH 1/6] gitlab-ci: put all the static tests into test job gitlab-ci used to run all of our jobs in parallel, now it mostly seems to run them sequentially. So splitting up the various parts of the CI suite into separate jobs mostly slows things down. This combines the static tests into one job (lint, pmd, checkstyle, tools) with the JVM tests aka Robolectric. That makes three jobs from the previous six. --- .gitlab-ci.yml | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 71f62b25f..6dfd02709 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,10 +10,16 @@ before_script: test: script: + - cd app + - ./tools/langs-list-check.py + - ./tools/check-string-format.py + - cd .. - ./gradlew assemble -PdisablePreDex # always report on lint errors to the build log - sed -i -e 's,textReport .*,textReport true,' app/build.gradle - ./gradlew lint -PdisablePreDex + - ./gradlew pmd -PdisablePreDex + - ./gradlew checkstyle -PdisablePreDex - ./gradlew test -PdisablePreDex || { for log in app/build/reports/*ests/*/*ml; do echo "read $log here:"; @@ -64,24 +70,6 @@ connected24: done - exit $EXITVALUE -pmd: - script: - - ./gradlew pmd -PdisablePreDex - -checkstyle: - script: - - ./gradlew checkstyle -PdisablePreDex - -tools: - before_script: - - echo "ignored, no gradle needed" - script: - - cd app - - ./tools/langs-list-check.py - - ./tools/check-string-format.py - after_script: - - echo "ignored, no gradle needed" - after_script: # this file changes every time but should not be cached - rm -f $GRADLE_USER_HOME/caches/modules-2/modules-2.lock From 6fb1207ae624d6d206cb8a8013243b4f82d94841 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 8 Dec 2016 00:01:48 +0100 Subject: [PATCH 2/6] always refresh APKs in DB at start with timestamps < 2010-01-01 APKs installed in /system} will often have zeroed out timestamps, like 2008-01-01 (ziptime) or 2009-01-01. So instead anything older than 2010 every time since we have no way to know whether an APK wasn't changed as part of an OTA update. An OTA update could change the APK without changing the versionCode or lastUpdateTime. closes #819 --- .../fdroid/data/InstalledAppProviderService.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/data/InstalledAppProviderService.java b/app/src/main/java/org/fdroid/fdroid/data/InstalledAppProviderService.java index 34616230a..6f0dee7fb 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/InstalledAppProviderService.java +++ b/app/src/main/java/org/fdroid/fdroid/data/InstalledAppProviderService.java @@ -124,13 +124,21 @@ public class InstalledAppProviderService extends IntentService { * is in sync with what the {@link PackageManager} tells us is installed. Once * completed, the relevant {@link android.content.ContentProvider}s will be * notified of any changes to installed statuses. - *

+ *

* The installed app cache could get out of sync, e.g. if F-Droid crashed/ or * ran out of battery half way through responding to {@link Intent#ACTION_PACKAGE_ADDED}. * This method returns immediately, and will continue to work in an * {@link IntentService}. It doesn't really matter where we put this in the * bootstrap process, because it runs in its own thread, at the lowest priority: * {@link Process#THREAD_PRIORITY_LOWEST}. + *

+ * APKs installed in {@code /system} will often have zeroed out timestamps, like + * 2008-01-01 (ziptime) or 2009-01-01. So instead anything older than 2010 every + * time since we have no way to know whether an APK wasn't changed as part of an + * OTA update. An OTA update could change the APK without changing the + * {@link PackageInfo#versionCode} or {@link PackageInfo#lastUpdateTime}. + * + * @see , Parcelable { public String license = "Unknown"; - public String author; - public String email; + public String authorName; + public String authorEmail; - public String webURL; + public String webSite; - public String trackerURL; + public String issueTracker; - public String sourceURL; + public String sourceCode; - public String changelogURL; + public String changelog; - public String donateURL; + public String donate; - public String bitcoinAddr; + public String bitcoin; - public String litecoinAddr; + public String litecoin; public String flattrID; @@ -186,32 +186,32 @@ public class App extends ValueObject implements Comparable, Parcelable { case Cols.LICENSE: license = cursor.getString(i); break; - case Cols.AUTHOR: - author = cursor.getString(i); + case Cols.AUTHOR_NAME: + authorName = cursor.getString(i); break; - case Cols.EMAIL: - email = cursor.getString(i); + case Cols.AUTHOR_EMAIL: + authorEmail = cursor.getString(i); break; - case Cols.WEB_URL: - webURL = cursor.getString(i); + case Cols.WEBSITE: + webSite = cursor.getString(i); break; - case Cols.TRACKER_URL: - trackerURL = cursor.getString(i); + case Cols.ISSUE_TRACKER: + issueTracker = cursor.getString(i); break; - case Cols.SOURCE_URL: - sourceURL = cursor.getString(i); + case Cols.SOURCE_CODE: + sourceCode = cursor.getString(i); break; - case Cols.CHANGELOG_URL: - changelogURL = cursor.getString(i); + case Cols.CHANGELOG: + changelog = cursor.getString(i); break; - case Cols.DONATE_URL: - donateURL = cursor.getString(i); + case Cols.DONATE: + donate = cursor.getString(i); break; - case Cols.BITCOIN_ADDR: - bitcoinAddr = cursor.getString(i); + case Cols.BITCOIN: + bitcoin = cursor.getString(i); break; - case Cols.LITECOIN_ADDR: - litecoinAddr = cursor.getString(i); + case Cols.LITECOIN: + litecoin = cursor.getString(i); break; case Cols.FLATTR_ID: flattrID = cursor.getString(i); @@ -490,15 +490,15 @@ public class App extends ValueObject implements Comparable, Parcelable { values.put(Cols.ICON_URL_LARGE, iconUrlLarge); values.put(Cols.DESCRIPTION, description); values.put(Cols.LICENSE, license); - values.put(Cols.AUTHOR, author); - values.put(Cols.EMAIL, email); - values.put(Cols.WEB_URL, webURL); - values.put(Cols.TRACKER_URL, trackerURL); - values.put(Cols.SOURCE_URL, sourceURL); - values.put(Cols.CHANGELOG_URL, changelogURL); - values.put(Cols.DONATE_URL, donateURL); - values.put(Cols.BITCOIN_ADDR, bitcoinAddr); - values.put(Cols.LITECOIN_ADDR, litecoinAddr); + values.put(Cols.AUTHOR_NAME, authorName); + values.put(Cols.AUTHOR_EMAIL, authorEmail); + values.put(Cols.WEBSITE, webSite); + values.put(Cols.ISSUE_TRACKER, issueTracker); + values.put(Cols.SOURCE_CODE, sourceCode); + values.put(Cols.CHANGELOG, changelog); + values.put(Cols.DONATE, donate); + values.put(Cols.BITCOIN, bitcoin); + values.put(Cols.LITECOIN, litecoin); values.put(Cols.FLATTR_ID, flattrID); values.put(Cols.ADDED, Utils.formatDate(added, "")); values.put(Cols.LAST_UPDATED, Utils.formatDate(lastUpdated, "")); @@ -556,12 +556,12 @@ public class App extends ValueObject implements Comparable, Parcelable { @Nullable public String getBitcoinUri() { - return TextUtils.isEmpty(bitcoinAddr) ? null : "bitcoin:" + bitcoinAddr; + return TextUtils.isEmpty(bitcoin) ? null : "bitcoin:" + bitcoin; } @Nullable public String getLitecoinUri() { - return TextUtils.isEmpty(litecoinAddr) ? null : "litecoin:" + litecoinAddr; + return TextUtils.isEmpty(bitcoin) ? null : "litecoin:" + bitcoin; } @Nullable @@ -632,15 +632,15 @@ public class App extends ValueObject implements Comparable, Parcelable { dest.writeString(this.icon); dest.writeString(this.description); dest.writeString(this.license); - dest.writeString(this.author); - dest.writeString(this.email); - dest.writeString(this.webURL); - dest.writeString(this.trackerURL); - dest.writeString(this.sourceURL); - dest.writeString(this.changelogURL); - dest.writeString(this.donateURL); - dest.writeString(this.bitcoinAddr); - dest.writeString(this.litecoinAddr); + dest.writeString(this.authorName); + dest.writeString(this.authorEmail); + dest.writeString(this.webSite); + dest.writeString(this.issueTracker); + dest.writeString(this.sourceCode); + dest.writeString(this.changelog); + dest.writeString(this.donate); + dest.writeString(this.bitcoin); + dest.writeString(this.litecoin); dest.writeString(this.flattrID); dest.writeString(this.upstreamVersionName); dest.writeInt(this.upstreamVersionCode); @@ -669,15 +669,15 @@ public class App extends ValueObject implements Comparable, Parcelable { this.icon = in.readString(); this.description = in.readString(); this.license = in.readString(); - this.author = in.readString(); - this.email = in.readString(); - this.webURL = in.readString(); - this.trackerURL = in.readString(); - this.sourceURL = in.readString(); - this.changelogURL = in.readString(); - this.donateURL = in.readString(); - this.bitcoinAddr = in.readString(); - this.litecoinAddr = in.readString(); + this.authorName = in.readString(); + this.authorEmail = in.readString(); + this.webSite = in.readString(); + this.issueTracker = in.readString(); + this.sourceCode = in.readString(); + this.changelog = in.readString(); + this.donate = in.readString(); + this.bitcoin = in.readString(); + this.litecoin = in.readString(); this.flattrID = in.readString(); this.upstreamVersionName = in.readString(); this.upstreamVersionCode = in.readInt(); 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 4803e78b3..14c10abb5 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java +++ b/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java @@ -116,19 +116,19 @@ class DBHelper extends SQLiteOpenHelper { + AppMetadataTable.Cols.ICON + " text, " + AppMetadataTable.Cols.DESCRIPTION + " text not null, " + AppMetadataTable.Cols.LICENSE + " text not null, " - + AppMetadataTable.Cols.AUTHOR + " text, " - + AppMetadataTable.Cols.EMAIL + " text, " - + AppMetadataTable.Cols.WEB_URL + " text, " - + AppMetadataTable.Cols.TRACKER_URL + " text, " - + AppMetadataTable.Cols.SOURCE_URL + " text, " - + AppMetadataTable.Cols.CHANGELOG_URL + " text, " + + AppMetadataTable.Cols.AUTHOR_NAME + " text, " + + AppMetadataTable.Cols.AUTHOR_EMAIL + " text, " + + AppMetadataTable.Cols.WEBSITE + " text, " + + AppMetadataTable.Cols.ISSUE_TRACKER + " text, " + + AppMetadataTable.Cols.SOURCE_CODE + " text, " + + AppMetadataTable.Cols.CHANGELOG + " text, " + AppMetadataTable.Cols.SUGGESTED_VERSION_CODE + " text," + AppMetadataTable.Cols.UPSTREAM_VERSION_NAME + " text," + AppMetadataTable.Cols.UPSTREAM_VERSION_CODE + " integer," + AppMetadataTable.Cols.ANTI_FEATURES + " string," - + AppMetadataTable.Cols.DONATE_URL + " string," - + AppMetadataTable.Cols.BITCOIN_ADDR + " string," - + AppMetadataTable.Cols.LITECOIN_ADDR + " string," + + AppMetadataTable.Cols.DONATE + " string," + + AppMetadataTable.Cols.BITCOIN + " string," + + AppMetadataTable.Cols.LITECOIN + " string," + AppMetadataTable.Cols.FLATTR_ID + " string," + AppMetadataTable.Cols.REQUIREMENTS + " string," + AppMetadataTable.Cols.ADDED + " string," @@ -756,11 +756,11 @@ class DBHelper extends SQLiteOpenHelper { } private void addChangelogToApp(SQLiteDatabase db, int oldVersion) { - if (oldVersion >= 48 || columnExists(db, AppMetadataTable.NAME, AppMetadataTable.Cols.CHANGELOG_URL)) { + if (oldVersion >= 48 || columnExists(db, AppMetadataTable.NAME, AppMetadataTable.Cols.CHANGELOG)) { return; } - Utils.debugLog(TAG, "Adding " + AppMetadataTable.Cols.CHANGELOG_URL + " column to " + AppMetadataTable.NAME); - db.execSQL("alter table " + AppMetadataTable.NAME + " add column " + AppMetadataTable.Cols.CHANGELOG_URL + " text"); + Utils.debugLog(TAG, "Adding " + AppMetadataTable.Cols.CHANGELOG + " column to " + AppMetadataTable.NAME); + db.execSQL("alter table " + AppMetadataTable.NAME + " add column " + AppMetadataTable.Cols.CHANGELOG + " text"); } private void addIconUrlLargeToApp(SQLiteDatabase db, int oldVersion) { @@ -809,13 +809,13 @@ class DBHelper extends SQLiteOpenHelper { if (oldVersion >= 53) { return; } - if (!columnExists(db, AppMetadataTable.NAME, AppMetadataTable.Cols.AUTHOR)) { - Utils.debugLog(TAG, "Adding " + AppMetadataTable.Cols.AUTHOR + " column to " + AppMetadataTable.NAME); - db.execSQL("alter table " + AppMetadataTable.NAME + " add column " + AppMetadataTable.Cols.AUTHOR + " text"); + if (!columnExists(db, AppMetadataTable.NAME, AppMetadataTable.Cols.AUTHOR_NAME)) { + Utils.debugLog(TAG, "Adding " + AppMetadataTable.Cols.AUTHOR_NAME + " column to " + AppMetadataTable.NAME); + db.execSQL("alter table " + AppMetadataTable.NAME + " add column " + AppMetadataTable.Cols.AUTHOR_NAME + " text"); } - if (!columnExists(db, AppMetadataTable.NAME, AppMetadataTable.Cols.EMAIL)) { - Utils.debugLog(TAG, "Adding " + AppMetadataTable.Cols.EMAIL + " column to " + AppMetadataTable.NAME); - db.execSQL("alter table " + AppMetadataTable.NAME + " add column " + AppMetadataTable.Cols.EMAIL + " text"); + if (!columnExists(db, AppMetadataTable.NAME, AppMetadataTable.Cols.AUTHOR_EMAIL)) { + Utils.debugLog(TAG, "Adding " + AppMetadataTable.Cols.AUTHOR_EMAIL + " column to " + AppMetadataTable.NAME); + db.execSQL("alter table " + AppMetadataTable.NAME + " add column " + AppMetadataTable.Cols.AUTHOR_EMAIL + " text"); } } 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 9d1a7a439..54c44c407 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/Schema.java +++ b/app/src/main/java/org/fdroid/fdroid/data/Schema.java @@ -124,15 +124,15 @@ public interface Schema { String ICON = "icon"; String DESCRIPTION = "description"; String LICENSE = "license"; - String AUTHOR = "author"; - String EMAIL = "email"; - String WEB_URL = "webURL"; - String TRACKER_URL = "trackerURL"; - String SOURCE_URL = "sourceURL"; - String CHANGELOG_URL = "changelogURL"; - String DONATE_URL = "donateURL"; - String BITCOIN_ADDR = "bitcoinAddr"; - String LITECOIN_ADDR = "litecoinAddr"; + String AUTHOR_NAME = "author"; + String AUTHOR_EMAIL = "email"; + String WEBSITE = "webURL"; + String ISSUE_TRACKER = "trackerURL"; + String SOURCE_CODE = "sourceURL"; + String CHANGELOG = "changelogURL"; + String DONATE = "donateURL"; + String BITCOIN = "bitcoinAddr"; + String LITECOIN = "litecoinAddr"; String FLATTR_ID = "flattrID"; String SUGGESTED_VERSION_CODE = "suggestedVercode"; String UPSTREAM_VERSION_NAME = "upstreamVersion"; @@ -176,8 +176,8 @@ public interface Schema { */ String[] ALL_COLS = { ROW_ID, PACKAGE_ID, REPO_ID, IS_COMPATIBLE, NAME, SUMMARY, ICON, DESCRIPTION, - LICENSE, AUTHOR, EMAIL, WEB_URL, TRACKER_URL, SOURCE_URL, - CHANGELOG_URL, DONATE_URL, BITCOIN_ADDR, LITECOIN_ADDR, FLATTR_ID, + LICENSE, AUTHOR_NAME, AUTHOR_EMAIL, WEBSITE, ISSUE_TRACKER, SOURCE_CODE, + CHANGELOG, DONATE, BITCOIN, LITECOIN, FLATTR_ID, UPSTREAM_VERSION_NAME, UPSTREAM_VERSION_CODE, ADDED, LAST_UPDATED, ANTI_FEATURES, REQUIREMENTS, ICON_URL, ICON_URL_LARGE, SUGGESTED_VERSION_CODE, @@ -190,8 +190,8 @@ public interface Schema { */ String[] ALL = { _ID, ROW_ID, REPO_ID, IS_COMPATIBLE, NAME, SUMMARY, ICON, DESCRIPTION, - LICENSE, AUTHOR, EMAIL, WEB_URL, TRACKER_URL, SOURCE_URL, - CHANGELOG_URL, DONATE_URL, BITCOIN_ADDR, LITECOIN_ADDR, FLATTR_ID, + LICENSE, AUTHOR_NAME, AUTHOR_EMAIL, WEBSITE, ISSUE_TRACKER, SOURCE_CODE, + CHANGELOG, DONATE, BITCOIN, LITECOIN, FLATTR_ID, UPSTREAM_VERSION_NAME, UPSTREAM_VERSION_CODE, ADDED, LAST_UPDATED, ANTI_FEATURES, REQUIREMENTS, ICON_URL, ICON_URL_LARGE, SUGGESTED_VERSION_CODE, SuggestedApk.VERSION_NAME, diff --git a/app/src/main/java/org/fdroid/fdroid/views/AppDetailsRecyclerViewAdapter.java b/app/src/main/java/org/fdroid/fdroid/views/AppDetailsRecyclerViewAdapter.java index e8ac029af..071f85bd9 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/AppDetailsRecyclerViewAdapter.java +++ b/app/src/main/java/org/fdroid/fdroid/views/AppDetailsRecyclerViewAdapter.java @@ -176,7 +176,7 @@ public class AppDetailsRecyclerViewAdapter } private boolean shouldShowDonate() { - return uriIsSetAndCanBeOpened(app.donateURL) || + return uriIsSetAndCanBeOpened(app.donate) || uriIsSetAndCanBeOpened(app.getBitcoinUri()) || uriIsSetAndCanBeOpened(app.getLitecoinUri()) || uriIsSetAndCanBeOpened(app.getFlattrUri()); @@ -382,8 +382,8 @@ public class AppDetailsRecyclerViewAdapter public void bindModel() { ImageLoader.getInstance().displayImage(app.iconUrlLarge, iconView, displayImageOptions); titleView.setText(app.name); - if (!TextUtils.isEmpty(app.author)) { - authorView.setText(context.getString(R.string.by_author) + " " + app.author); + if (!TextUtils.isEmpty(app.authorName)) { + authorView.setText(context.getString(R.string.by_author) + " " + app.authorName); authorView.setVisibility(View.VISIBLE); } else { authorView.setVisibility(View.GONE); @@ -523,18 +523,18 @@ public class AppDetailsRecyclerViewAdapter } public void bindModel() { - if (TextUtils.isEmpty(app.author)) { + if (TextUtils.isEmpty(app.authorName)) { donateHeading.setText(context.getString(R.string.app_details_donate_prompt_unknown_author, app.name)); } else { - String author = "" + app.author + ""; + String author = "" + app.authorName + ""; donateHeading.setText(Html.fromHtml(context.getString(R.string.app_details_donate_prompt, app.name, author))); } donationOptionsLayout.removeAllViews(); // Donate button - if (uriIsSetAndCanBeOpened(app.donateURL)) { - addDonateOption(R.layout.donate_generic, app.donateURL); + if (uriIsSetAndCanBeOpened(app.donate)) { + addDonateOption(R.layout.donate_generic, app.donate); } // Bitcoin @@ -639,28 +639,28 @@ public class AppDetailsRecyclerViewAdapter contentView.removeAllViews(); // Source button - if (uriIsSetAndCanBeOpened(app.sourceURL)) { - addLinkItemView(contentView, R.string.menu_source, R.drawable.ic_source_code, app.sourceURL); + if (uriIsSetAndCanBeOpened(app.sourceCode)) { + addLinkItemView(contentView, R.string.menu_source, R.drawable.ic_source_code, app.sourceCode); } // Issues button - if (uriIsSetAndCanBeOpened(app.trackerURL)) { - addLinkItemView(contentView, R.string.menu_issues, R.drawable.ic_issues, app.trackerURL); + if (uriIsSetAndCanBeOpened(app.issueTracker)) { + addLinkItemView(contentView, R.string.menu_issues, R.drawable.ic_issues, app.issueTracker); } // Changelog button - if (uriIsSetAndCanBeOpened(app.changelogURL)) { - addLinkItemView(contentView, R.string.menu_changelog, R.drawable.ic_changelog, app.changelogURL); + if (uriIsSetAndCanBeOpened(app.changelog)) { + addLinkItemView(contentView, R.string.menu_changelog, R.drawable.ic_changelog, app.changelog); } // Website button - if (uriIsSetAndCanBeOpened(app.webURL)) { - addLinkItemView(contentView, R.string.menu_website, R.drawable.ic_website, app.webURL); + if (uriIsSetAndCanBeOpened(app.webSite)) { + addLinkItemView(contentView, R.string.menu_website, R.drawable.ic_website, app.webSite); } // Email button final String subject = Uri.encode(context.getString(R.string.app_details_subject, app.name)); - String emailUrl = app.email == null ? null : ("mailto:" + app.email + "?subject=" + subject); + String emailUrl = app.authorEmail == null ? null : ("mailto:" + app.authorEmail + "?subject=" + subject); if (uriIsSetAndCanBeOpened(emailUrl)) { addLinkItemView(contentView, R.string.menu_email, R.drawable.ic_email, emailUrl); } diff --git a/app/src/test/java/org/fdroid/fdroid/updater/ProperMultiRepoUpdaterTest.java b/app/src/test/java/org/fdroid/fdroid/updater/ProperMultiRepoUpdaterTest.java index 19dea49bb..e978ec5ac 100644 --- a/app/src/test/java/org/fdroid/fdroid/updater/ProperMultiRepoUpdaterTest.java +++ b/app/src/test/java/org/fdroid/fdroid/updater/ProperMultiRepoUpdaterTest.java @@ -274,9 +274,9 @@ public class ProperMultiRepoUpdaterTest extends MultiRepoUpdaterTest { assertEquals("2048", a2048.name); assertEquals(String.format("

2048 from %s repo.

", id), a2048.description); assertEquals(String.format("Puzzle game (%s)", id), a2048.summary); - assertEquals(String.format("https://github.com/uberspot/2048-android?%s", id), a2048.webURL); - assertEquals(String.format("https://github.com/uberspot/2048-android?code&%s", id), a2048.sourceURL); - assertEquals(String.format("https://github.com/uberspot/2048-android/issues?%s", id), a2048.trackerURL); + assertEquals(String.format("https://github.com/uberspot/2048-android?%s", id), a2048.webSite); + assertEquals(String.format("https://github.com/uberspot/2048-android?code&%s", id), a2048.sourceCode); + assertEquals(String.format("https://github.com/uberspot/2048-android/issues?%s", id), a2048.issueTracker); } private void assertAdAwayMetadata(Repo repo, @RepoIdentifier String id) { @@ -290,11 +290,11 @@ public class ProperMultiRepoUpdaterTest extends MultiRepoUpdaterTest { assertEquals(String.format("AdAway", id), adaway.name); assertEquals(String.format("

AdAway from %s repo.

", id), adaway.description); assertEquals(String.format("Block advertisements (%s)", id), adaway.summary); - assertEquals(String.format("http://sufficientlysecure.org/index.php/adaway?%s", id), adaway.webURL); - assertEquals(String.format("https://github.com/dschuermann/ad-away?%s", id), adaway.sourceURL); - assertEquals(String.format("https://github.com/dschuermann/ad-away/issues?%s", id), adaway.trackerURL); - assertEquals(String.format("https://github.com/dschuermann/ad-away/raw/HEAD/CHANGELOG?%s", id), adaway.changelogURL); - assertEquals(String.format("http://sufficientlysecure.org/index.php/adaway?%s", id), adaway.donateURL); + assertEquals(String.format("http://sufficientlysecure.org/index.php/adaway?%s", id), adaway.webSite); + assertEquals(String.format("https://github.com/dschuermann/ad-away?%s", id), adaway.sourceCode); + assertEquals(String.format("https://github.com/dschuermann/ad-away/issues?%s", id), adaway.issueTracker); + assertEquals(String.format("https://github.com/dschuermann/ad-away/raw/HEAD/CHANGELOG?%s", id), adaway.changelog); + assertEquals(String.format("http://sufficientlysecure.org/index.php/adaway?%s", id), adaway.donate); assertEquals(String.format("369138", id), adaway.flattrID); } @@ -309,9 +309,9 @@ public class ProperMultiRepoUpdaterTest extends MultiRepoUpdaterTest { assertEquals("adbWireless", adb.name); assertEquals(String.format("

adbWireless from %s repo.

", id), adb.description); assertEquals(String.format("Wireless adb (%s)", id), adb.summary); - assertEquals(String.format("https://adbwireless.example.com?%s", id), adb.webURL); - assertEquals(String.format("https://adbwireless.example.com/source?%s", id), adb.sourceURL); - assertEquals(String.format("https://adbwireless.example.com/issues?%s", id), adb.trackerURL); + assertEquals(String.format("https://adbwireless.example.com?%s", id), adb.webSite); + assertEquals(String.format("https://adbwireless.example.com/source?%s", id), adb.sourceCode); + assertEquals(String.format("https://adbwireless.example.com/issues?%s", id), adb.issueTracker); } private void assertCalendarMetadata(Repo repo, @RepoIdentifier String id) { @@ -325,9 +325,9 @@ public class ProperMultiRepoUpdaterTest extends MultiRepoUpdaterTest { assertEquals("Add to calendar", calendar.name); assertEquals(String.format("

Add to calendar from %s repo.

", id), calendar.description); assertEquals(String.format("Import .ics files into calendar (%s)", id), calendar.summary); - assertEquals(String.format("https://github.com/danielegobbetti/ICSImport/blob/HEAD/README.md?%s", id), calendar.webURL); - assertEquals(String.format("https://github.com/danielegobbetti/ICSImport?%s", id), calendar.sourceURL); - assertEquals(String.format("https://github.com/danielegobbetti/ICSImport/issues?%s", id), calendar.trackerURL); + assertEquals(String.format("https://github.com/danielegobbetti/ICSImport/blob/HEAD/README.md?%s", id), calendar.webSite); + assertEquals(String.format("https://github.com/danielegobbetti/ICSImport?%s", id), calendar.sourceCode); + assertEquals(String.format("https://github.com/danielegobbetti/ICSImport/issues?%s", id), calendar.issueTracker); assertEquals("2225390", calendar.flattrID); } From bc0db92c5067663449e493f630f1b3b2cc82c7d9 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 5 Dec 2016 13:51:59 +0100 Subject: [PATCH 5/6] ensure that App description is never null In the v0 index format, empty descriptions were filled in with boilerplate text. The v1 index format instead leaves empty descriptions empty, and lets the various consumers (fdroidclient, web interfaces, etc) decide what to show. The database and code still assume that the description will not be null, so instead this ensures there is something in the database, but it will be an empty string instead of a null. In the future, it would probably make sense to standardize empty values on null or something. --- app/src/main/java/org/fdroid/fdroid/data/AppProvider.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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 3022fdfcb..3b6972915 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java +++ b/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java @@ -12,9 +12,9 @@ import android.util.Log; import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.data.Schema.ApkTable; -import org.fdroid.fdroid.data.Schema.AppPrefsTable; import org.fdroid.fdroid.data.Schema.AppMetadataTable; import org.fdroid.fdroid.data.Schema.AppMetadataTable.Cols; +import org.fdroid.fdroid.data.Schema.AppPrefsTable; import org.fdroid.fdroid.data.Schema.CatJoinTable; import org.fdroid.fdroid.data.Schema.CategoryTable; import org.fdroid.fdroid.data.Schema.InstalledAppTable; @@ -837,6 +837,11 @@ public class AppProvider extends FDroidProvider { values.remove(Cols.Package.PACKAGE_NAME); values.put(Cols.PACKAGE_ID, packageId); + if (!values.containsKey(Cols.DESCRIPTION) || values.getAsString(Cols.DESCRIPTION) == null) { + // the current structure assumes that description is always present and non-null + values.put(Cols.DESCRIPTION, ""); + } + String[] categories = null; boolean saveCategories = false; if (values.containsKey(Cols.ForWriting.Categories.CATEGORIES)) { From 601c85103ecb04eeab435b36b56da5a96df618c9 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 27 Feb 2017 14:23:14 +0100 Subject: [PATCH 6/6] fields as instance vars: icon, mirrors for Repo; antiFeatures for Apk This adds support for the index fields: icon, mirrors, and antiFeatures. icon and mirrors are for Repo, they've been around a while on the server side, but just never used on the client side. For Apk, this adds a new per-APK antiFeatures field so that each APK can be individually marked. For example, when tracking is added or removed, vulnerabilities are discovered and fixed, etc. These fields will be ignored when using the v0 index.xml format, they will be used by the upcoming index-v1 format: !422 --- .../java/org/fdroid/fdroid/RepoUpdater.java | 19 +++++++++++--- .../org/fdroid/fdroid/RepoXMLHandler.java | 11 ++++++-- .../main/java/org/fdroid/fdroid/data/Apk.java | 9 +++++++ .../java/org/fdroid/fdroid/data/DBHelper.java | 26 ++++++++++++++++++- .../java/org/fdroid/fdroid/data/Repo.java | 18 +++++++++++++ .../java/org/fdroid/fdroid/data/Schema.java | 8 ++++-- .../org/fdroid/fdroid/mock/RepoDetails.java | 7 ++++- 7 files changed, 89 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/RepoUpdater.java b/app/src/main/java/org/fdroid/fdroid/RepoUpdater.java index 3c47c485f..a29899c89 100644 --- a/app/src/main/java/org/fdroid/fdroid/RepoUpdater.java +++ b/app/src/main/java/org/fdroid/fdroid/RepoUpdater.java @@ -58,6 +58,7 @@ import java.security.CodeSigner; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.jar.JarEntry; @@ -195,9 +196,11 @@ public class RepoUpdater { private RepoXMLHandler.IndexReceiver createIndexReceiver() { return new RepoXMLHandler.IndexReceiver() { @Override - public void receiveRepo(String name, String description, String signingCert, int maxAge, int version, long timestamp) { + public void receiveRepo(String name, String description, String signingCert, int maxAge, + int version, long timestamp, String icon, String[] mirrors) { signingCertFromIndexXml = signingCert; - repoDetailsToSave = prepareRepoDetailsForSaving(name, description, maxAge, version, timestamp); + repoDetailsToSave = prepareRepoDetailsForSaving(name, description, maxAge, version, + timestamp, icon, mirrors); } @Override @@ -294,7 +297,9 @@ public class RepoUpdater { * Update tracking data for the repo represented by this instance (index version, etag, * description, human-readable name, etc. */ - private ContentValues prepareRepoDetailsForSaving(String name, String description, int maxAge, int version, long timestamp) { + private ContentValues prepareRepoDetailsForSaving(String name, String description, int maxAge, + int version, long timestamp, String icon, + String[] mirrors) { ContentValues values = new ContentValues(); values.put(RepoTable.Cols.LAST_UPDATED, Utils.formatTime(new Date(), "")); @@ -329,6 +334,14 @@ public class RepoUpdater { // timestamp. values.put(RepoTable.Cols.TIMESTAMP, timestamp); + if (icon != null && !icon.equals(repo.icon)) { + values.put(RepoTable.Cols.ICON, icon); + } + + if (mirrors != null && mirrors.length > 0 && !Arrays.equals(mirrors, repo.mirrors)) { + values.put(RepoTable.Cols.MIRRORS, Utils.serializeCommaSeparatedString(mirrors)); + } + return values; } diff --git a/app/src/main/java/org/fdroid/fdroid/RepoXMLHandler.java b/app/src/main/java/org/fdroid/fdroid/RepoXMLHandler.java index e822348c7..345b0d890 100644 --- a/app/src/main/java/org/fdroid/fdroid/RepoXMLHandler.java +++ b/app/src/main/java/org/fdroid/fdroid/RepoXMLHandler.java @@ -59,6 +59,8 @@ public class RepoXMLHandler extends DefaultHandler { private long repoTimestamp; private String repoDescription; private String repoName; + private String repoIcon; + private final ArrayList repoMirrors = new ArrayList<>(); /** * Set of requested permissions per package/APK @@ -73,7 +75,8 @@ public class RepoXMLHandler extends DefaultHandler { private final StringBuilder curchars = new StringBuilder(); public interface IndexReceiver { - void receiveRepo(String name, String description, String signingCert, int maxage, int version, long timestamp); + void receiveRepo(String name, String description, String signingCert, int maxage, int version, + long timestamp, String icon, String[] mirrors); void receiveApp(App app, List packages); @@ -258,6 +261,8 @@ public class RepoXMLHandler extends DefaultHandler { } } else if ("description".equals(localName)) { repoDescription = cleanWhiteSpace(str); + } else if ("mirror".equals(localName)) { + repoMirrors.add(str); } } @@ -312,7 +317,8 @@ public class RepoXMLHandler extends DefaultHandler { } private void onRepoParsed() { - receiver.receiveRepo(repoName, repoDescription, repoSigningCert, repoMaxAge, repoVersion, repoTimestamp); + receiver.receiveRepo(repoName, repoDescription, repoSigningCert, repoMaxAge, repoVersion, + repoTimestamp, repoIcon, repoMirrors.toArray(new String[repoMirrors.size()])); } private void onRepoPushRequestParsed(RepoPushRequest repoPushRequest) { @@ -331,6 +337,7 @@ public class RepoXMLHandler extends DefaultHandler { repoName = cleanWhiteSpace(attributes.getValue("", "name")); repoDescription = cleanWhiteSpace(attributes.getValue("", "description")); repoTimestamp = parseLong(attributes.getValue("", "timestamp"), 0); + repoIcon = attributes.getValue("", "icon"); } else if (RepoPushRequest.INSTALL.equals(localName) || RepoPushRequest.UNINSTALL.equals(localName)) { if (repo.pushRequests == Repo.PUSH_REQUEST_ACCEPT_ALWAYS) { 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 d00250966..d1f75ff89 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/Apk.java +++ b/app/src/main/java/org/fdroid/fdroid/data/Apk.java @@ -2,6 +2,7 @@ package org.fdroid.fdroid.data; import android.annotation.TargetApi; import android.content.ContentValues; +import android.content.pm.PackageInfo; import android.database.Cursor; import android.os.Build; import android.os.Parcel; @@ -73,6 +74,8 @@ public class Apk extends ValueObject implements Comparable, Parcelable { public String repoAddress; public String[] incompatibleReasons; + public String[] antiFeatures; + /** * The numeric primary key of the Metadata table, which is used to join apks. */ @@ -203,6 +206,9 @@ public class Apk extends ValueObject implements Comparable, Parcelable { case Cols.Repo.ADDRESS: repoAddress = cursor.getString(i); break; + case Cols.ANTI_FEATURES: + antiFeatures = Utils.parseCommaSeparatedString(cursor.getString(i)); + break; } } } @@ -303,6 +309,7 @@ public class Apk extends ValueObject implements Comparable, Parcelable { 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.ANTI_FEATURES, Utils.serializeCommaSeparatedString(antiFeatures)); values.put(Cols.IS_COMPATIBLE, compatible ? 1 : 0); return values; } @@ -349,6 +356,7 @@ public class Apk extends ValueObject implements Comparable, Parcelable { dest.writeInt(this.repoVersion); dest.writeString(this.repoAddress); dest.writeStringArray(this.incompatibleReasons); + dest.writeStringArray(this.antiFeatures); dest.writeLong(this.appId); } @@ -380,6 +388,7 @@ public class Apk extends ValueObject implements Comparable, Parcelable { this.repoVersion = in.readInt(); this.repoAddress = in.readString(); this.incompatibleReasons = in.createStringArray(); + this.antiFeatures = in.createStringArray(); this.appId = in.readLong(); } 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 14c10abb5..76a4f9312 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java +++ b/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java @@ -76,6 +76,8 @@ class DBHelper extends SQLiteOpenHelper { + RepoTable.Cols.USERNAME + " string, " + RepoTable.Cols.PASSWORD + " string," + RepoTable.Cols.TIMESTAMP + " integer not null default 0, " + + RepoTable.Cols.ICON + " string, " + + RepoTable.Cols.MIRRORS + " string, " + RepoTable.Cols.PUSH_REQUESTS + " integer not null default " + Repo.PUSH_REQUEST_IGNORE + ");"; @@ -104,6 +106,7 @@ class DBHelper extends SQLiteOpenHelper { + ApkTable.Cols.ADDED_DATE + " string, " + ApkTable.Cols.IS_COMPATIBLE + " int not null, " + ApkTable.Cols.INCOMPATIBLE_REASONS + " text, " + + ApkTable.Cols.ANTI_FEATURES + " string, " + "PRIMARY KEY (" + ApkTable.Cols.APP_ID + ", " + ApkTable.Cols.VERSION_CODE + ", " + ApkTable.Cols.REPO_ID + ")" + ");"; @@ -178,7 +181,7 @@ class DBHelper extends SQLiteOpenHelper { + InstalledAppTable.Cols.HASH + " TEXT NOT NULL" + " );"; - protected static final int DB_VERSION = 65; + protected static final int DB_VERSION = 66; private final Context context; @@ -258,6 +261,27 @@ class DBHelper extends SQLiteOpenHelper { migrateToPackageTable(db, oldVersion); addObbFiles(db, oldVersion); addCategoryTables(db, oldVersion); + addIndexV1Fields(db, oldVersion); + } + + private void addIndexV1Fields(SQLiteDatabase db, int oldVersion) { + if (oldVersion >= 66) { + return; + } + if (!columnExists(db, Schema.RepoTable.NAME, RepoTable.Cols.ICON)) { + Utils.debugLog(TAG, "Adding " + RepoTable.Cols.ICON + " field to " + RepoTable.NAME + " table in db."); + db.execSQL("alter table " + RepoTable.NAME + " add column " + RepoTable.Cols.ICON + " string;"); + } + + if (!columnExists(db, RepoTable.NAME, RepoTable.Cols.MIRRORS)) { + Utils.debugLog(TAG, "Adding " + RepoTable.Cols.MIRRORS + " field to " + RepoTable.NAME + " table in db."); + db.execSQL("alter table " + RepoTable.NAME + " add column " + RepoTable.Cols.MIRRORS + " string;"); + } + + if (!columnExists(db, ApkTable.NAME, ApkTable.Cols.ANTI_FEATURES)) { + Utils.debugLog(TAG, "Adding " + ApkTable.Cols.ANTI_FEATURES + " field to " + ApkTable.NAME + " table in db."); + db.execSQL("alter table " + ApkTable.NAME + " add column " + ApkTable.Cols.ANTI_FEATURES + " string;"); + } } /** diff --git a/app/src/main/java/org/fdroid/fdroid/data/Repo.java b/app/src/main/java/org/fdroid/fdroid/data/Repo.java index fa8289bdf..589c5d0ce 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/Repo.java +++ b/app/src/main/java/org/fdroid/fdroid/data/Repo.java @@ -47,6 +47,7 @@ public class Repo extends ValueObject { public String address; public String name; public String description; + public String icon; /** index version, i.e. what fdroidserver built it - 0 if not specified */ public int version; public boolean inuse; @@ -71,6 +72,9 @@ public class Repo extends ValueObject { /** When the signed repo index was generated, used to protect against replay attacks */ public long timestamp; + /** Official mirrors of this repo, considered automatically interchangeable */ + public String[] mirrors; + /** How to treat push requests included in this repo's index XML */ public int pushRequests = PUSH_REQUEST_IGNORE; @@ -131,6 +135,12 @@ public class Repo extends ValueObject { case Cols.TIMESTAMP: timestamp = cursor.getLong(i); break; + case Cols.ICON: + icon = cursor.getString(i); + break; + case Cols.MIRRORS: + mirrors = Utils.parseCommaSeparatedString(cursor.getString(i)); + break; case Cols.PUSH_REQUESTS: pushRequests = cursor.getInt(i); break; @@ -257,6 +267,14 @@ public class Repo extends ValueObject { timestamp = toInt(values.getAsInteger(Cols.TIMESTAMP)); } + if (values.containsKey(Cols.ICON)) { + icon = values.getAsString(Cols.ICON); + } + + if (values.containsKey(Cols.MIRRORS)) { + mirrors = Utils.parseCommaSeparatedString(values.getAsString(Cols.MIRRORS)); + } + if (values.containsKey(Cols.PUSH_REQUESTS)) { pushRequests = toInt(values.getAsInteger(Cols.PUSH_REQUESTS)); } 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 54c44c407..6c0491fba 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/Schema.java +++ b/app/src/main/java/org/fdroid/fdroid/data/Schema.java @@ -240,6 +240,7 @@ public interface Schema { String ADDED_DATE = "added"; String IS_COMPATIBLE = "compatible"; String INCOMPATIBLE_REASONS = "incompatibleReasons"; + String ANTI_FEATURES = "antiFeatures"; interface Repo { String VERSION = "repoVersion"; @@ -258,7 +259,7 @@ public interface Schema { SIZE, SIGNATURE, SOURCE_NAME, MIN_SDK_VERSION, TARGET_SDK_VERSION, MAX_SDK_VERSION, OBB_MAIN_FILE, OBB_MAIN_FILE_SHA256, OBB_PATCH_FILE, OBB_PATCH_FILE_SHA256, REQUESTED_PERMISSIONS, FEATURES, NATIVE_CODE, HASH_TYPE, ADDED_DATE, - IS_COMPATIBLE, INCOMPATIBLE_REASONS, + IS_COMPATIBLE, INCOMPATIBLE_REASONS, ANTI_FEATURES, }; /** @@ -270,6 +271,7 @@ public interface Schema { OBB_MAIN_FILE, OBB_MAIN_FILE_SHA256, OBB_PATCH_FILE, OBB_PATCH_FILE_SHA256, REQUESTED_PERMISSIONS, FEATURES, NATIVE_CODE, HASH_TYPE, ADDED_DATE, IS_COMPATIBLE, Repo.VERSION, Repo.ADDRESS, INCOMPATIBLE_REASONS, + ANTI_FEATURES, }; } } @@ -295,12 +297,14 @@ public interface Schema { String USERNAME = "username"; String PASSWORD = "password"; String TIMESTAMP = "timestamp"; + String ICON = "icon"; + String MIRRORS = "mirrors"; String PUSH_REQUESTS = "pushRequests"; String[] ALL = { _ID, ADDRESS, NAME, DESCRIPTION, IN_USE, PRIORITY, SIGNING_CERT, FINGERPRINT, MAX_AGE, LAST_UPDATED, LAST_ETAG, VERSION, IS_SWAP, - USERNAME, PASSWORD, TIMESTAMP, PUSH_REQUESTS, + USERNAME, PASSWORD, TIMESTAMP, ICON, MIRRORS, PUSH_REQUESTS, }; } } diff --git a/app/src/testShared/java/org/fdroid/fdroid/mock/RepoDetails.java b/app/src/testShared/java/org/fdroid/fdroid/mock/RepoDetails.java index 4371bbaa4..5d8428a15 100644 --- a/app/src/testShared/java/org/fdroid/fdroid/mock/RepoDetails.java +++ b/app/src/testShared/java/org/fdroid/fdroid/mock/RepoDetails.java @@ -31,19 +31,24 @@ public class RepoDetails implements RepoXMLHandler.IndexReceiver { public int maxAge; public int version; public long timestamp; + public String icon; + public String[] mirrors; public List apks = new ArrayList<>(); public List apps = new ArrayList<>(); public List repoPushRequestList = new ArrayList<>(); @Override - public void receiveRepo(String name, String description, String signingCert, int maxage, int version, long timestamp) { + public void receiveRepo(String name, String description, String signingCert, int maxage, + int version, long timestamp, String icon, String[] mirrors) { this.name = name; this.description = description; this.signingCert = signingCert; this.maxAge = maxage; this.version = version; this.timestamp = timestamp; + this.icon = icon; + this.mirrors = mirrors; } @Override