Add Repo.getFileUrl() method to get file URL in a standard way
This commit is contained in:
parent
5187b88a08
commit
3cb6cc747b
@ -44,7 +44,6 @@ import org.fdroid.fdroid.installer.InstallManagerService;
|
||||
import org.fdroid.fdroid.installer.InstallerService;
|
||||
import org.fdroid.fdroid.net.Downloader;
|
||||
import org.fdroid.fdroid.net.DownloaderFactory;
|
||||
import org.fdroid.fdroid.net.TreeUriDownloader;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
@ -116,11 +115,7 @@ public class IndexUpdater {
|
||||
}
|
||||
|
||||
protected String getIndexUrl(@NonNull Repo repo) {
|
||||
if (repo.address.startsWith("content://")) {
|
||||
return repo.address + TreeUriDownloader.ESCAPED_SLASH + SIGNED_FILE_NAME;
|
||||
} else {
|
||||
return repo.address + "/" + SIGNED_FILE_NAME;
|
||||
}
|
||||
return repo.getFileUrl(SIGNED_FILE_NAME);
|
||||
}
|
||||
|
||||
public boolean hasChanged() {
|
||||
|
@ -24,7 +24,7 @@ package org.fdroid.fdroid;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
@ -97,15 +97,8 @@ public class IndexV1Updater extends IndexUpdater {
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Storage Access Framework URLs have a crazy encoded path within the URL path.
|
||||
*/
|
||||
protected String getIndexUrl(@NonNull Repo repo) {
|
||||
if (repo.address.startsWith("content://")) {
|
||||
return repo.address + "%2F" + SIGNED_FILE_NAME;
|
||||
} else {
|
||||
return Uri.parse(repo.address).buildUpon().appendPath(SIGNED_FILE_NAME).build().toString();
|
||||
}
|
||||
return repo.getFileUrl(SIGNED_FILE_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -120,7 +120,7 @@ public final class Utils {
|
||||
|
||||
private static Handler toastHandler;
|
||||
|
||||
public static final String FALLBACK_ICONS_DIR = "/icons/";
|
||||
public static final String FALLBACK_ICONS_DIR = "icons";
|
||||
|
||||
/*
|
||||
* @param dpiMultiplier Lets you grab icons for densities larger or
|
||||
@ -132,22 +132,22 @@ public final class Utils {
|
||||
final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
|
||||
final double dpi = metrics.densityDpi * dpiMultiplier;
|
||||
if (dpi >= 640) {
|
||||
return "/icons-640/";
|
||||
return "icons-640";
|
||||
}
|
||||
if (dpi >= 480) {
|
||||
return "/icons-480/";
|
||||
return "icons-480";
|
||||
}
|
||||
if (dpi >= 320) {
|
||||
return "/icons-320/";
|
||||
return "icons-320";
|
||||
}
|
||||
if (dpi >= 240) {
|
||||
return "/icons-240/";
|
||||
return "icons-240";
|
||||
}
|
||||
if (dpi >= 160) {
|
||||
return "/icons-160/";
|
||||
return "icons-160";
|
||||
}
|
||||
|
||||
return "/icons-120/";
|
||||
return "icons-120";
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -280,7 +280,8 @@ public class Apk extends ValueObject implements Comparable<Apk>, Parcelable {
|
||||
@JsonIgnore // prevent tests from failing due to nulls in checkRepoAddress()
|
||||
public String getCanonicalUrl() {
|
||||
checkRepoAddress();
|
||||
return repoAddress + "/" + apkName.replace(" ", "%20");
|
||||
Repo repo = new Repo(repoAddress);
|
||||
return repo.getFileUrl(apkName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -735,9 +735,9 @@ public class App extends ValueObject implements Comparable<App>, Parcelable {
|
||||
} else {
|
||||
iconsDir = Utils.FALLBACK_ICONS_DIR;
|
||||
}
|
||||
return repo.address + iconsDir + iconFromApk;
|
||||
return repo.getFileUrl(iconsDir, iconFromApk);
|
||||
}
|
||||
return repo.address + "/" + packageName + "/" + iconUrl;
|
||||
return repo.getFileUrl(packageName, iconUrl);
|
||||
}
|
||||
|
||||
public String getFeatureGraphicUrl(Context context) {
|
||||
@ -745,7 +745,7 @@ public class App extends ValueObject implements Comparable<App>, Parcelable {
|
||||
return null;
|
||||
}
|
||||
Repo repo = RepoProvider.Helper.findById(context, repoId);
|
||||
return repo.address + "/" + packageName + "/" + featureGraphic;
|
||||
return repo.getFileUrl(packageName, featureGraphic);
|
||||
}
|
||||
|
||||
public String getPromoGraphic(Context context) {
|
||||
@ -753,7 +753,7 @@ public class App extends ValueObject implements Comparable<App>, Parcelable {
|
||||
return null;
|
||||
}
|
||||
Repo repo = RepoProvider.Helper.findById(context, repoId);
|
||||
return repo.address + "/" + packageName + "/" + promoGraphic;
|
||||
return repo.getFileUrl(packageName, promoGraphic);
|
||||
}
|
||||
|
||||
public String getTvBanner(Context context) {
|
||||
@ -761,7 +761,7 @@ public class App extends ValueObject implements Comparable<App>, Parcelable {
|
||||
return null;
|
||||
}
|
||||
Repo repo = RepoProvider.Helper.findById(context, repoId);
|
||||
return repo.address + "/" + packageName + "/" + tvBanner;
|
||||
return repo.getFileUrl(packageName, tvBanner);
|
||||
}
|
||||
|
||||
public String[] getAllScreenshots(Context context) {
|
||||
@ -785,7 +785,7 @@ public class App extends ValueObject implements Comparable<App>, Parcelable {
|
||||
String[] result = new String[list.size()];
|
||||
int i = 0;
|
||||
for (String url : list) {
|
||||
result[i] = repo.address + "/" + packageName + "/" + url;
|
||||
result[i] = repo.getFileUrl(packageName, url);
|
||||
i++;
|
||||
}
|
||||
return result;
|
||||
|
@ -25,13 +25,16 @@ package org.fdroid.fdroid.data;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import org.fdroid.fdroid.FDroidApp;
|
||||
import org.fdroid.fdroid.Preferences;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
import org.fdroid.fdroid.data.Schema.RepoTable.Cols;
|
||||
import org.fdroid.fdroid.net.TreeUriDownloader;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
@ -141,6 +144,10 @@ public class Repo extends ValueObject {
|
||||
public Repo() {
|
||||
}
|
||||
|
||||
public Repo(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public Repo(Cursor cursor) {
|
||||
|
||||
checkCursorPosition(cursor);
|
||||
@ -263,6 +270,42 @@ public class Repo extends ValueObject {
|
||||
return tempName;
|
||||
}
|
||||
|
||||
public String getFileUrl(String... pathElements)
|
||||
{
|
||||
/* Each String in pathElements might contain a /, should keep these as path elements */
|
||||
List<String> elements = new ArrayList();
|
||||
for (String element: pathElements) {
|
||||
for (String elementPart : element.split("/")) {
|
||||
elements.add(elementPart);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Storage Access Framework URLs have this wacky URL-encoded path within the URL path.
|
||||
*
|
||||
* i.e.
|
||||
* content://authority/tree/313E-1F1C%3A/document/313E-1F1C%3Aguardianproject.info%2Ffdroid%2Frepo
|
||||
*
|
||||
* Currently don't know a better way to identify these than by content:// prefix,
|
||||
* seems the Android SDK expects apps to consider them as opaque identifiers.
|
||||
*/
|
||||
if (address.startsWith("content://")) {
|
||||
StringBuilder result = new StringBuilder(address);
|
||||
for (String element: elements) {
|
||||
result.append(TreeUriDownloader.ESCAPED_SLASH);
|
||||
result.append(element);
|
||||
}
|
||||
return result.toString();
|
||||
} else { // Normal URL
|
||||
Uri.Builder result = Uri.parse(address).buildUpon();
|
||||
for (String element: elements) {
|
||||
result.appendPath((element));
|
||||
}
|
||||
return result.build().toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static int toInt(Integer value) {
|
||||
if (value == null) {
|
||||
return 0;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Senecto Limited
|
||||
* Copyright (C) 2018-2021 Senecto Limited
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@ -43,8 +43,13 @@ import static org.junit.Assert.assertEquals;
|
||||
public class RepoUrlsTest extends FDroidProviderTest {
|
||||
private static final String TAG = "RepoUrlsTest";
|
||||
|
||||
/** Private class describing a repository URL we're going to test, and
|
||||
* the file pattern for any files within that URL.
|
||||
*/
|
||||
private static class TestRepo {
|
||||
// Repo URL for the test case
|
||||
public String repoUrl;
|
||||
// String format pattern for generating file URLs, should contain a single %s for the filename
|
||||
public String fileUrlPattern;
|
||||
|
||||
public TestRepo(String repoUrl, String fileUrlPattern)
|
||||
@ -74,11 +79,13 @@ public class RepoUrlsTest extends FDroidProviderTest {
|
||||
"https://raw.githubusercontent.com/guardianproject/fdroid-repo/master/fdroid/repo/%s"),
|
||||
new TestRepo(
|
||||
"content://com.android.externalstorage.documents/tree/1AFB-2402%3A/document/1AFB-2402%3Atesty.at.or.at%2Ffdroid%2Frepo",
|
||||
// note escaped URL-encoding % in format string patterns
|
||||
// note: to have a URL-escaped path in a format string pattern, we need to
|
||||
// %-escape all URL %
|
||||
"content://com.android.externalstorage.documents/tree/1AFB-2402%%3A/document/1AFB-2402%%3Atesty.at.or.at%%2Ffdroid%%2Frepo%%2F%s"),
|
||||
new TestRepo(
|
||||
"content://authority/tree/313E-1F1C%3A/document/313E-1F1C%3Aguardianproject.info%2Ffdroid%2Frepo",
|
||||
// note escaped URL-encoding % in format string patterns
|
||||
// note: to have a URL-escaped path in a format string pattern, we need to
|
||||
// %-escape all URL %
|
||||
"content://authority/tree/313E-1F1C%%3A/document/313E-1F1C%%3Aguardianproject.info%%2Ffdroid%%2Frepo%%2F%s"),
|
||||
new TestRepo(
|
||||
"http://10.20.31.244:8888/fdroid/repo?FINGERPRINT=35521D88285A9D06FBE33D35FB8B4BB872D753666CF981728E2249FEE6D2D0F2&SWAP=1&BSSID=FE:EE:DA:45:2D:4E",
|
||||
@ -97,6 +104,13 @@ public class RepoUrlsTest extends FDroidProviderTest {
|
||||
String get(TestRepo tr);
|
||||
}
|
||||
|
||||
/** Utility test function - go through the list of test repos,
|
||||
* using the useOfRepo interface to instantiate a repo from the URL
|
||||
* and return a file of some kind (Apk, index, etc.) and check that
|
||||
* it matches the test repo's expected URL format.
|
||||
* @param fileName File that 'useOfRepo' will return in the repo, when called
|
||||
* @param useOfRepo Instance of the function that uses the repo to build a file URL
|
||||
*/
|
||||
private void testReposWithFile(String fileName, getFileFromRepo useOfRepo)
|
||||
{
|
||||
for(TestRepo tr: REPOS) {
|
||||
@ -146,18 +160,4 @@ public class RepoUrlsTest extends FDroidProviderTest {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Apk insertApk(String packageName, String name, String repoAddress) {
|
||||
|
||||
App app = Assert.insertApp(context, packageName, name);
|
||||
|
||||
ContentValues additionalValues = new ContentValues();
|
||||
additionalValues.put(ApkTable.Cols.Repo.ADDRESS, repoAddress);
|
||||
|
||||
Uri contentUri = Assert.insertApk(context, app, 1, additionalValues);
|
||||
Cursor queryCursor = contentResolver.query(contentUri, ApkTable.Cols.ALL, null, null, null);
|
||||
queryCursor.moveToFirst();
|
||||
return new Apk(queryCursor);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user