From fb5b169e54af4e1f2dc504521ca6faafbeec2ae5 Mon Sep 17 00:00:00 2001
From: Torsten Grote
Date: Thu, 1 Sep 2022 15:45:57 -0300
Subject: [PATCH] [app] Add support for IPFS CID downloading
This uses IndexFile objects instead of String file names everywhere. The general advantage of that is that we can now pass the hash and the file size to the downloader. For index v2 the hash can then get validated while downloading.
---
.../org/fdroid/fdroid/nearby/SwapService.java | 4 +-
.../fdroid/fdroid/nearby/SwapSuccessView.java | 11 +-
.../fdroid/fdroid/AppUpdateStatusManager.java | 12 +-
.../org/fdroid/fdroid/NotificationHelper.java | 2 +-
.../main/java/org/fdroid/fdroid/Utils.java | 51 +++--
.../main/java/org/fdroid/fdroid/data/Apk.java | 57 +++--
.../main/java/org/fdroid/fdroid/data/App.java | 201 ++++++------------
.../org/fdroid/fdroid/installer/ApkCache.java | 4 +-
.../installer/InstallManagerService.java | 9 +-
.../fdroid/net/BluetoothDownloader.java | 14 +-
.../fdroid/fdroid/net/DownloaderFactory.java | 50 ++++-
.../fdroid/fdroid/net/DownloaderService.java | 14 +-
.../fdroid/net/LocalFileDownloader.java | 13 +-
.../fdroid/fdroid/net/TreeUriDownloader.java | 17 +-
.../views/InstallConfirmActivity.java | 2 +-
.../views/AppDetailsRecyclerViewAdapter.java | 16 +-
.../fdroid/views/ScreenShotsActivity.java | 24 ++-
.../views/ScreenShotsRecyclerViewAdapter.java | 3 +-
.../fdroid/views/apps/FeatureImage.java | 9 +-
.../java/org/fdroid/fdroid/RepoUrlsTest.java | 3 +-
.../java/org/fdroid/fdroid/TestUtils.java | 10 +-
.../java/org/fdroid/fdroid/data/ApkTest.java | 13 +-
.../fdroid/data/SuggestedVersionTest.java | 20 +-
.../fdroid/installer/FileInstallerTest.java | 4 +-
.../installer/InstallerFactoryTest.java | 5 +-
.../fdroid/views/AppDetailsAdapterTest.java | 11 +-
26 files changed, 273 insertions(+), 306 deletions(-)
diff --git a/app/src/full/java/org/fdroid/fdroid/nearby/SwapService.java b/app/src/full/java/org/fdroid/fdroid/nearby/SwapService.java
index 358cde6f0..2549d41fc 100644
--- a/app/src/full/java/org/fdroid/fdroid/nearby/SwapService.java
+++ b/app/src/full/java/org/fdroid/fdroid/nearby/SwapService.java
@@ -33,6 +33,7 @@ import org.fdroid.index.IndexParserKt;
import org.fdroid.index.SigningException;
import org.fdroid.index.v1.IndexV1;
import org.fdroid.index.v1.IndexV1Verifier;
+import org.fdroid.index.v2.FileV2;
import java.io.File;
import java.io.IOException;
@@ -130,11 +131,12 @@ public class SwapService extends Service {
private void updateRepo(@NonNull Peer peer, Repository repo)
throws IOException, InterruptedException, SigningException {
Uri uri = Uri.parse(repo.getAddress()).buildUpon().appendPath("index-v1.jar").build();
+ FileV2 indexFile = FileV2.fromPath("/index-v1.jar");
File swapJarFile =
File.createTempFile("swap", "", getApplicationContext().getCacheDir());
try {
Downloader downloader =
- DownloaderFactory.INSTANCE.createWithTryFirstMirror(repo, uri, swapJarFile);
+ DownloaderFactory.INSTANCE.createWithTryFirstMirror(repo, uri, indexFile, swapJarFile);
downloader.download();
IndexV1Verifier verifier = new IndexV1Verifier(swapJarFile, null, peer.getFingerprint());
Pair pair = verifier.getStreamAndVerify(inputStream ->
diff --git a/app/src/full/java/org/fdroid/fdroid/nearby/SwapSuccessView.java b/app/src/full/java/org/fdroid/fdroid/nearby/SwapSuccessView.java
index 8dac0a7d8..b20a5ca18 100644
--- a/app/src/full/java/org/fdroid/fdroid/nearby/SwapSuccessView.java
+++ b/app/src/full/java/org/fdroid/fdroid/nearby/SwapSuccessView.java
@@ -40,6 +40,8 @@ import org.fdroid.index.v1.AppV1;
import org.fdroid.index.v1.IndexV1;
import org.fdroid.index.v1.PackageV1;
import org.fdroid.index.v1.PermissionV1;
+import org.fdroid.index.v2.FileV1;
+import org.fdroid.index.v2.FileV2;
import java.util.ArrayList;
import java.util.HashMap;
@@ -98,7 +100,7 @@ public class SwapSuccessView extends SwapView {
App app = new App();
app.name = a.getName();
app.packageName = a.getPackageName();
- app.iconUrl = "icons/" + a.getIcon();
+ app.iconFile = FileV2.fromPath("icons/" + a.getIcon());
try {
PackageInfo packageInfo = getContext().getPackageManager().getPackageInfo(app.packageName, 0);
app.installedVersionCode = packageInfo.versionCode;
@@ -115,9 +117,7 @@ public class SwapSuccessView extends SwapView {
apk.versionCode = packageV1.getVersionCode();
}
apk.versionName = packageV1.getVersionName();
- apk.apkName = packageV1.getApkName();
- apk.hashType = packageV1.getHashType();
- apk.hash = packageV1.getHash();
+ apk.apkFile = new FileV1("/" + packageV1.getApkName(), packageV1.getHash(), packageV1.getSize(), null);
ArrayList permissions =
new ArrayList<>(packageV1.getUsesPermission().size());
for (PermissionV1 perm : packageV1.getUsesPermission()) {
@@ -313,9 +313,8 @@ public class SwapSuccessView extends SwapView {
nameView.setText(app.name);
}
- String path = app.getIconPath(getContext());
Glide.with(iconView.getContext())
- .load(Utils.getDownloadRequest(repo, path))
+ .load(Utils.getDownloadRequest(repo, app.iconFile))
.apply(Utils.getAlwaysShowIconRequestOptions())
.into(iconView);
diff --git a/app/src/main/java/org/fdroid/fdroid/AppUpdateStatusManager.java b/app/src/main/java/org/fdroid/fdroid/AppUpdateStatusManager.java
index 670478b72..ccc89d7c5 100644
--- a/app/src/main/java/org/fdroid/fdroid/AppUpdateStatusManager.java
+++ b/app/src/main/java/org/fdroid/fdroid/AppUpdateStatusManager.java
@@ -294,12 +294,13 @@ public final class AppUpdateStatusManager {
}
private void updateApkInternal(@NonNull AppUpdateStatus entry, @NonNull Status status, PendingIntent intent) {
+ String apkName = entry.apk.getApkPath();
if (status == Status.UpdateAvailable && entry.status.ordinal() > status.ordinal()) {
- Utils.debugLog(LOGTAG, "Not updating APK " + entry.apk.apkName + " state to " + status.name());
+ Utils.debugLog(LOGTAG, "Not updating APK " + apkName + " state to " + status.name());
// If we have this entry in a more advanced state already, don't downgrade it
return;
} else {
- Utils.debugLog(LOGTAG, "Update APK " + entry.apk.apkName + " state to " + status.name());
+ Utils.debugLog(LOGTAG, "Update APK " + apkName + " state to " + status.name());
}
boolean isStatusUpdate = entry.status != status;
entry.status = status;
@@ -315,7 +316,8 @@ public final class AppUpdateStatusManager {
}
private void addApkInternal(@NonNull App app, @NonNull Apk apk, @NonNull Status status, PendingIntent intent) {
- Utils.debugLog(LOGTAG, "Add APK " + apk.apkName + " with state " + status.name());
+ String apkName = apk.getApkPath();
+ Utils.debugLog(LOGTAG, "Add APK " + apkName + " with state " + status.name());
AppUpdateStatus entry = createAppEntry(app, apk, status, intent);
setEntryContentIntentIfEmpty(entry);
appMapping.put(entry.getCanonicalUrl(), entry);
@@ -463,7 +465,7 @@ public final class AppUpdateStatusManager {
InstallManagerService.removePendingInstall(context, canonicalUrl);
AppUpdateStatus entry = appMapping.remove(canonicalUrl);
if (entry != null) {
- Utils.debugLog(LOGTAG, "Remove APK " + entry.apk.apkName);
+ Utils.debugLog(LOGTAG, "Remove APK " + entry.apk.getApkPath());
notifyRemove(entry);
}
}
@@ -473,7 +475,7 @@ public final class AppUpdateStatusManager {
synchronized (appMapping) {
AppUpdateStatus entry = appMapping.get(canonicalUrl);
if (entry != null) {
- Utils.debugLog(LOGTAG, "Refresh APK " + entry.apk.apkName);
+ Utils.debugLog(LOGTAG, "Refresh APK " + entry.apk.getApkPath());
notifyChange(entry, true);
}
}
diff --git a/app/src/main/java/org/fdroid/fdroid/NotificationHelper.java b/app/src/main/java/org/fdroid/fdroid/NotificationHelper.java
index 091d61687..d8b1203f4 100644
--- a/app/src/main/java/org/fdroid/fdroid/NotificationHelper.java
+++ b/app/src/main/java/org/fdroid/fdroid/NotificationHelper.java
@@ -548,7 +548,7 @@ public class NotificationHelper {
}
});
} else {
- App.loadBitmapWithGlide(context, entry.app.repoId, entry.app.getIconPath(context))
+ App.loadBitmapWithGlide(context, entry.app.repoId, entry.app.getIconPath())
.into(new CustomTarget() {
@Override
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition super Bitmap> transition) {
diff --git a/app/src/main/java/org/fdroid/fdroid/Utils.java b/app/src/main/java/org/fdroid/fdroid/Utils.java
index 76f17edc5..1567e20af 100644
--- a/app/src/main/java/org/fdroid/fdroid/Utils.java
+++ b/app/src/main/java/org/fdroid/fdroid/Utils.java
@@ -52,6 +52,7 @@ import com.google.zxing.BarcodeFormat;
import com.google.zxing.encode.Contents;
import com.google.zxing.encode.QRCodeEncoder;
+import org.fdroid.IndexFile;
import org.fdroid.database.AppOverviewItem;
import org.fdroid.database.Repository;
import org.fdroid.download.DownloadRequest;
@@ -77,6 +78,7 @@ import java.net.Socket;
import java.security.MessageDigest;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
+import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Formatter;
@@ -475,27 +477,20 @@ public final class Utils {
* @see Preferences#isBackgroundDownloadAllowed()
*/
public static void setIconFromRepoOrPM(@NonNull App app, ImageView iv, Context context) {
- long repoId = app.repoId;
- String iconPath = app.iconFromApk;
- if (iconPath == null) {
- Glide.with(context).clear(iv);
- iv.setImageResource(R.drawable.ic_repo_app_default);
- } else {
- loadWithGlide(context, repoId, iconPath, iv);
- }
+ loadWithGlide(context, app.repoId, app.iconFile, iv);
}
@Deprecated
public static void setIconFromRepoOrPM(@NonNull AppOverviewItem app, ImageView iv, Context context) {
long repoId = app.getRepoId();
- FileV2 iconFile = app.getIcon(App.getLocales());
- String iconPath = iconFile == null ? null : iconFile.getName();
- loadWithGlide(context, repoId, iconPath, iv);
+ IndexFile iconFile = app.getIcon(App.getLocales());
+ loadWithGlide(context, repoId, iconFile, iv);
}
- private static void loadWithGlide(Context context, long repoId, String iconPath, ImageView iv) {
- if (iconPath == null) {
+ public static void loadWithGlide(Context context, long repoId, @Nullable IndexFile file, ImageView iv) {
+ if (file == null) {
Glide.with(context).clear(iv);
+ iv.setImageResource(R.drawable.ic_repo_app_default);
return;
}
if (iconRequestOptions == null) {
@@ -513,15 +508,24 @@ public final class Utils {
}
String address = getRepoAddress(repo);
if (address.startsWith("content://")) {
- String uri = getUri(address, iconPath.split("/")).toString();
+ String uri = getUri(address, file.getName().split("/")).toString();
Glide.with(context).load(uri).apply(options).into(iv);
} else {
- DownloadRequest request = getDownloadRequest(repo, iconPath);
+ DownloadRequest request = getDownloadRequest(repo, file);
Glide.with(context).load(request).apply(options).into(iv);
}
}
@Nullable
+ public static DownloadRequest getDownloadRequest(@NonNull Repository repo, @Nullable IndexFile file) {
+ if (file == null) return null;
+ List mirrors = repo.getMirrors();
+ Proxy proxy = NetCipher.getProxy();
+ return new DownloadRequest(file, mirrors, proxy, repo.getUsername(), repo.getPassword());
+ }
+
+ @Nullable
+ @Deprecated
public static DownloadRequest getDownloadRequest(@NonNull Repository repo, @Nullable String path) {
if (path == null) return null;
List mirrors = repo.getMirrors();
@@ -854,6 +858,23 @@ public final class Utils {
});
}
+ public static ArrayList toString(@Nullable List files) {
+ if (files == null) return new ArrayList<>(0);
+ ArrayList list = new ArrayList<>(files.size());
+ for (FileV2 file : files) {
+ list.add(file.serialize());
+ }
+ return list;
+ }
+
+ public static List fileV2FromStrings(List list) {
+ ArrayList files = new ArrayList<>(list.size());
+ for (String s : list) {
+ files.add(FileV2.deserialize(s));
+ }
+ return files;
+ }
+
/**
* Keep an instance of this class as an field in an AppCompatActivity for figuring out whether the on
* screen keyboard is currently visible or not.
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 653627ca9..741c7a4f3 100644
--- a/app/src/main/java/org/fdroid/fdroid/data/Apk.java
+++ b/app/src/main/java/org/fdroid/fdroid/data/Apk.java
@@ -19,6 +19,7 @@ import org.fdroid.fdroid.CompatibilityChecker;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.installer.ApkCache;
+import org.fdroid.index.v2.FileV1;
import org.fdroid.index.v2.PermissionV2;
import org.fdroid.index.v2.SignerV2;
@@ -60,7 +61,6 @@ public class Apk implements Comparable, Parcelable {
// these are never set by the Apk/package index metadata
public String repoAddress;
public String canonicalRepoAddress;
- long repoVersion;
public SanitizedFile installedFile; // the .apk file on this device's filesystem
public boolean compatible; // True if compatible with the device.
public long repoId; // the database ID of the repo it comes from
@@ -107,13 +107,20 @@ public class Apk implements Comparable, Parcelable {
*/
public String sig;
- public String apkName; // F-Droid style APK name
+ /**
+ * Can be null when created with {@link #Apk(PackageInfo)}
+ * which happens only for showing an installed version
+ * in {@link org.fdroid.fdroid.views.AppDetailsActivity}.
+ */
+ @Nullable
+ public FileV1 apkFile;
/**
* If not null, this is the name of the source tarball for the
* application. Null indicates that it's a developer's binary
* build - otherwise it's built from source.
*/
+ @Nullable
public String srcname;
public String[] incompatibleReasons;
@@ -122,11 +129,6 @@ public class Apk implements Comparable, Parcelable {
public String whatsNew;
- /**
- * The numeric primary key of the Metadata table, which is used to join apks.
- */
- public long appId;
-
public Apk() {
}
@@ -154,9 +156,6 @@ public class Apk implements Comparable, Parcelable {
Repository repo = Objects.requireNonNull(FDroidApp.getRepo(v.getRepoId()));
repoAddress = Utils.getRepoAddress(repo);
canonicalRepoAddress = repo.getAddress();
- repoVersion = repo.getVersion();
- hash = v.getFile().getSha256();
- hashType = "sha256";
added = new Date(v.getAdded());
features = v.getFeatureNames().toArray(new String[0]);
setPackageName(v.getPackageName());
@@ -174,11 +173,7 @@ public class Apk implements Comparable, Parcelable {
} else {
releaseChannels = channels;
}
- // obbMainFile = cursor.getString(i);
- // obbMainFileSha256 = cursor.getString(i);
- // obbPatchFile = cursor.getString(i);
- // obbPatchFileSha256 = cursor.getString(i);
- apkName = v.getFile().getName();
+ apkFile = v.getFile();
setRequestedPermissions(v.getUsesPermission(), 0);
setRequestedPermissions(v.getUsesPermissionSdk23(), 23);
nativecode = v.getNativeCode().toArray(new String[0]);
@@ -205,18 +200,23 @@ public class Apk implements Comparable, Parcelable {
}
private void checkRepoAddress() {
- if (repoAddress == null || apkName == null) {
+ if (repoAddress == null || apkFile == null) {
throw new IllegalStateException(
"Apk needs to have both Schema.ApkTable.Cols.REPO_ADDRESS and "
+ "Schema.ApkTable.Cols.NAME set in order to calculate URL "
+ "[package: " + packageName
+ ", versionCode: " + versionCode
- + ", apkName: " + apkName
+ + ", apkName: " + getApkPath()
+ ", repoAddress: " + repoAddress
+ ", repoId: " + repoId + "]");
}
}
+ @Nullable
+ public String getApkPath() {
+ return apkFile == null ? "" : apkFile.getName();
+ }
+
/**
* Get the URL that points to the canonical download source for this
* package. This is also used as the unique ID for tracking downloading,
@@ -229,12 +229,12 @@ public class Apk implements Comparable, Parcelable {
public String getCanonicalUrl() {
checkRepoAddress();
/* Each String in pathElements might contain a /, should keep these as path elements */
- return Utils.getUri(canonicalRepoAddress, apkName.split("/")).toString();
+ return Utils.getUri(canonicalRepoAddress, getApkPath().split("/")).toString();
}
public String getDownloadUrl() {
checkRepoAddress();
- return Utils.getUri(repoAddress, apkName.split("/")).toString();
+ return Utils.getUri(repoAddress, getApkPath().split("/")).toString();
}
/**
@@ -311,8 +311,6 @@ public class Apk implements Comparable, Parcelable {
dest.writeLong(this.versionCode);
dest.writeLong(this.size);
dest.writeLong(this.repoId);
- dest.writeString(this.hash);
- dest.writeString(this.hashType);
dest.writeInt(this.minSdkVersion);
dest.writeInt(this.targetSdkVersion);
dest.writeInt(this.maxSdkVersion);
@@ -326,15 +324,13 @@ public class Apk implements Comparable, Parcelable {
dest.writeStringArray(this.nativecode);
dest.writeString(this.sig);
dest.writeByte(this.compatible ? (byte) 1 : (byte) 0);
- dest.writeString(this.apkName);
+ dest.writeString(this.apkFile.serialize());
dest.writeSerializable(this.installedFile);
dest.writeString(this.srcname);
- dest.writeLong(this.repoVersion);
dest.writeString(this.repoAddress);
dest.writeString(this.canonicalRepoAddress);
dest.writeStringArray(this.incompatibleReasons);
dest.writeStringArray(this.antiFeatures);
- dest.writeLong(this.appId);
}
protected Apk(Parcel in) {
@@ -343,8 +339,6 @@ public class Apk implements Comparable, Parcelable {
this.versionCode = in.readLong();
this.size = in.readLong();
this.repoId = in.readLong();
- this.hash = in.readString();
- this.hashType = in.readString();
this.minSdkVersion = in.readInt();
this.targetSdkVersion = in.readInt();
this.maxSdkVersion = in.readInt();
@@ -359,15 +353,13 @@ public class Apk implements Comparable, Parcelable {
this.nativecode = in.createStringArray();
this.sig = in.readString();
this.compatible = in.readByte() != 0;
- this.apkName = in.readString();
+ this.apkFile = FileV1.deserialize(in.readString());
this.installedFile = (SanitizedFile) in.readSerializable();
this.srcname = in.readString();
- this.repoVersion = in.readLong();
this.repoAddress = in.readString();
this.canonicalRepoAddress = in.readString();
this.incompatibleReasons = in.createStringArray();
this.antiFeatures = in.createStringArray();
- this.appId = in.readLong();
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
@@ -536,7 +528,7 @@ public class Apk implements Comparable, Parcelable {
}
public File getInstalledMediaFile(Context context) {
- return new File(this.getMediaInstallPath(context), SanitizedFile.sanitizeFileName(this.apkName));
+ return new File(this.getMediaInstallPath(context), SanitizedFile.sanitizeFileName(getApkPath()));
}
/**
@@ -554,7 +546,8 @@ public class Apk implements Comparable, Parcelable {
* @return true if this is an apk instead of a non-apk/media file
*/
public boolean isApk() {
- return apkName == null
- || apkName.substring(apkName.length() - 4).toLowerCase(Locale.ENGLISH).endsWith(".apk");
+ return apkFile == null
+ || apkFile.getName().substring(apkFile.getName().length() - 4)
+ .toLowerCase(Locale.ENGLISH).endsWith(".apk");
}
}
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 35e3d1de8..4d1bf39eb 100644
--- a/app/src/main/java/org/fdroid/fdroid/data/App.java
+++ b/app/src/main/java/org/fdroid/fdroid/data/App.java
@@ -19,6 +19,7 @@ import android.util.Log;
import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestBuilder;
+import org.fdroid.IndexFile;
import org.fdroid.database.AppListItem;
import org.fdroid.database.Repository;
import org.fdroid.database.UpdatableApp;
@@ -86,16 +87,10 @@ public class App implements Comparable, Parcelable {
public String installedSig;
public int installedVersionCode;
public String installedVersionName;
- private long id;
public org.fdroid.database.AppPrefs prefs;
public String preferredSigner;
public boolean isApk;
- /**
- * Has this {@code App} been localized into one of the user's current locales.
- */
- boolean isLocalized;
-
/**
* This is primarily for the purpose of saving app metadata when parsing an index.xml file.
* At most other times, we don't particularly care which repo an {@link App} object came from.
@@ -110,7 +105,6 @@ public class App implements Comparable, Parcelable {
public String name = "Unknown";
public String summary = "Unknown application";
- public String iconFromApk;
public String description;
@@ -119,15 +113,15 @@ public class App implements Comparable, Parcelable {
*/
public String whatsNew;
- public String featureGraphic;
- public String promoGraphic;
- public String tvBanner;
+ public FileV2 featureGraphic;
+ private FileV2 promoGraphic;
+ private FileV2 tvBanner;
- public String[] phoneScreenshots = new String[0];
- public String[] sevenInchScreenshots = new String[0];
- public String[] tenInchScreenshots = new String[0];
- public String[] tvScreenshots = new String[0];
- public String[] wearScreenshots = new String[0];
+ public List phoneScreenshots = Collections.emptyList();
+ private List sevenInchScreenshots = Collections.emptyList();
+ private List tenInchScreenshots = Collections.emptyList();
+ private List tvScreenshots = Collections.emptyList();
+ private List wearScreenshots = Collections.emptyList();
public String license;
@@ -205,18 +199,7 @@ public class App implements Comparable, Parcelable {
@Nullable
public String[] antiFeatures;
- /**
- * Requires root access (only ever used for root)
- */
- @Nullable
- @Deprecated
- public String[] requirements;
-
- /**
- * URL to download the app's icon. (Set only from localized block, see also
- * {@link #iconFromApk} and {@link #getIconPath(Context)} (Context)}
- */
- public String iconUrl;
+ public FileV2 iconFile;
@Override
public int compareTo(@NonNull App app) {
@@ -227,20 +210,16 @@ public class App implements Comparable, Parcelable {
}
public App(final UpdatableApp app) {
- id = 0;
repoId = app.getUpdate().getRepoId();
setPackageName(app.getPackageName());
name = app.getName() == null ? "" : app.getName();
summary = app.getSummary() == null ? "" : app.getSummary();
installedVersionCode = (int) app.getInstalledVersionCode();
autoInstallVersionCode = (int) app.getUpdate().getManifest().getVersionCode();
- FileV2 icon = app.getIcon(getLocales());
- iconUrl = icon == null ? null : icon.getName();
- iconFromApk = icon == null ? null : icon.getName();
+ iconFile = app.getIcon(getLocales());
}
public App(final org.fdroid.database.App app, @Nullable PackageInfo packageInfo) {
- id = 0;
repoId = app.getRepoId();
compatible = app.getMetadata().isCompatible();
setPackageName(app.getPackageName());
@@ -269,40 +248,15 @@ public class App implements Comparable, Parcelable {
preferredSigner = app.getMetadata().getPreferredSigner();
added = new Date(app.getMetadata().getAdded());
lastUpdated = new Date(app.getMetadata().getLastUpdated());
- FileV2 icon = app.getIcon(getLocales());
- iconUrl = icon == null ? null : icon.getName();
- iconFromApk = icon == null ? null : icon.getName();
- FileV2 featureGraphic = app.getFeatureGraphic(getLocales());
- this.featureGraphic = featureGraphic == null ? null : featureGraphic.getName();
- FileV2 promoGraphic = app.getPromoGraphic(getLocales());
- this.promoGraphic = promoGraphic == null ? null : promoGraphic.getName();
- FileV2 tvBanner = app.getPromoGraphic(getLocales());
- this.tvBanner = tvBanner == null ? null : tvBanner.getName();
- List phoneFiles = app.getPhoneScreenshots(getLocales());
- phoneScreenshots = new String[phoneFiles.size()];
- for (int i = 0; i < phoneFiles.size(); i++) {
- phoneScreenshots[i] = phoneFiles.get(i).getName();
- }
- List sevenInchFiles = app.getSevenInchScreenshots(getLocales());
- sevenInchScreenshots = new String[sevenInchFiles.size()];
- for (int i = 0; i < sevenInchFiles.size(); i++) {
- phoneScreenshots[i] = sevenInchFiles.get(i).getName();
- }
- List tenInchFiles = app.getTenInchScreenshots(getLocales());
- tenInchScreenshots = new String[tenInchFiles.size()];
- for (int i = 0; i < tenInchFiles.size(); i++) {
- phoneScreenshots[i] = tenInchFiles.get(i).getName();
- }
- List tvFiles = app.getTvScreenshots(getLocales());
- tvScreenshots = new String[tvFiles.size()];
- for (int i = 0; i < tvFiles.size(); i++) {
- phoneScreenshots[i] = tvFiles.get(i).getName();
- }
- List wearFiles = app.getWearScreenshots(getLocales());
- wearScreenshots = new String[wearFiles.size()];
- for (int i = 0; i < wearFiles.size(); i++) {
- phoneScreenshots[i] = wearFiles.get(i).getName();
- }
+ iconFile = app.getIcon(getLocales());
+ featureGraphic = app.getFeatureGraphic(getLocales());
+ promoGraphic = app.getPromoGraphic(getLocales());
+ tvBanner = app.getPromoGraphic(getLocales());
+ phoneScreenshots = app.getPhoneScreenshots(getLocales());
+ sevenInchScreenshots = app.getSevenInchScreenshots(getLocales());
+ tenInchScreenshots = app.getTenInchScreenshots(getLocales());
+ tvScreenshots = app.getTvScreenshots(getLocales());
+ wearScreenshots = app.getWearScreenshots(getLocales());
setInstalled(packageInfo);
}
@@ -311,8 +265,7 @@ public class App implements Comparable, Parcelable {
setPackageName(item.getPackageName());
name = item.getName() == null ? "" : item.getName();
summary = item.getSummary() == null ? "" : item.getSummary();
- FileV2 iconFile = item.getIcon(getLocales());
- iconFromApk = iconFile == null ? null : iconFile.getName();
+ iconFile = item.getIcon(getLocales());
installedVersionCode = item.getInstalledVersionCode() == null ? 0 : item.getInstalledVersionCode().intValue();
installedVersionName = item.getInstalledVersionName();
antiFeatures = item.getAntiFeatureKeys().toArray(new String[0]);
@@ -367,7 +320,7 @@ public class App implements Comparable, Parcelable {
/**
* Set the Package Name property while ensuring it is sanitized.
*/
- void setPackageName(String packageName) {
+ private void setPackageName(String packageName) {
if (Utils.isSafePackageName(packageName)) {
this.packageName = packageName;
} else {
@@ -379,7 +332,7 @@ public class App implements Comparable, Parcelable {
/**
* Returns the app description text with all newlines replaced by {@code
}
*/
- public static String formatDescription(String description) {
+ private static String formatDescription(String description) {
return description.replace("\n", "
");
}
@@ -395,11 +348,11 @@ public class App implements Comparable, Parcelable {
.build();
}
- public RequestBuilder loadWithGlide(Context context, String path) {
- return loadWithGlide(context, repoId, path);
+ public RequestBuilder loadWithGlide(Context context, IndexFile file) {
+ return loadWithGlide(context, repoId, file);
}
- public static RequestBuilder loadWithGlide(Context context, long repoId, String path) {
+ public static RequestBuilder loadWithGlide(Context context, long repoId, IndexFile file) {
Repository repo = FDroidApp.getRepo(repoId);
if (repo == null) { // This is also used for apps that do not have a repo
return Glide.with(context).load((Drawable) null);
@@ -410,12 +363,12 @@ public class App implements Comparable, Parcelable {
}
String address = Utils.getRepoAddress(repo);
if (address.startsWith("content://")) {
- String sb = Utils.getUri(address, path.split("/")).toString();
+ String sb = Utils.getUri(address, file.getName().split("/")).toString();
return Glide.with(context).load(sb);
} else if (address.startsWith("file://")) {
- return Glide.with(context).load(path);
+ return Glide.with(context).load(file);
} else {
- return Glide.with(context).load(Utils.getDownloadRequest(repo, path));
+ return Glide.with(context).load(Utils.getDownloadRequest(repo, file));
}
}
@@ -438,23 +391,18 @@ public class App implements Comparable, Parcelable {
}
}
- public String getIconPath(Context context) {
- String path;
- if (TextUtils.isEmpty(iconUrl)) {
- if (TextUtils.isEmpty(iconFromApk)) {
- return null;
- }
- if (iconFromApk.endsWith(".xml")) {
- // We cannot use xml resources as icons. F-Droid server should not include them
- // https://gitlab.com/fdroid/fdroidserver/issues/344
- return null;
- }
- String iconsDir = Utils.getIconsDir(context, 1.0);
- path = getPath(iconsDir, iconFromApk);
+ public String getIconPath() {
+ if (iconFile == null) {
+ return null;
+ } else if (TextUtils.isEmpty(iconFile.getName())) {
+ return null;
+ } else if (iconFile.getName().endsWith(".xml")) {
+ // We cannot use xml resources as icons. F-Droid server should not include them
+ // https://gitlab.com/fdroid/fdroidserver/issues/344
+ return null;
} else {
- path = iconUrl;
+ return iconFile.getName();
}
- return path;
}
/**
@@ -477,23 +425,12 @@ public class App implements Comparable, Parcelable {
return sb.toString();
}
- public ArrayList getAllScreenshots() {
- ArrayList list = new ArrayList<>();
- if (phoneScreenshots != null) {
- Collections.addAll(list, phoneScreenshots);
- }
- if (sevenInchScreenshots != null) {
- Collections.addAll(list, sevenInchScreenshots);
- }
- if (tenInchScreenshots != null) {
- Collections.addAll(list, tenInchScreenshots);
- }
- if (tvScreenshots != null) {
- Collections.addAll(list, tvScreenshots);
- }
- if (wearScreenshots != null) {
- Collections.addAll(list, wearScreenshots);
- }
+ public List getAllScreenshots() {
+ ArrayList list = new ArrayList<>(phoneScreenshots);
+ list.addAll(sevenInchScreenshots);
+ list.addAll(tenInchScreenshots);
+ list.addAll(tvScreenshots);
+ list.addAll(wearScreenshots);
return list;
}
@@ -737,10 +674,6 @@ public class App implements Comparable, Parcelable {
return new int[]{minSdkVersion, targetSdkVersion, maxSdkVersion};
}
- public long getId() {
- return id;
- }
-
@Override
public int describeContents() {
return 0;
@@ -774,7 +707,7 @@ public class App implements Comparable, Parcelable {
dest.writeString(this.name);
dest.writeLong(this.repoId);
dest.writeString(this.summary);
- dest.writeString(this.iconFromApk);
+ dest.writeString(this.iconFile == null ? null : this.iconFile.serialize());
dest.writeString(this.description);
dest.writeString(this.whatsNew);
dest.writeString(this.license);
@@ -801,23 +734,19 @@ public class App implements Comparable, Parcelable {
dest.writeLong(this.lastUpdated != null ? this.lastUpdated.getTime() : -1);
dest.writeStringArray(this.categories);
dest.writeStringArray(this.antiFeatures);
- dest.writeStringArray(this.requirements);
- dest.writeString(this.iconUrl);
- dest.writeString(this.featureGraphic);
- dest.writeString(this.promoGraphic);
- dest.writeString(this.tvBanner);
- dest.writeStringArray(this.phoneScreenshots);
- dest.writeStringArray(this.sevenInchScreenshots);
- dest.writeStringArray(this.tenInchScreenshots);
- dest.writeStringArray(this.tvScreenshots);
- dest.writeStringArray(this.wearScreenshots);
+ dest.writeString(this.featureGraphic == null ? null : this.featureGraphic.serialize());
+ dest.writeString(this.promoGraphic == null ? null : this.promoGraphic.serialize());
+ dest.writeString(this.tvBanner == null ? null : this.tvBanner.serialize());
+ dest.writeStringList(Utils.toString(this.phoneScreenshots));
+ dest.writeStringList(Utils.toString(this.sevenInchScreenshots));
+ dest.writeStringList(Utils.toString(this.tenInchScreenshots));
+ dest.writeStringList(Utils.toString(this.tvScreenshots));
+ dest.writeStringList(Utils.toString(this.wearScreenshots));
dest.writeByte(this.isApk ? (byte) 1 : (byte) 0);
- dest.writeByte(this.isLocalized ? (byte) 1 : (byte) 0);
dest.writeString(this.installedVersionName);
dest.writeInt(this.installedVersionCode);
dest.writeParcelable(this.installedApk, flags);
dest.writeString(this.installedSig);
- dest.writeLong(this.id);
}
protected App(Parcel in) {
@@ -826,7 +755,7 @@ public class App implements Comparable, Parcelable {
this.name = in.readString();
this.repoId = in.readLong();
this.summary = in.readString();
- this.iconFromApk = in.readString();
+ this.iconFile = FileV2.deserialize(in.readString());
this.description = in.readString();
this.whatsNew = in.readString();
this.license = in.readString();
@@ -855,23 +784,19 @@ public class App implements Comparable, Parcelable {
this.lastUpdated = tmpLastUpdated == -1 ? null : new Date(tmpLastUpdated);
this.categories = in.createStringArray();
this.antiFeatures = in.createStringArray();
- this.requirements = in.createStringArray();
- this.iconUrl = in.readString();
- this.featureGraphic = in.readString();
- this.promoGraphic = in.readString();
- this.tvBanner = in.readString();
- this.phoneScreenshots = in.createStringArray();
- this.sevenInchScreenshots = in.createStringArray();
- this.tenInchScreenshots = in.createStringArray();
- this.tvScreenshots = in.createStringArray();
- this.wearScreenshots = in.createStringArray();
+ this.featureGraphic = FileV2.deserialize(in.readString());
+ this.promoGraphic = FileV2.deserialize(in.readString());
+ this.tvBanner = FileV2.deserialize(in.readString());
+ this.phoneScreenshots = Utils.fileV2FromStrings(in.createStringArrayList());
+ this.sevenInchScreenshots = Utils.fileV2FromStrings(in.createStringArrayList());
+ this.tenInchScreenshots = Utils.fileV2FromStrings(in.createStringArrayList());
+ this.tvScreenshots = Utils.fileV2FromStrings(in.createStringArrayList());
+ this.wearScreenshots = Utils.fileV2FromStrings(in.createStringArrayList());
this.isApk = in.readByte() != 0;
- this.isLocalized = in.readByte() != 0;
this.installedVersionName = in.readString();
this.installedVersionCode = in.readInt();
this.installedApk = in.readParcelable(Apk.class.getClassLoader());
this.installedSig = in.readString();
- this.id = in.readLong();
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
diff --git a/app/src/main/java/org/fdroid/fdroid/installer/ApkCache.java b/app/src/main/java/org/fdroid/fdroid/installer/ApkCache.java
index ae4218a5f..fd4e0bc78 100644
--- a/app/src/main/java/org/fdroid/fdroid/installer/ApkCache.java
+++ b/app/src/main/java/org/fdroid/fdroid/installer/ApkCache.java
@@ -59,7 +59,7 @@ public class ApkCache {
throws IOException {
String name = expectedApk.packageName;
String apkFileName = name + "-" + expectedApk.versionName + ".apk";
- return copyApkToFiles(context, apkFile, apkFileName, true, expectedApk.hash, expectedApk.hashType);
+ return copyApkToFiles(context, apkFile, apkFileName, true, expectedApk.apkFile.getSha256(), "sha256");
}
/**
@@ -133,7 +133,7 @@ public class ApkCache {
*/
public static boolean apkIsCached(File apkFile, Apk apkToCheck) {
return apkFile.length() == apkToCheck.size &&
- Utils.isFileMatchingHash(apkFile, apkToCheck.hash, apkToCheck.hashType);
+ Utils.isFileMatchingHash(apkFile, apkToCheck.apkFile.getSha256(), "sha256");
}
/**
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 638dc0f72..36d58c9f9 100644
--- a/app/src/main/java/org/fdroid/fdroid/installer/InstallManagerService.java
+++ b/app/src/main/java/org/fdroid/fdroid/installer/InstallManagerService.java
@@ -15,7 +15,6 @@ import android.util.Log;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.WildcardFileFilter;
-import org.fdroid.download.Downloader;
import org.fdroid.fdroid.AppUpdateStatusManager;
import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.compat.PackageManagerCompat;
@@ -69,7 +68,7 @@ import static vendored.org.apache.commons.codec.digest.MessageDigestAlgorithms.S
* for a {@code String} ID, use {@code canonicalUrl}, {@link Uri#toString()}, or
* {@link Intent#getDataString()}
* for an {@code int} ID, use {@link String#hashCode()} or {@link Uri#hashCode()}
- * for an {@link Intent} extra, use {@link Downloader#EXTRA_CANONICAL_URL} and include a
+ * for an {@link Intent} extra, use {@link DownloaderService#EXTRA_CANONICAL_URL} and include a
* {@link String} instance
*
* The implementations of {@link Uri#toString()} and {@link Intent#getDataString()} both
@@ -214,7 +213,7 @@ public class InstallManagerService extends Service {
long apkFileSize = apkFilePath.length();
if (!apkFilePath.exists() || apkFileSize < apk.size) {
Utils.debugLog(TAG, "download " + canonicalUrl + " " + apkFilePath);
- DownloaderService.queue(this, apk.repoId, canonicalUrl, apk.getDownloadUrl());
+ DownloaderService.queue(this, apk.repoId, canonicalUrl, apk.getDownloadUrl(), apk.apkFile);
} else if (ApkCache.apkIsCached(apkFilePath, apk)) {
Utils.debugLog(TAG, "skip download, we have it, straight to install " + canonicalUrl + " " + apkFilePath);
sendBroadcast(intent.getData(), DownloaderService.ACTION_STARTED, apkFilePath);
@@ -222,7 +221,7 @@ public class InstallManagerService extends Service {
} else {
Utils.debugLog(TAG, "delete and download again " + canonicalUrl + " " + apkFilePath);
apkFilePath.delete();
- DownloaderService.queue(this, apk.repoId, canonicalUrl, apk.getDownloadUrl());
+ DownloaderService.queue(this, apk.repoId, canonicalUrl, apk.getDownloadUrl(), apk.apkFile);
}
return START_REDELIVER_INTENT; // if killed before completion, retry Intent
@@ -307,7 +306,7 @@ public class InstallManagerService extends Service {
}
}
};
- DownloaderService.queue(this, repoId, obbUrlString, obbUrlString);
+ DownloaderService.queue(this, repoId, obbUrlString, obbUrlString, null);
localBroadcastManager.registerReceiver(downloadReceiver,
DownloaderService.getIntentFilter(obbUrlString));
}
diff --git a/app/src/main/java/org/fdroid/fdroid/net/BluetoothDownloader.java b/app/src/main/java/org/fdroid/fdroid/net/BluetoothDownloader.java
index 511dadc75..4b4ca5bfc 100644
--- a/app/src/main/java/org/fdroid/fdroid/net/BluetoothDownloader.java
+++ b/app/src/main/java/org/fdroid/fdroid/net/BluetoothDownloader.java
@@ -4,6 +4,7 @@ import android.net.Uri;
import android.util.Log;
import org.apache.commons.io.input.BoundedInputStream;
+import org.fdroid.IndexFile;
import org.fdroid.download.Downloader;
import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.nearby.BluetoothClient;
@@ -39,8 +40,8 @@ public class BluetoothDownloader extends Downloader {
&& Pattern.matches("([0-9A-F]{2}-)+[0-9A-F]{2}", uri.getHost());
}
- public BluetoothDownloader(Uri uri, File destFile) throws IOException {
- super(destFile);
+ BluetoothDownloader(Uri uri, IndexFile indexFile, File destFile) throws IOException {
+ super(indexFile, destFile);
String macAddress = uri.getHost().replace("-", ":");
this.connection = new BluetoothClient(macAddress).openConnection();
this.sourcePath = uri.getPath();
@@ -91,18 +92,11 @@ public class BluetoothDownloader extends Downloader {
@Override
public long totalDownloadSize() {
- if (getFileSize() != null) return getFileSize();
+ if (getIndexFile().getSize() != null) return getIndexFile().getSize();
FileDetails details = getFileDetails();
return details != null ? details.getFileSize() : -1;
}
- @Override
- public void download(long totalSize, @Nullable String sha256) throws IOException, InterruptedException {
- setFileSize(totalSize);
- setSha256(sha256);
- download();
- }
-
@Override
public void download() throws IOException, InterruptedException {
downloadFromStream(false);
diff --git a/app/src/main/java/org/fdroid/fdroid/net/DownloaderFactory.java b/app/src/main/java/org/fdroid/fdroid/net/DownloaderFactory.java
index e94b5a8b4..4fdd79307 100644
--- a/app/src/main/java/org/fdroid/fdroid/net/DownloaderFactory.java
+++ b/app/src/main/java/org/fdroid/fdroid/net/DownloaderFactory.java
@@ -6,18 +6,23 @@ import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import org.fdroid.IndexFile;
import org.fdroid.database.Repository;
import org.fdroid.download.DownloadRequest;
import org.fdroid.download.Downloader;
import org.fdroid.download.HttpDownloader;
+import org.fdroid.download.HttpDownloaderV2;
import org.fdroid.download.HttpManager;
import org.fdroid.download.Mirror;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.Utils;
+import org.fdroid.index.IndexFormatVersion;
import java.io.File;
import java.io.IOException;
import java.net.Proxy;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import info.guardianproject.netcipher.NetCipher;
@@ -32,33 +37,60 @@ public class DownloaderFactory extends org.fdroid.download.DownloaderFactory {
@NonNull
@Override
- public Downloader create(Repository repo, @NonNull Uri uri, @NonNull File destFile) throws IOException {
+ public Downloader create(Repository repo, @NonNull Uri uri, @NonNull IndexFile indexFile,
+ @NonNull File destFile) throws IOException {
List mirrors = repo.getMirrors();
- return create(repo, mirrors, uri, destFile, null);
+ return create(repo, mirrors, uri, indexFile, destFile, null);
}
@NonNull
@Override
protected Downloader create(@NonNull Repository repo, @NonNull List mirrors, @NonNull Uri uri,
- @NonNull File destFile, @Nullable Mirror tryFirst) throws IOException {
+ @NonNull IndexFile indexFile, @NonNull File destFile,
+ @Nullable Mirror tryFirst) throws IOException {
Downloader downloader;
String scheme = uri.getScheme();
if (BluetoothDownloader.SCHEME.equals(scheme)) {
- downloader = new BluetoothDownloader(uri, destFile);
+ downloader = new BluetoothDownloader(uri, indexFile, destFile);
} else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {
- downloader = new TreeUriDownloader(uri, destFile);
+ downloader = new TreeUriDownloader(uri, indexFile, destFile);
} else if (ContentResolver.SCHEME_FILE.equals(scheme)) {
- downloader = new LocalFileDownloader(uri, destFile);
+ downloader = new LocalFileDownloader(uri, indexFile, destFile);
} else {
String repoAddress = Utils.getRepoAddress(repo);
String path = uri.toString().replace(repoAddress, "");
Utils.debugLog(TAG, "Using suffix " + path + " with mirrors " + mirrors);
Proxy proxy = NetCipher.getProxy();
- DownloadRequest request = new DownloadRequest(path, mirrors, proxy, repo.getUsername(),
- repo.getPassword(), tryFirst);
- downloader = new HttpDownloader(HTTP_MANAGER, request, destFile);
+ DownloadRequest request = new DownloadRequest(indexFile, mirrors, proxy,
+ repo.getUsername(), repo.getPassword(), tryFirst);
+ if (repo.getFormatVersion() == null || repo.getFormatVersion() == IndexFormatVersion.ONE) {
+ //noinspection deprecation
+ downloader = new HttpDownloader(HTTP_MANAGER, request, destFile);
+ } else {
+ DownloadRequest r;
+ if (request.getIndexFile().getIpfsCidV1() == null) r = request;
+ else {
+ // add IPFS gateways to mirrors, because have have a CIDv1
+ List m = new ArrayList<>(mirrors);
+ m.addAll(IPFS_MIRRORS);
+ r = new DownloadRequest(request.getIndexFile(), m, proxy, repo.getUsername(),
+ repo.getPassword(), tryFirst);
+ }
+ downloader = new HttpDownloaderV2(HTTP_MANAGER, r, destFile);
+ }
}
return downloader;
}
+
+ private static final List IPFS_MIRRORS = Arrays.asList(
+ new Mirror("https://ipfs.eth.aragon.network/ipfs/", null, true),
+ new Mirror("https://gateway.ipfs.io/ipfs/", null, true),
+ new Mirror("https://ipfs.io/ipfs/", null, true),
+ new Mirror("https://cloudflare-ipfs.com/ipfs/", null, true),
+ new Mirror("https://ipfs.fleek.co/ipfs/", null, true),
+ new Mirror("https://gateway.pinata.cloud/ipfs/", null, true),
+ new Mirror("https://ipfs.filebase.io/ipfs/", null, true)
+ );
+
}
diff --git a/app/src/main/java/org/fdroid/fdroid/net/DownloaderService.java b/app/src/main/java/org/fdroid/fdroid/net/DownloaderService.java
index 6bc009b86..bef7b389d 100644
--- a/app/src/main/java/org/fdroid/fdroid/net/DownloaderService.java
+++ b/app/src/main/java/org/fdroid/fdroid/net/DownloaderService.java
@@ -43,6 +43,7 @@ import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.data.DBHelper;
import org.fdroid.fdroid.data.SanitizedFile;
import org.fdroid.fdroid.installer.ApkCache;
+import org.fdroid.index.v2.FileV1;
import java.io.File;
import java.io.IOException;
@@ -63,11 +64,11 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
/**
* DownloaderService is a service that handles asynchronous download requests
* (expressed as {@link Intent}s) on demand. Clients send download requests
- * through {@link #queue(Context, long, String)} calls. The
+ * through {@link #queue(Context, long, String, String, FileV1)} calls. The
* service is started as needed, it handles each {@code Intent} using a worker
* thread, and stops itself when it runs out of work. Requests can be canceled
* using {@link #cancel(Context, String)}. If this service is killed during
- * operation, it will receive the queued {@link #queue(Context, long, String)}
+ * operation, it will receive the queued {@link #queue(Context, long, String, String, FileV1)}
* and {@link #cancel(Context, String)} requests again due to
* {@link Service#START_REDELIVER_INTENT}. Bad requests will be ignored,
* including on restart after killing via {@link Service#START_NOT_STICKY}.
@@ -123,6 +124,7 @@ public class DownloaderService extends Service {
* @see android.content.Intent#EXTRA_ORIGINATING_URI
*/
public static final String EXTRA_CANONICAL_URL = "org.fdroid.fdroid.net.Downloader.extra.CANONICAL_URL";
+ private static final String EXTRA_INDEX_FILE_V1 = "org.fdroid.fdroid.net.Downloader.extra.INDEX_FILE_V1";
private volatile Looper serviceLooper;
private static volatile ServiceHandler serviceHandler;
@@ -246,6 +248,7 @@ public class DownloaderService extends Service {
final Uri canonicalUrl = intent.getData();
final Uri downloadUrl =
Uri.parse(intent.getStringExtra(DownloaderService.EXTRA_CANONICAL_URL));
+ final FileV1 fileV1 = FileV1.deserialize(intent.getStringExtra(DownloaderService.EXTRA_INDEX_FILE_V1));
final SanitizedFile localFile = ApkCache.getApkDownloadPath(this, canonicalUrl);
sendBroadcast(uri, DownloaderService.ACTION_STARTED, localFile, repoId, canonicalUrl);
@@ -264,7 +267,7 @@ public class DownloaderService extends Service {
} else return; // repo might have been deleted in the meantime
}
}
- downloader = DownloaderFactory.INSTANCE.create(repo, downloadUrl, localFile);
+ downloader = DownloaderFactory.INSTANCE.create(repo, downloadUrl, fileV1, localFile);
downloader.setListener(new ProgressListener() {
@Override
public void onProgress(long bytesRead, long totalBytes) {
@@ -334,7 +337,7 @@ public class DownloaderService extends Service {
* @see #cancel(Context, String)
*/
public static void queue(Context context, long repoId, String canonicalUrl,
- String downloadUrl) {
+ String downloadUrl, FileV1 fileV1) {
if (TextUtils.isEmpty(canonicalUrl)) {
return;
}
@@ -344,6 +347,7 @@ public class DownloaderService extends Service {
intent.setData(Uri.parse(canonicalUrl));
intent.putExtra(DownloaderService.EXTRA_REPO_ID, repoId);
intent.putExtra(DownloaderService.EXTRA_CANONICAL_URL, downloadUrl);
+ intent.putExtra(DownloaderService.EXTRA_INDEX_FILE_V1, fileV1.serialize());
context.startService(intent);
}
@@ -354,7 +358,7 @@ public class DownloaderService extends Service {
*
* @param context this app's {@link Context}
* @param canonicalUrl The URL to remove from the download queue
- * @see #queue(Context, long, String)
+ * @see #queue(Context, long, String, String, FileV1
*/
public static void cancel(Context context, String canonicalUrl) {
if (TextUtils.isEmpty(canonicalUrl)) {
diff --git a/app/src/main/java/org/fdroid/fdroid/net/LocalFileDownloader.java b/app/src/main/java/org/fdroid/fdroid/net/LocalFileDownloader.java
index 72cae0aff..3dd522f9c 100644
--- a/app/src/main/java/org/fdroid/fdroid/net/LocalFileDownloader.java
+++ b/app/src/main/java/org/fdroid/fdroid/net/LocalFileDownloader.java
@@ -3,10 +3,10 @@ package org.fdroid.fdroid.net;
import android.net.Uri;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
+import org.fdroid.IndexFile;
import org.fdroid.download.Downloader;
import org.fdroid.download.NotFoundException;
@@ -31,8 +31,8 @@ public class LocalFileDownloader extends Downloader {
private InputStream inputStream;
private final File sourceFile;
- LocalFileDownloader(Uri uri, File destFile) {
- super(destFile);
+ LocalFileDownloader(Uri uri, IndexFile indexFile, File destFile) {
+ super(indexFile, destFile);
sourceFile = new File(uri.getPath());
}
@@ -73,13 +73,6 @@ public class LocalFileDownloader extends Downloader {
return sourceFile.length();
}
- @Override
- public void download(long totalSize, @Nullable String sha256) throws IOException, InterruptedException {
- setFileSize(totalSize);
- setSha256(sha256);
- download();
- }
-
@Override
public void download() throws IOException, InterruptedException {
if (!sourceFile.exists()) {
diff --git a/app/src/main/java/org/fdroid/fdroid/net/TreeUriDownloader.java b/app/src/main/java/org/fdroid/fdroid/net/TreeUriDownloader.java
index 2788ee594..830a7962f 100644
--- a/app/src/main/java/org/fdroid/fdroid/net/TreeUriDownloader.java
+++ b/app/src/main/java/org/fdroid/fdroid/net/TreeUriDownloader.java
@@ -1,9 +1,9 @@
package org.fdroid.fdroid.net;
-import android.annotation.TargetApi;
import android.content.Context;
import android.net.Uri;
+import org.fdroid.IndexFile;
import org.fdroid.download.Downloader;
import org.fdroid.download.NotFoundException;
import org.fdroid.fdroid.FDroidApp;
@@ -16,7 +16,6 @@ import java.io.InputStream;
import java.net.ProtocolException;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import androidx.documentfile.provider.DocumentFile;
/**
@@ -34,7 +33,6 @@ import androidx.documentfile.provider.DocumentFile;
* @see Open Files using Storage Access Framework
* @see Using Scoped Directory Access
*/
-@TargetApi(21)
public class TreeUriDownloader extends Downloader {
public static final String TAG = "TreeUriDownloader";
@@ -49,8 +47,8 @@ public class TreeUriDownloader extends Downloader {
private final Uri treeUri;
private final DocumentFile documentFile;
- TreeUriDownloader(Uri uri, File destFile) {
- super(destFile);
+ TreeUriDownloader(Uri uri, IndexFile indexFile, File destFile) {
+ super(indexFile, destFile);
context = FDroidApp.getInstance();
String path = uri.getEncodedPath();
int lastEscapedSlash = path.lastIndexOf(ESCAPED_SLASH);
@@ -102,14 +100,7 @@ public class TreeUriDownloader extends Downloader {
@Override
protected long totalDownloadSize() {
- return getFileSize() != null ? getFileSize() : documentFile.length();
- }
-
- @Override
- public void download(long totalSize, @Nullable String sha256) throws IOException, InterruptedException {
- setFileSize(totalSize);
- setSha256(sha256);
- downloadFromStream(false);
+ return getIndexFile().getSize() != null ? getIndexFile().getSize() : documentFile.length();
}
@Override
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 1cdb5328f..0f17adbb8 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
@@ -191,7 +191,7 @@ public class InstallConfirmActivity extends AppCompatActivity implements OnCance
TextView appName = (TextView) appSnippet.findViewById(R.id.app_name);
appName.setText(app.name);
ImageView appIcon = (ImageView) appSnippet.findViewById(R.id.app_icon);
- app.loadWithGlide(this, app.getIconPath(this))
+ app.loadWithGlide(this, app.iconFile)
.apply(Utils.getAlwaysShowIconRequestOptions())
.into(appIcon);
}
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 aa2ae0afc..e2f45dbc3 100644
--- a/app/src/main/java/org/fdroid/fdroid/views/AppDetailsRecyclerViewAdapter.java
+++ b/app/src/main/java/org/fdroid/fdroid/views/AppDetailsRecyclerViewAdapter.java
@@ -63,6 +63,7 @@ import org.fdroid.fdroid.privileged.views.AppDiff;
import org.fdroid.fdroid.privileged.views.AppSecurityPermissions;
import org.fdroid.fdroid.views.appdetails.AntiFeaturesListingView;
import org.fdroid.fdroid.views.main.MainActivity;
+import org.fdroid.index.v2.FileV2;
import java.io.File;
import java.util.ArrayList;
@@ -148,8 +149,8 @@ public class AppDetailsRecyclerViewAdapter
compatibleVersionsDifferentSig.add(apk);
if (allowBySig) {
versions.add(apk);
- if (!versionsExpandTracker.containsKey(apk.apkName)) {
- versionsExpandTracker.put(apk.apkName, false);
+ if (!versionsExpandTracker.containsKey(apk.getApkPath())) {
+ versionsExpandTracker.put(apk.getApkPath(), false);
}
}
}
@@ -713,7 +714,7 @@ public class AppDetailsRecyclerViewAdapter
@Override
public void onScreenshotClick(int position) {
- ArrayList screenshots = Objects.requireNonNull(app).getAllScreenshots();
+ List screenshots = Objects.requireNonNull(app).getAllScreenshots();
context.startActivity(ScreenShotsActivity.getStartIntent(context, app.repoId, screenshots, position));
}
@@ -1104,7 +1105,8 @@ public class AppDetailsRecyclerViewAdapter
TextUtils.equals(apk.sig, app.installedSig);
boolean isApkSuggested = apk.equals(suggestedApk);
boolean isApkDownloading = callbacks.isAppDownloading() && downloadedApk != null &&
- downloadedApk.compareTo(apk) == 0 && TextUtils.equals(apk.apkName, downloadedApk.apkName);
+ downloadedApk.compareTo(apk) == 0 &&
+ TextUtils.equals(apk.getApkPath(), downloadedApk.getApkPath());
boolean isApkInstalledDummy = apk.versionCode == app.installedVersionCode &&
apk.compatible && apk.size == 0 && apk.maxSdkVersion == -1;
@@ -1198,7 +1200,7 @@ public class AppDetailsRecyclerViewAdapter
}
// Expand the view if it was previously expanded or when downloading
- expand(versionsExpandTracker.get(apk.apkName) || isApkDownloading);
+ expand(versionsExpandTracker.get(apk.getApkPath()) || isApkDownloading);
// Toggle expanded view when clicking the whole version item,
// unless it's an installed app version dummy item - it doesn't
@@ -1293,7 +1295,7 @@ public class AppDetailsRecyclerViewAdapter
}
private void expand(boolean expand) {
- versionsExpandTracker.put(apk.apkName, expand);
+ versionsExpandTracker.put(apk.getApkPath(), expand);
expandedLayout.setVisibility(expand ? View.VISIBLE : View.GONE);
versionCode.setVisibility(expand ? View.VISIBLE : View.GONE);
expandArrow.setImageDrawable(ContextCompat.getDrawable(context, expand ?
@@ -1314,7 +1316,7 @@ public class AppDetailsRecyclerViewAdapter
return;
}
- boolean expand = !versionsExpandTracker.get(apk.apkName);
+ boolean expand = !versionsExpandTracker.get(apk.getApkPath());
expand(expand);
if (expand) {
diff --git a/app/src/main/java/org/fdroid/fdroid/views/ScreenShotsActivity.java b/app/src/main/java/org/fdroid/fdroid/views/ScreenShotsActivity.java
index c0e24cb59..13ea5f72a 100644
--- a/app/src/main/java/org/fdroid/fdroid/views/ScreenShotsActivity.java
+++ b/app/src/main/java/org/fdroid/fdroid/views/ScreenShotsActivity.java
@@ -20,9 +20,10 @@ import androidx.viewpager.widget.ViewPager;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.R;
+import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.data.App;
+import org.fdroid.index.v2.FileV2;
-import java.util.ArrayList;
import java.util.List;
/**
@@ -41,11 +42,11 @@ public class ScreenShotsActivity extends AppCompatActivity {
private static boolean allowDownload = true;
- public static Intent getStartIntent(Context context, long repoId, ArrayList screenshots,
+ public static Intent getStartIntent(Context context, long repoId, List screenshots,
int startPosition) {
Intent intent = new Intent(context, ScreenShotsActivity.class);
intent.putExtra(EXTRA_REPO_ID, repoId);
- intent.putStringArrayListExtra(EXTRA_SCREENSHOT_LIST, screenshots);
+ intent.putStringArrayListExtra(EXTRA_SCREENSHOT_LIST, Utils.toString(screenshots));
intent.putExtra(EXTRA_START_POSITION, startPosition);
return intent;
}
@@ -59,7 +60,8 @@ public class ScreenShotsActivity extends AppCompatActivity {
setContentView(R.layout.activity_screenshots);
long repoId = getIntent().getLongExtra(EXTRA_REPO_ID, 1);
- List screenshots = getIntent().getStringArrayListExtra(EXTRA_SCREENSHOT_LIST);
+ List list = getIntent().getStringArrayListExtra(EXTRA_SCREENSHOT_LIST);
+ List screenshots = Utils.fileV2FromStrings(list);
int startPosition = getIntent().getIntExtra(EXTRA_START_POSITION, 0);
ViewPager viewPager = (ViewPager) findViewById(R.id.screenshot_view_pager);
@@ -86,9 +88,9 @@ public class ScreenShotsActivity extends AppCompatActivity {
private static class ScreenShotPagerAdapter extends FragmentStatePagerAdapter {
private final long repoId;
- private final List screenshots;
+ private final List screenshots;
- ScreenShotPagerAdapter(FragmentManager fragmentManager, long repoId, List screenshots) {
+ ScreenShotPagerAdapter(FragmentManager fragmentManager, long repoId, List screenshots) {
super(fragmentManager);
this.repoId = repoId;
this.screenshots = screenshots;
@@ -113,23 +115,23 @@ public class ScreenShotsActivity extends AppCompatActivity {
private static final String ARG_REPO_ID = "ARG_REPO_ID";
private static final String ARG_SCREENSHOT_URL = "ARG_SCREENSHOT_URL";
- static ScreenShotPageFragment newInstance(long repoId, @NonNull String screenshotUrl) {
+ static ScreenShotPageFragment newInstance(long repoId, @NonNull FileV2 screenshotUrl) {
ScreenShotPageFragment fragment = new ScreenShotPageFragment();
Bundle args = new Bundle();
args.putLong(ARG_REPO_ID, repoId);
- args.putString(ARG_SCREENSHOT_URL, screenshotUrl);
+ args.putString(ARG_SCREENSHOT_URL, screenshotUrl.serialize());
fragment.setArguments(args);
return fragment;
}
private long repoId;
- private String screenshotUrl;
+ private FileV2 screenshot;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
repoId = requireArguments().getLong(ARG_REPO_ID);
- screenshotUrl = requireArguments().getString(ARG_SCREENSHOT_URL);
+ screenshot = FileV2.deserialize(requireArguments().getString(ARG_SCREENSHOT_URL));
}
@Nullable
@@ -139,7 +141,7 @@ public class ScreenShotsActivity extends AppCompatActivity {
View rootView = inflater.inflate(R.layout.activity_screenshots_page, container, false);
ImageView screenshotView = (ImageView) rootView.findViewById(R.id.screenshot);
- App.loadWithGlide(requireContext(), repoId, screenshotUrl)
+ App.loadWithGlide(requireContext(), repoId, screenshot)
.onlyRetrieveFromCache(!allowDownload)
.error(R.drawable.screenshot_placeholder)
.fallback(R.drawable.screenshot_placeholder)
diff --git a/app/src/main/java/org/fdroid/fdroid/views/ScreenShotsRecyclerViewAdapter.java b/app/src/main/java/org/fdroid/fdroid/views/ScreenShotsRecyclerViewAdapter.java
index a86d3da1b..10fa5d5f1 100644
--- a/app/src/main/java/org/fdroid/fdroid/views/ScreenShotsRecyclerViewAdapter.java
+++ b/app/src/main/java/org/fdroid/fdroid/views/ScreenShotsRecyclerViewAdapter.java
@@ -12,6 +12,7 @@ import com.bumptech.glide.request.RequestOptions;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.data.App;
+import org.fdroid.index.v2.FileV2;
import java.util.List;
@@ -20,7 +21,7 @@ import java.util.List;
*/
class ScreenShotsRecyclerViewAdapter extends RecyclerView.Adapter {
private final long repoId;
- private final List screenshots;
+ private final List screenshots;
private final RequestOptions displayImageOptions;
private final Listener listener;
diff --git a/app/src/main/java/org/fdroid/fdroid/views/apps/FeatureImage.java b/app/src/main/java/org/fdroid/fdroid/views/apps/FeatureImage.java
index 300707434..684374ab4 100644
--- a/app/src/main/java/org/fdroid/fdroid/views/apps/FeatureImage.java
+++ b/app/src/main/java/org/fdroid/fdroid/views/apps/FeatureImage.java
@@ -9,7 +9,6 @@ import android.graphics.Path;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
-import android.text.TextUtils;
import android.util.AttributeSet;
import androidx.annotation.ColorInt;
@@ -25,6 +24,7 @@ import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import org.fdroid.fdroid.R;
+import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.data.App;
import java.util.Random;
@@ -251,11 +251,10 @@ public class FeatureImage extends AppCompatImageView {
public void loadImageAndDisplay(App app) {
setColour(ContextCompat.getColor(getContext(), R.color.fdroid_blue));
- if (!TextUtils.isEmpty(app.featureGraphic)) {
- app.loadWithGlide(getContext(), app.featureGraphic).into(this);
+ if (app.featureGraphic == null) {
+ loadImageAndExtractColour(app.loadWithGlide(getContext(), app.iconFile));
} else {
- String path = app.getIconPath(getContext());
- loadImageAndExtractColour(app.loadWithGlide(getContext(), path));
+ Utils.loadWithGlide(getContext(), app.repoId, app.featureGraphic, this);
}
}
diff --git a/app/src/test/java/org/fdroid/fdroid/RepoUrlsTest.java b/app/src/test/java/org/fdroid/fdroid/RepoUrlsTest.java
index 76b33ad2f..b0c7c02dd 100644
--- a/app/src/test/java/org/fdroid/fdroid/RepoUrlsTest.java
+++ b/app/src/test/java/org/fdroid/fdroid/RepoUrlsTest.java
@@ -20,6 +20,7 @@
package org.fdroid.fdroid;
import org.fdroid.fdroid.data.Apk;
+import org.fdroid.index.v2.FileV1;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -133,7 +134,7 @@ public class RepoUrlsTest {
public void testApkUrls() {
testReposWithFile(APK_NAME, tr -> {
Apk apk = new Apk();
- apk.apkName = APK_NAME;
+ apk.apkFile = new FileV1(APK_NAME, "hash", null, null);
apk.versionCode = 1;
apk.repoAddress = tr.repoUrl;
apk.canonicalRepoAddress = tr.repoUrl;
diff --git a/app/src/test/java/org/fdroid/fdroid/TestUtils.java b/app/src/test/java/org/fdroid/fdroid/TestUtils.java
index 2ab6ad391..f7887a4b3 100644
--- a/app/src/test/java/org/fdroid/fdroid/TestUtils.java
+++ b/app/src/test/java/org/fdroid/fdroid/TestUtils.java
@@ -2,6 +2,7 @@ package org.fdroid.fdroid;
import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.data.App;
+import org.fdroid.index.v2.FileV1;
import java.io.File;
import java.io.FileOutputStream;
@@ -41,20 +42,19 @@ public class TestUtils {
}
}
- public static Apk getApk(long appId, int versionCode) {
- return getApk(appId, versionCode, "signature", null);
+ public static Apk getApk(int versionCode) {
+ return getApk(versionCode, "signature", null);
}
- public static Apk getApk(long appId, int versionCode, String signature, String releaseChannel) {
+ public static Apk getApk(int versionCode, String signature, String releaseChannel) {
Apk apk = new Apk();
- apk.appId = appId;
apk.repoAddress = "http://www.example.com/fdroid/repo";
apk.canonicalRepoAddress = "http://www.example.com/fdroid/repo";
apk.versionCode = versionCode;
apk.repoId = 1;
apk.versionName = "The good one";
apk.hash = "11111111aaaaaaaa";
- apk.apkName = "Test Apk";
+ apk.apkFile = new FileV1("Test Apk", "hash", null, null);
apk.size = 10000;
apk.compatible = true;
apk.sig = signature;
diff --git a/app/src/test/java/org/fdroid/fdroid/data/ApkTest.java b/app/src/test/java/org/fdroid/fdroid/data/ApkTest.java
index 9ec5c0dc5..a98b6efcb 100644
--- a/app/src/test/java/org/fdroid/fdroid/data/ApkTest.java
+++ b/app/src/test/java/org/fdroid/fdroid/data/ApkTest.java
@@ -7,6 +7,7 @@ import android.webkit.MimeTypeMap;
import org.apache.commons.io.FileUtils;
import org.fdroid.fdroid.installer.ApkCache;
import org.fdroid.fdroid.nearby.PublicSourceDirProvider;
+import org.fdroid.index.v2.FileV1;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -17,6 +18,7 @@ import org.robolectric.shadows.ShadowMimeTypeMap;
import java.io.File;
import java.io.IOException;
+import java.net.URL;
import androidx.test.core.app.ApplicationProvider;
@@ -41,7 +43,7 @@ public class ApkTest {
@Test(expected = IllegalStateException.class)
public void testGetMediaInstallPathWithApk() {
Apk apk = new Apk();
- apk.apkName = "test.apk";
+ apk.apkFile = new FileV1("test.apk", "hash", null, null);
apk.repoAddress = "https://example.com/fdroid/repo";
apk.canonicalRepoAddress = "https://example.com/fdroid/repo";
assertTrue(apk.isApk());
@@ -51,7 +53,7 @@ public class ApkTest {
@Test
public void testGetMediaInstallPathWithOta() throws IOException {
Apk apk = new Apk();
- apk.apkName = "org.fdroid.fdroid.privileged.ota_2110.zip";
+ apk.apkFile = new FileV1("org.fdroid.fdroid.privileged.ota_2110.zip", "hash", null, null);
apk.repoAddress = "https://example.com/fdroid/repo";
apk.canonicalRepoAddress = "https://example.com/fdroid/repo";
assertFalse(apk.isApk());
@@ -63,7 +65,7 @@ public class ApkTest {
@Test
public void testGetMediaInstallPathWithObf() {
Apk apk = new Apk();
- apk.apkName = "Norway_bouvet_europe_2.obf";
+ apk.apkFile = new FileV1("Norway_bouvet_europe_2.obf", "hash", null, null);
apk.repoAddress = "https://example.com/fdroid/repo";
apk.canonicalRepoAddress = "https://example.com/fdroid/repo";
assertFalse(apk.isApk());
@@ -74,7 +76,7 @@ public class ApkTest {
@Test
public void testGetMediaInstallPathWithObfZip() throws IOException {
Apk apk = new Apk();
- apk.apkName = "Norway_bouvet_europe_2.obf.zip";
+ apk.apkFile = new FileV1("Norway_bouvet_europe_2.obf.zip", "hash", null, null);
apk.repoAddress = "https://example.com/fdroid/repo";
apk.canonicalRepoAddress = "https://example.com/fdroid/repo";
assertFalse(apk.isApk());
@@ -84,7 +86,8 @@ public class ApkTest {
}
private void copyResourceFileToCache(Apk apk) throws IOException {
- FileUtils.copyInputStreamToFile(getClass().getClassLoader().getResource(apk.apkName).openStream(),
+ URL res = getClass().getClassLoader().getResource(apk.apkFile.getName());
+ FileUtils.copyInputStreamToFile(res.openStream(),
ApkCache.getApkDownloadPath(context, apk.getCanonicalUrl()));
}
}
diff --git a/app/src/test/java/org/fdroid/fdroid/data/SuggestedVersionTest.java b/app/src/test/java/org/fdroid/fdroid/data/SuggestedVersionTest.java
index a3adffb13..af73be714 100644
--- a/app/src/test/java/org/fdroid/fdroid/data/SuggestedVersionTest.java
+++ b/app/src/test/java/org/fdroid/fdroid/data/SuggestedVersionTest.java
@@ -38,9 +38,9 @@ public class SuggestedVersionTest {
App singleApp = TestUtils.getApp();
singleApp.installedVersionCode = 1;
singleApp.installedSig = TestUtils.FDROID_SIG;
- Apk apk1 = TestUtils.getApk(singleApp.getId(), 1, TestUtils.FDROID_SIG, Apk.RELEASE_CHANNEL_STABLE);
- Apk apk2 = TestUtils.getApk(singleApp.getId(), 2, TestUtils.FDROID_SIG, Apk.RELEASE_CHANNEL_STABLE);
- Apk apk3 = TestUtils.getApk(singleApp.getId(), 3, TestUtils.FDROID_SIG, Apk.RELEASE_CHANNEL_BETA);
+ Apk apk1 = TestUtils.getApk(1, TestUtils.FDROID_SIG, Apk.RELEASE_CHANNEL_STABLE);
+ Apk apk2 = TestUtils.getApk(2, TestUtils.FDROID_SIG, Apk.RELEASE_CHANNEL_STABLE);
+ Apk apk3 = TestUtils.getApk(3, TestUtils.FDROID_SIG, Apk.RELEASE_CHANNEL_BETA);
List apks = new ArrayList<>();
apks.add(apk3);
apks.add(apk2);
@@ -57,11 +57,11 @@ public class SuggestedVersionTest {
App singleApp = TestUtils.getApp();
singleApp.installedVersionCode = 0;
- Apk apk1 = TestUtils.getApk(singleApp.getId(), 1, TestUtils.FDROID_SIG, Apk.RELEASE_CHANNEL_STABLE);
- Apk apk2 = TestUtils.getApk(singleApp.getId(), 2, TestUtils.FDROID_SIG, Apk.RELEASE_CHANNEL_STABLE);
- Apk apk3 = TestUtils.getApk(singleApp.getId(), 3, TestUtils.FDROID_SIG, Apk.RELEASE_CHANNEL_STABLE);
- Apk apk4 = TestUtils.getApk(singleApp.getId(), 4, TestUtils.UPSTREAM_SIG, Apk.RELEASE_CHANNEL_STABLE);
- Apk apk5 = TestUtils.getApk(singleApp.getId(), 5, TestUtils.UPSTREAM_SIG, Apk.RELEASE_CHANNEL_BETA);
+ Apk apk1 = TestUtils.getApk(1, TestUtils.FDROID_SIG, Apk.RELEASE_CHANNEL_STABLE);
+ Apk apk2 = TestUtils.getApk(2, TestUtils.FDROID_SIG, Apk.RELEASE_CHANNEL_STABLE);
+ Apk apk3 = TestUtils.getApk(3, TestUtils.FDROID_SIG, Apk.RELEASE_CHANNEL_STABLE);
+ Apk apk4 = TestUtils.getApk(4, TestUtils.UPSTREAM_SIG, Apk.RELEASE_CHANNEL_STABLE);
+ Apk apk5 = TestUtils.getApk(5, TestUtils.UPSTREAM_SIG, Apk.RELEASE_CHANNEL_BETA);
List apks = new ArrayList<>();
apks.add(apk5);
apks.add(apk4);
@@ -80,8 +80,8 @@ public class SuggestedVersionTest {
assertSuggested(singleApp, apks, 3, Apk.RELEASE_CHANNEL_STABLE);
// This adds the "suggestedVersionCode" version of the app, but signed by f-droid.
- Apk apk4f = TestUtils.getApk(singleApp.getId(), 4, TestUtils.FDROID_SIG, Apk.RELEASE_CHANNEL_STABLE);
- Apk apk5f = TestUtils.getApk(singleApp.getId(), 5, TestUtils.FDROID_SIG, Apk.RELEASE_CHANNEL_BETA);
+ Apk apk4f = TestUtils.getApk(4, TestUtils.FDROID_SIG, Apk.RELEASE_CHANNEL_STABLE);
+ Apk apk5f = TestUtils.getApk(5, TestUtils.FDROID_SIG, Apk.RELEASE_CHANNEL_BETA);
apks.clear();
apks.add(apk5);
apks.add(apk5f);
diff --git a/app/src/test/java/org/fdroid/fdroid/installer/FileInstallerTest.java b/app/src/test/java/org/fdroid/fdroid/installer/FileInstallerTest.java
index 3512d32fe..fb6d6f720 100644
--- a/app/src/test/java/org/fdroid/fdroid/installer/FileInstallerTest.java
+++ b/app/src/test/java/org/fdroid/fdroid/installer/FileInstallerTest.java
@@ -4,6 +4,7 @@ import android.content.ContextWrapper;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.data.Apk;
+import org.fdroid.index.v2.FileV1;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -17,7 +18,6 @@ import static org.junit.Assert.assertFalse;
@RunWith(RobolectricTestRunner.class)
public class FileInstallerTest {
- public static final String TAG = "FileInstallerTest";
private ContextWrapper context;
@@ -31,7 +31,7 @@ public class FileInstallerTest {
@Test
public void testInstallOtaZip() {
Apk apk = new Apk();
- apk.apkName = "org.fdroid.fdroid.privileged.ota_2010.zip";
+ apk.apkFile = new FileV1("org.fdroid.fdroid.privileged.ota_2010.zip", "hash", null, null);
apk.packageName = "org.fdroid.fdroid.privileged.ota";
apk.versionCode = 2010;
assertFalse(apk.isApk());
diff --git a/app/src/test/java/org/fdroid/fdroid/installer/InstallerFactoryTest.java b/app/src/test/java/org/fdroid/fdroid/installer/InstallerFactoryTest.java
index cca65c351..8265bfd80 100644
--- a/app/src/test/java/org/fdroid/fdroid/installer/InstallerFactoryTest.java
+++ b/app/src/test/java/org/fdroid/fdroid/installer/InstallerFactoryTest.java
@@ -4,6 +4,7 @@ import android.content.ContextWrapper;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.data.Apk;
+import org.fdroid.index.v2.FileV1;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -28,7 +29,7 @@ public class InstallerFactoryTest {
public void testApkInstallerInstance() {
for (String filename : new String[]{"test.apk", "A.APK", "b.ApK"}) {
Apk apk = new Apk();
- apk.apkName = filename;
+ apk.apkFile = new FileV1(filename, "hash", null, null);
apk.packageName = "test";
Installer installer = InstallerFactory.create(context, apk);
assertEquals(filename + " should use a DefaultInstaller",
@@ -41,7 +42,7 @@ public class InstallerFactoryTest {
public void testFileInstallerInstance() {
for (String filename : new String[]{"org.fdroid.fdroid.privileged.ota_2110.zip", "test.ZIP"}) {
Apk apk = new Apk();
- apk.apkName = filename;
+ apk.apkFile = new FileV1(filename, "hash", null, null);
apk.packageName = "cafe0088";
Installer installer = InstallerFactory.create(context, apk);
assertEquals("should be a FileInstaller",
diff --git a/app/src/test/java/org/fdroid/fdroid/views/AppDetailsAdapterTest.java b/app/src/test/java/org/fdroid/fdroid/views/AppDetailsAdapterTest.java
index 9d0ce90b8..7d54cd2d8 100644
--- a/app/src/test/java/org/fdroid/fdroid/views/AppDetailsAdapterTest.java
+++ b/app/src/test/java/org/fdroid/fdroid/views/AppDetailsAdapterTest.java
@@ -17,6 +17,7 @@ import org.fdroid.fdroid.R;
import org.fdroid.fdroid.TestUtils;
import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.data.App;
+import org.fdroid.index.v2.FileV2;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -57,7 +58,9 @@ public class AppDetailsAdapterTest {
@Test
public void appWithScreenshots() {
App app = TestUtils.getApp();
- app.phoneScreenshots = new String[]{"screenshot1.png", "screenshot2.png"};
+ app.phoneScreenshots = new ArrayList<>(2);
+ app.phoneScreenshots.add(FileV2.fromPath("screenshot1.png"));
+ app.phoneScreenshots.add(FileV2.fromPath("screenshot2.png"));
AppDetailsRecyclerViewAdapter adapter = new AppDetailsRecyclerViewAdapter(context, app, dummyCallbacks);
adapter.updateItems(app, Collections.emptyList(), appPrefs);
@@ -71,9 +74,9 @@ public class AppDetailsAdapterTest {
App app = TestUtils.getApp();
app.preferredSigner = "eaa1d713b9c2a0475234a86d6539f910";
List apks = new ArrayList<>();
- apks.add(TestUtils.getApk(app.getId(), 1));
- apks.add(TestUtils.getApk(app.getId(), 2));
- apks.add(TestUtils.getApk(app.getId(), 3));
+ apks.add(TestUtils.getApk(1));
+ apks.add(TestUtils.getApk(2));
+ apks.add(TestUtils.getApk(3));
app.installedApk = apks.get(0);
AppDetailsRecyclerViewAdapter adapter = new AppDetailsRecyclerViewAdapter(context, app, dummyCallbacks);