Add ktlint and run it in CI

Fixes formatting issues it found.

Also remove version variables from gradle scripts as they are not wanted by the project.
merge-requests/1083/head
Torsten Grote 1 year ago
parent 82b131ff71
commit decc2cc6e3
No known key found for this signature in database
GPG Key ID: 3E5F77D92CF891FF

@ -0,0 +1,2 @@
[*.{kt, kts}]
max_line_length = 100

@ -34,6 +34,7 @@ stages:
- app/build/reports
- app/build/outputs/*ml
- app/build/outputs/apk
- build/reports
expire_in: 1 week
when: on_failure
after_script:
@ -49,10 +50,11 @@ test_lint_pmd_checkstyle:
- ./gradlew assemble
# always report on lint errors to the build log
- sed -i -e 's,textReport .*,textReport true,' app/build.gradle
- ./gradlew testFullDebugUnitTest || set_error
- ./gradlew testDebugUnitTest testFullDebugUnitTest || set_error
- ./gradlew lint || set_error
- ./gradlew pmd || set_error
- ./gradlew checkstyle || set_error
- ./gradlew ktlintCheck || set_error
- ./tools/check-format-strings.py || set_error
- ./tools/check-fastlane-whitespace.py || set_error
- ./tools/remove-unused-and-blank-translations.py || set_error

@ -177,8 +177,8 @@ dependencies {
implementation 'com.fasterxml.jackson.core:jackson-annotations:2.11.1'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.11.1'
implementation "com.github.bumptech.glide:glide:$glide_version"
annotationProcessor "com.github.bumptech.glide:compiler:$glide_version"
implementation "com.github.bumptech.glide:glide:4.12.0"
annotationProcessor "com.github.bumptech.glide:compiler:4.12.0"
implementation 'org.bouncycastle:bcprov-jdk15on:1.65'
fullImplementation 'org.bouncycastle:bcpkix-jdk15on:1.65'

@ -26,7 +26,7 @@ import org.fdroid.fdroid.data.Repo;
import org.fdroid.fdroid.data.RepoProvider;
import org.fdroid.fdroid.data.Schema;
import org.fdroid.fdroid.nearby.peers.Peer;
import org.fdroid.download.Downloader;
import org.fdroid.fdroid.net.DownloaderService;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
@ -392,9 +392,9 @@ public class SwapService extends Service {
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.onErrorComplete(e -> {
Intent intent = new Intent(Downloader.ACTION_INTERRUPTED);
Intent intent = new Intent(DownloaderService.ACTION_INTERRUPTED);
intent.setData(Uri.parse(repo.address));
intent.putExtra(Downloader.EXTRA_ERROR_MESSAGE, e.getLocalizedMessage());
intent.putExtra(DownloaderService.EXTRA_ERROR_MESSAGE, e.getLocalizedMessage());
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
return true;
})

@ -153,15 +153,15 @@ public class SwapSuccessView extends SwapView implements LoaderManager.LoaderCal
@Override
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()) {
case Downloader.ACTION_STARTED:
case DownloaderService.ACTION_STARTED:
resetView();
break;
case Downloader.ACTION_PROGRESS:
case DownloaderService.ACTION_PROGRESS:
if (progressView.getVisibility() != View.VISIBLE) {
showProgress();
}
long read = intent.getLongExtra(Downloader.EXTRA_BYTES_READ, 0);
long total = intent.getLongExtra(Downloader.EXTRA_TOTAL_BYTES, 0);
long read = intent.getLongExtra(DownloaderService.EXTRA_BYTES_READ, 0);
long total = intent.getLongExtra(DownloaderService.EXTRA_TOTAL_BYTES, 0);
if (total > 0) {
progressView.setIndeterminate(false);
progressView.setMax(100);
@ -170,17 +170,17 @@ public class SwapSuccessView extends SwapView implements LoaderManager.LoaderCal
progressView.setIndeterminate(true);
}
break;
case Downloader.ACTION_COMPLETE:
case DownloaderService.ACTION_COMPLETE:
localBroadcastManager.unregisterReceiver(this);
resetView();
statusInstalled.setText(R.string.installing);
statusInstalled.setVisibility(View.VISIBLE);
btnInstall.setVisibility(View.GONE);
break;
case Downloader.ACTION_INTERRUPTED:
case DownloaderService.ACTION_INTERRUPTED:
localBroadcastManager.unregisterReceiver(this);
if (intent.hasExtra(Downloader.EXTRA_ERROR_MESSAGE)) {
String msg = intent.getStringExtra(Downloader.EXTRA_ERROR_MESSAGE)
if (intent.hasExtra(DownloaderService.EXTRA_ERROR_MESSAGE)) {
String msg = intent.getStringExtra(DownloaderService.EXTRA_ERROR_MESSAGE)
+ " " + intent.getDataString();
Toast.makeText(context, R.string.download_error, Toast.LENGTH_SHORT).show();
Toast.makeText(context, msg, Toast.LENGTH_LONG).show();

@ -54,6 +54,7 @@ import org.fdroid.fdroid.data.RepoProvider;
import org.fdroid.fdroid.nearby.peers.BluetoothPeer;
import org.fdroid.fdroid.nearby.peers.Peer;
import org.fdroid.fdroid.net.BluetoothDownloader;
import org.fdroid.fdroid.net.DownloaderService;
import org.fdroid.fdroid.qr.CameraCharacteristicsChecker;
import org.fdroid.fdroid.views.main.MainActivity;
@ -273,7 +274,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
localBroadcastManager = LocalBroadcastManager.getInstance(this);
localBroadcastManager.registerReceiver(downloaderInterruptedReceiver,
new IntentFilter(Downloader.ACTION_INTERRUPTED));
new IntentFilter(DownloaderService.ACTION_INTERRUPTED));
wifiManager = ContextCompat.getSystemService(getApplicationContext(), WifiManager.class);
wifiApControl = WifiApControl.getInstance(this);
@ -1505,7 +1506,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
public void onReceive(Context context, Intent intent) {
Repo repo = RepoProvider.Helper.findByUrl(context, intent.getData(), null);
if (repo != null && repo.isSwap) {
setUpConnectingProgressText(intent.getStringExtra(Downloader.EXTRA_ERROR_MESSAGE));
setUpConnectingProgressText(intent.getStringExtra(DownloaderService.EXTRA_ERROR_MESSAGE));
}
}
};

@ -10,13 +10,13 @@ import android.content.pm.PackageManager;
import android.os.Parcel;
import android.os.Parcelable;
import org.fdroid.download.Downloader;
import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.data.App;
import org.fdroid.fdroid.data.AppProvider;
import org.fdroid.fdroid.data.Repo;
import org.fdroid.fdroid.installer.ErrorDialogActivity;
import org.fdroid.fdroid.installer.InstallManagerService;
import org.fdroid.fdroid.net.DownloaderService;
import org.fdroid.fdroid.views.AppDetailsActivity;
import java.util.ArrayList;
@ -292,7 +292,7 @@ public final class AppUpdateStatusManager {
private void notifyAdd(AppUpdateStatus entry) {
if (!isBatchUpdating) {
Intent broadcastIntent = new Intent(BROADCAST_APPSTATUS_ADDED);
broadcastIntent.putExtra(Downloader.EXTRA_CANONICAL_URL, entry.getCanonicalUrl());
broadcastIntent.putExtra(DownloaderService.EXTRA_CANONICAL_URL, entry.getCanonicalUrl());
broadcastIntent.putExtra(EXTRA_STATUS, entry.copy());
localBroadcastManager.sendBroadcast(broadcastIntent);
}
@ -301,7 +301,7 @@ public final class AppUpdateStatusManager {
private void notifyChange(AppUpdateStatus entry, boolean isStatusUpdate) {
if (!isBatchUpdating) {
Intent broadcastIntent = new Intent(BROADCAST_APPSTATUS_CHANGED);
broadcastIntent.putExtra(Downloader.EXTRA_CANONICAL_URL, entry.getCanonicalUrl());
broadcastIntent.putExtra(DownloaderService.EXTRA_CANONICAL_URL, entry.getCanonicalUrl());
broadcastIntent.putExtra(EXTRA_STATUS, entry.copy());
broadcastIntent.putExtra(EXTRA_IS_STATUS_UPDATE, isStatusUpdate);
localBroadcastManager.sendBroadcast(broadcastIntent);
@ -311,7 +311,7 @@ public final class AppUpdateStatusManager {
private void notifyRemove(AppUpdateStatus entry) {
if (!isBatchUpdating) {
Intent broadcastIntent = new Intent(BROADCAST_APPSTATUS_REMOVED);
broadcastIntent.putExtra(Downloader.EXTRA_CANONICAL_URL, entry.getCanonicalUrl());
broadcastIntent.putExtra(DownloaderService.EXTRA_CANONICAL_URL, entry.getCanonicalUrl());
broadcastIntent.putExtra(EXTRA_STATUS, entry.copy());
localBroadcastManager.sendBroadcast(broadcastIntent);
}

@ -4,7 +4,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import org.fdroid.download.Downloader;
import org.fdroid.fdroid.net.DownloaderService;
/**
* For security purposes we need to ensure that all Intent objects we give to a PendingIntent are
@ -16,7 +16,7 @@ public class NotificationBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
AppUpdateStatusManager manager = AppUpdateStatusManager.getInstance(context);
String canonicalUrl = intent.getStringExtra(Downloader.EXTRA_CANONICAL_URL);
String canonicalUrl = intent.getStringExtra(DownloaderService.EXTRA_CANONICAL_URL);
switch (intent.getAction()) {
case NotificationHelper.BROADCAST_NOTIFICATIONS_ALL_UPDATES_CLEARED:
manager.clearAllUpdates();

@ -30,8 +30,8 @@ import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
import org.fdroid.download.Downloader;
import org.fdroid.fdroid.data.App;
import org.fdroid.fdroid.net.DownloaderService;
import org.fdroid.fdroid.views.AppDetailsActivity;
import org.fdroid.fdroid.views.main.MainActivity;
@ -114,14 +114,14 @@ public class NotificationHelper {
case AppUpdateStatusManager.BROADCAST_APPSTATUS_ADDED:
updateStatusLists();
createSummaryNotifications();
url = intent.getStringExtra(Downloader.EXTRA_CANONICAL_URL);
url = intent.getStringExtra(DownloaderService.EXTRA_CANONICAL_URL);
entry = appUpdateStatusManager.get(url);
if (entry != null) {
createNotification(entry);
}
break;
case AppUpdateStatusManager.BROADCAST_APPSTATUS_CHANGED:
url = intent.getStringExtra(Downloader.EXTRA_CANONICAL_URL);
url = intent.getStringExtra(DownloaderService.EXTRA_CANONICAL_URL);
entry = appUpdateStatusManager.get(url);
updateStatusLists();
if (entry != null) {
@ -132,7 +132,7 @@ public class NotificationHelper {
}
break;
case AppUpdateStatusManager.BROADCAST_APPSTATUS_REMOVED:
url = intent.getStringExtra(Downloader.EXTRA_CANONICAL_URL);
url = intent.getStringExtra(DownloaderService.EXTRA_CANONICAL_URL);
notificationManager.cancel(url, NOTIFY_ID_INSTALLED);
notificationManager.cancel(url, NOTIFY_ID_UPDATES);
updateStatusLists();
@ -365,7 +365,7 @@ public class NotificationHelper {
}
Intent intentDeleted = new Intent(BROADCAST_NOTIFICATIONS_UPDATE_CLEARED);
intentDeleted.putExtra(Downloader.EXTRA_CANONICAL_URL, entry.getCanonicalUrl());
intentDeleted.putExtra(DownloaderService.EXTRA_CANONICAL_URL, entry.getCanonicalUrl());
intentDeleted.setClass(context, NotificationBroadcastReceiver.class);
PendingIntent piDeleted = PendingIntent.getBroadcast(context, 0, intentDeleted, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setDeleteIntent(piDeleted);
@ -453,7 +453,7 @@ public class NotificationHelper {
}
Intent intentDeleted = new Intent(BROADCAST_NOTIFICATIONS_INSTALLED_CLEARED);
intentDeleted.putExtra(Downloader.EXTRA_CANONICAL_URL, entry.getCanonicalUrl());
intentDeleted.putExtra(DownloaderService.EXTRA_CANONICAL_URL, entry.getCanonicalUrl());
intentDeleted.setClass(context, NotificationBroadcastReceiver.class);
PendingIntent piDeleted = PendingIntent.getBroadcast(context, 0, intentDeleted, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setDeleteIntent(piDeleted);

@ -28,7 +28,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import org.apache.commons.io.filefilter.RegexFileFilter;
import org.fdroid.download.DownloadRequest;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils;

@ -25,8 +25,8 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import org.fdroid.download.Downloader;
import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.net.DownloaderService;
import androidx.annotation.NonNull;
@ -50,7 +50,7 @@ public class DefaultInstaller extends Installer {
Intent installIntent = new Intent(context, DefaultInstallerActivity.class);
installIntent.setAction(DefaultInstallerActivity.ACTION_INSTALL_PACKAGE);
installIntent.putExtra(Downloader.EXTRA_CANONICAL_URL, canonicalUri.toString());
installIntent.putExtra(DownloaderService.EXTRA_CANONICAL_URL, canonicalUri.toString());
installIntent.putExtra(Installer.EXTRA_APK, apk);
installIntent.setData(localApkUri);

@ -30,9 +30,9 @@ import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import org.fdroid.download.Downloader;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.net.DownloaderService;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentActivity;
@ -69,7 +69,7 @@ public class DefaultInstallerActivity extends FragmentActivity {
installer = new DefaultInstaller(this, apk);
if (ACTION_INSTALL_PACKAGE.equals(action)) {
Uri localApkUri = intent.getData();
canonicalUri = Uri.parse(intent.getStringExtra(Downloader.EXTRA_CANONICAL_URL));
canonicalUri = Uri.parse(intent.getStringExtra(DownloaderService.EXTRA_CANONICAL_URL));
installPackage(localApkUri);
} else if (ACTION_UNINSTALL_PACKAGE.equals(action)) {
uninstallPackage(apk.packageName);

@ -24,8 +24,8 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import org.fdroid.download.Downloader;
import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.net.DownloaderService;
import androidx.annotation.NonNull;
@ -54,7 +54,7 @@ public class FileInstaller extends Installer {
protected void installPackageInternal(Uri localApkUri, Uri canonicalUri) {
Intent installIntent = new Intent(context, FileInstallerActivity.class);
installIntent.setAction(FileInstallerActivity.ACTION_INSTALL_FILE);
installIntent.putExtra(Downloader.EXTRA_CANONICAL_URL, canonicalUri.toString());
installIntent.putExtra(DownloaderService.EXTRA_CANONICAL_URL, canonicalUri.toString());
installIntent.putExtra(Installer.EXTRA_APK, apk);
installIntent.setData(localApkUri);

@ -10,11 +10,11 @@ import android.view.ContextThemeWrapper;
import android.widget.Toast;
import org.apache.commons.io.FileUtils;
import org.fdroid.download.Downloader;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.net.DownloaderService;
import java.io.File;
import java.io.IOException;
@ -59,7 +59,7 @@ public class FileInstallerActivity extends FragmentActivity {
apk = intent.getParcelableExtra(Installer.EXTRA_APK);
installer = new FileInstaller(this, apk);
if (ACTION_INSTALL_FILE.equals(action)) {
canonicalUri = Uri.parse(intent.getStringExtra(Downloader.EXTRA_CANONICAL_URL));
canonicalUri = Uri.parse(intent.getStringExtra(DownloaderService.EXTRA_CANONICAL_URL));
if (hasStoragePermission()) {
installPackage(localApkUri, canonicalUri, apk);
} else {

@ -217,8 +217,8 @@ public class InstallManagerService extends Service {
DownloaderService.queue(this, apk.repoId, canonicalUrl);
} else if (ApkCache.apkIsCached(apkFilePath, apk)) {
Utils.debugLog(TAG, "skip download, we have it, straight to install " + canonicalUrl + " " + apkFilePath);
sendBroadcast(intent.getData(), Downloader.ACTION_STARTED, apkFilePath);
sendBroadcast(intent.getData(), Downloader.ACTION_COMPLETE, apkFilePath);
sendBroadcast(intent.getData(), DownloaderService.ACTION_STARTED, apkFilePath);
sendBroadcast(intent.getData(), DownloaderService.ACTION_COMPLETE, apkFilePath);
} else {
Utils.debugLog(TAG, "delete and download again " + canonicalUrl + " " + apkFilePath);
apkFilePath.delete();
@ -231,7 +231,7 @@ public class InstallManagerService extends Service {
private void sendBroadcast(Uri uri, String action, File file) {
Intent intent = new Intent(action);
intent.setData(uri);
intent.putExtra(Downloader.EXTRA_DOWNLOAD_PATH, file.getAbsolutePath());
intent.putExtra(DownloaderService.EXTRA_DOWNLOAD_PATH, file.getAbsolutePath());
localBroadcastManager.sendBroadcast(intent);
}
@ -263,16 +263,16 @@ public class InstallManagerService extends Service {
return;
}
String action = intent.getAction();
if (Downloader.ACTION_STARTED.equals(action)) {
if (DownloaderService.ACTION_STARTED.equals(action)) {
Utils.debugLog(TAG, action + " " + intent);
} else if (Downloader.ACTION_PROGRESS.equals(action)) {
} else if (DownloaderService.ACTION_PROGRESS.equals(action)) {
long bytesRead = intent.getLongExtra(Downloader.EXTRA_BYTES_READ, 0);
long totalBytes = intent.getLongExtra(Downloader.EXTRA_TOTAL_BYTES, 0);
long bytesRead = intent.getLongExtra(DownloaderService.EXTRA_BYTES_READ, 0);
long totalBytes = intent.getLongExtra(DownloaderService.EXTRA_TOTAL_BYTES, 0);
appUpdateStatusManager.updateApkProgress(canonicalUrl, totalBytes, bytesRead);
} else if (Downloader.ACTION_COMPLETE.equals(action)) {
} else if (DownloaderService.ACTION_COMPLETE.equals(action)) {
localBroadcastManager.unregisterReceiver(this);
File localFile = new File(intent.getStringExtra(Downloader.EXTRA_DOWNLOAD_PATH));
File localFile = new File(intent.getStringExtra(DownloaderService.EXTRA_DOWNLOAD_PATH));
Uri localApkUri = Uri.fromFile(localFile);
Utils.debugLog(TAG, "OBB download completed " + intent.getDataString()
+ " to " + localApkUri);
@ -298,9 +298,9 @@ public class InstallManagerService extends Service {
} finally {
FileUtils.deleteQuietly(localFile);
}
} else if (Downloader.ACTION_INTERRUPTED.equals(action)) {
} else if (DownloaderService.ACTION_INTERRUPTED.equals(action)) {
localBroadcastManager.unregisterReceiver(this);
} else if (Downloader.ACTION_CONNECTION_FAILED.equals(action)) {
} else if (DownloaderService.ACTION_CONNECTION_FAILED.equals(action)) {
localBroadcastManager.unregisterReceiver(this);
} else {
throw new RuntimeException("intent action not handled!");
@ -329,7 +329,7 @@ public class InstallManagerService extends Service {
String canonicalUrl = intent.getDataString();
switch (intent.getAction()) {
case Downloader.ACTION_STARTED:
case DownloaderService.ACTION_STARTED:
// App should currently be in the "PendingDownload" state, so this changes it to "Downloading".
Intent intentObject = new Intent(context, InstallManagerService.class);
intentObject.setAction(ACTION_CANCEL);
@ -338,17 +338,17 @@ public class InstallManagerService extends Service {
appUpdateStatusManager.updateApk(canonicalUrl,
AppUpdateStatusManager.Status.Downloading, action);
break;
case Downloader.ACTION_PROGRESS:
long bytesRead = intent.getLongExtra(Downloader.EXTRA_BYTES_READ, 0);
long totalBytes = intent.getLongExtra(Downloader.EXTRA_TOTAL_BYTES, 0);
case DownloaderService.ACTION_PROGRESS:
long bytesRead = intent.getLongExtra(DownloaderService.EXTRA_BYTES_READ, 0);
long totalBytes = intent.getLongExtra(DownloaderService.EXTRA_TOTAL_BYTES, 0);
appUpdateStatusManager.updateApkProgress(canonicalUrl, totalBytes, bytesRead);
break;
case Downloader.ACTION_COMPLETE:
File localFile = new File(intent.getStringExtra(Downloader.EXTRA_DOWNLOAD_PATH));
case DownloaderService.ACTION_COMPLETE:
File localFile = new File(intent.getStringExtra(DownloaderService.EXTRA_DOWNLOAD_PATH));
Uri localApkUri = Uri.fromFile(localFile);
Utils.debugLog(TAG, "download completed of "
+ intent.getStringExtra(Downloader.EXTRA_MIRROR_URL) + " to " + localApkUri);
+ intent.getStringExtra(DownloaderService.EXTRA_MIRROR_URL) + " to " + localApkUri);
appUpdateStatusManager.updateApk(canonicalUrl,
AppUpdateStatusManager.Status.ReadyToInstall, null);
@ -360,10 +360,10 @@ public class InstallManagerService extends Service {
InstallerService.install(context, localApkUri, canonicalUri, apk);
}
break;
case Downloader.ACTION_INTERRUPTED:
case Downloader.ACTION_CONNECTION_FAILED:
case DownloaderService.ACTION_INTERRUPTED:
case DownloaderService.ACTION_CONNECTION_FAILED:
appUpdateStatusManager.setDownloadError(canonicalUrl,
intent.getStringExtra(Downloader.EXTRA_ERROR_MESSAGE));
intent.getStringExtra(DownloaderService.EXTRA_ERROR_MESSAGE));
localBroadcastManager.unregisterReceiver(this);
break;
default:

@ -27,10 +27,10 @@ import android.os.Build;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.WildcardFileFilter;
import org.fdroid.download.Downloader;
import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.data.App;
import org.fdroid.fdroid.net.DownloaderService;
import org.fdroid.fdroid.views.AppDetailsActivity;
import java.io.File;
@ -77,7 +77,7 @@ public class InstallerService extends JobIntentService {
if (ACTION_INSTALL.equals(intent.getAction())) {
Uri uri = intent.getData();
Uri canonicalUri = Uri.parse(intent.getStringExtra(Downloader.EXTRA_CANONICAL_URL));
Uri canonicalUri = Uri.parse(intent.getStringExtra(DownloaderService.EXTRA_CANONICAL_URL));
installer.installPackage(uri, canonicalUri);
} else if (ACTION_UNINSTALL.equals(intent.getAction())) {
installer.uninstallPackage();
@ -127,7 +127,7 @@ public class InstallerService extends JobIntentService {
Intent intent = new Intent(context, InstallerService.class);
intent.setAction(ACTION_INSTALL);
intent.setData(localApkUri);
intent.putExtra(Downloader.EXTRA_CANONICAL_URL, canonicalUri.toString());
intent.putExtra(DownloaderService.EXTRA_CANONICAL_URL, canonicalUri.toString());
intent.putExtra(Installer.EXTRA_APK, apk);
enqueueWork(context, intent);
}

@ -12,8 +12,8 @@ import android.util.Log;
import android.webkit.MimeTypeMap;
import org.apache.commons.io.FileUtils;
import org.fdroid.download.Downloader;
import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.net.DownloaderService;
import java.io.File;
import java.io.IOException;
@ -41,7 +41,7 @@ public class ObfInstallerService extends IntentService {
public static void install(Context context, Uri canonicalUri, Apk apk, File path) {
Intent intent = new Intent(context, ObfInstallerService.class);
intent.setAction(ACTION_INSTALL_OBF);
intent.putExtra(Downloader.EXTRA_CANONICAL_URL, canonicalUri.toString());
intent.putExtra(DownloaderService.EXTRA_CANONICAL_URL, canonicalUri.toString());
intent.putExtra(Installer.EXTRA_APK, apk);
intent.putExtra(EXTRA_OBF_PATH, path.getAbsolutePath());
context.startService(intent);
@ -53,7 +53,7 @@ public class ObfInstallerService extends IntentService {
Log.e(TAG, "received invalid intent: " + intent);
return;
}
Uri canonicalUri = Uri.parse(intent.getStringExtra(Downloader.EXTRA_CANONICAL_URL));
Uri canonicalUri = Uri.parse(intent.getStringExtra(DownloaderService.EXTRA_CANONICAL_URL));
final Apk apk = intent.getParcelableExtra(Installer.EXTRA_APK);
final String path = intent.getStringExtra(EXTRA_OBF_PATH);
final String extension = MimeTypeMap.getFileExtensionFromUrl(path);

@ -99,6 +99,29 @@ public class DownloaderService extends Service {
private static final String ACTION_QUEUE = "org.fdroid.fdroid.net.DownloaderService.action.QUEUE";
private static final String ACTION_CANCEL = "org.fdroid.fdroid.net.DownloaderService.action.CANCEL";
public static final String ACTION_STARTED = "org.fdroid.fdroid.net.Downloader.action.STARTED";
public static final String ACTION_PROGRESS = "org.fdroid.fdroid.net.Downloader.action.PROGRESS";
public static final String ACTION_INTERRUPTED = "org.fdroid.fdroid.net.Downloader.action.INTERRUPTED";
public static final String ACTION_CONNECTION_FAILED = "org.fdroid.fdroid.net.Downloader.action.CONNECTION_FAILED";
public static final String ACTION_COMPLETE = "org.fdroid.fdroid.net.Downloader.action.COMPLETE";
public static final String EXTRA_DOWNLOAD_PATH = "org.fdroid.fdroid.net.Downloader.extra.DOWNLOAD_PATH";
public static final String EXTRA_BYTES_READ = "org.fdroid.fdroid.net.Downloader.extra.BYTES_READ";
public static final String EXTRA_TOTAL_BYTES = "org.fdroid.fdroid.net.Downloader.extra.TOTAL_BYTES";
public static final String EXTRA_ERROR_MESSAGE = "org.fdroid.fdroid.net.Downloader.extra.ERROR_MESSAGE";
public static final String EXTRA_REPO_ID = "org.fdroid.fdroid.net.Downloader.extra.REPO_ID";
public static final String EXTRA_MIRROR_URL = "org.fdroid.fdroid.net.Downloader.extra.MIRROR_URL";
/**
* Unique ID used to represent this specific package's install process,
* including {@link android.app.Notification}s, also known as {@code canonicalUrl}.
* Careful about types, this should always be a {@link String}, so it can
* be handled on the receiving side by {@link android.content.Intent#getStringArrayExtra(String)}.
*
* @see org.fdroid.fdroid.installer.InstallManagerService
* @see android.content.Intent#EXTRA_ORIGINATING_URI
*/
public static final String EXTRA_CANONICAL_URL = "org.fdroid.fdroid.net.Downloader.extra.CANONICAL_URL";
private volatile Looper serviceLooper;
private static volatile ServiceHandler serviceHandler;
private static volatile Downloader downloader;
@ -149,7 +172,7 @@ public class DownloaderService extends Service {
Utils.debugLog(TAG, "Received Intent with no URI: " + intent);
return START_NOT_STICKY;
}
String canonicalUrl = intent.getStringExtra(Downloader.EXTRA_CANONICAL_URL);
String canonicalUrl = intent.getStringExtra(DownloaderService.EXTRA_CANONICAL_URL);
if (canonicalUrl == null) {
Utils.debugLog(TAG, "Received Intent with no EXTRA_CANONICAL_URL: " + intent);
return START_NOT_STICKY;
@ -218,10 +241,10 @@ public class DownloaderService extends Service {
*/
private void handleIntent(Intent intent) {
final Uri uri = intent.getData();
final long repoId = intent.getLongExtra(Downloader.EXTRA_REPO_ID, 0);
final Uri canonicalUrl = Uri.parse(intent.getStringExtra(Downloader.EXTRA_CANONICAL_URL));
final long repoId = intent.getLongExtra(DownloaderService.EXTRA_REPO_ID, 0);
final Uri canonicalUrl = Uri.parse(intent.getStringExtra(DownloaderService.EXTRA_CANONICAL_URL));
final SanitizedFile localFile = ApkCache.getApkDownloadPath(this, canonicalUrl);
sendBroadcast(uri, Downloader.ACTION_STARTED, localFile, repoId, canonicalUrl);
sendBroadcast(uri, DownloaderService.ACTION_STARTED, localFile, repoId, canonicalUrl);
try {
activeCanonicalUrl = canonicalUrl.toString();
@ -230,26 +253,26 @@ public class DownloaderService extends Service {
downloader.setListener(new ProgressListener() {
@Override
public void onProgress(long bytesRead, long totalBytes) {
Intent intent = new Intent(Downloader.ACTION_PROGRESS);
Intent intent = new Intent(DownloaderService.ACTION_PROGRESS);
intent.setData(canonicalUrl);
intent.putExtra(Downloader.EXTRA_BYTES_READ, bytesRead);
intent.putExtra(Downloader.EXTRA_TOTAL_BYTES, totalBytes);
intent.putExtra(DownloaderService.EXTRA_BYTES_READ, bytesRead);
intent.putExtra(DownloaderService.EXTRA_TOTAL_BYTES, totalBytes);
localBroadcastManager.sendBroadcast(intent);
}
});
downloader.download();
sendBroadcast(uri, Downloader.ACTION_COMPLETE, localFile, repoId, canonicalUrl);
sendBroadcast(uri, DownloaderService.ACTION_COMPLETE, localFile, repoId, canonicalUrl);
} catch (InterruptedException e) {
sendBroadcast(uri, Downloader.ACTION_INTERRUPTED, localFile, repoId, canonicalUrl);
sendBroadcast(uri, DownloaderService.ACTION_INTERRUPTED, localFile, repoId, canonicalUrl);
} catch (ConnectException | HttpRetryException | NoRouteToHostException | SocketTimeoutException
| SSLHandshakeException | SSLKeyException | SSLPeerUnverifiedException | SSLProtocolException
| ProtocolException | UnknownHostException e) {
// if the above list of exceptions changes, also change it in IndexV1Updater.update()
Log.e(TAG, "CONNECTION_FAILED: " + e.getLocalizedMessage());
sendBroadcast(uri, Downloader.ACTION_CONNECTION_FAILED, localFile, repoId, canonicalUrl);
sendBroadcast(uri, DownloaderService.ACTION_CONNECTION_FAILED, localFile, repoId, canonicalUrl);
} catch (IOException e) {
e.printStackTrace();
sendBroadcast(uri, Downloader.ACTION_INTERRUPTED, localFile,
sendBroadcast(uri, DownloaderService.ACTION_INTERRUPTED, localFile,
e.getLocalizedMessage(), repoId, canonicalUrl);
} finally {
if (downloader != null) {
@ -261,7 +284,7 @@ public class DownloaderService extends Service {
}
private void sendCancelledBroadcast(Uri uri, String canonicalUrl) {
sendBroadcast(uri, Downloader.ACTION_INTERRUPTED, null, 0, Uri.parse(canonicalUrl));
sendBroadcast(uri, DownloaderService.ACTION_INTERRUPTED, null, 0, Uri.parse(canonicalUrl));
}
private void sendBroadcast(Uri uri, String action, File file, long repoId, Uri canonicalUrl) {
@ -275,13 +298,13 @@ public class DownloaderService extends Service {
intent.setData(canonicalUrl);
}
if (file != null) {
intent.putExtra(Downloader.EXTRA_DOWNLOAD_PATH, file.getAbsolutePath());
intent.putExtra(DownloaderService.EXTRA_DOWNLOAD_PATH, file.getAbsolutePath());
}
if (!TextUtils.isEmpty(errorMessage)) {
intent.putExtra(Downloader.EXTRA_ERROR_MESSAGE, errorMessage);
intent.putExtra(DownloaderService.EXTRA_ERROR_MESSAGE, errorMessage);
}
intent.putExtra(Downloader.EXTRA_REPO_ID, repoId);
intent.putExtra(Downloader.EXTRA_MIRROR_URL, uri.toString());
intent.putExtra(DownloaderService.EXTRA_REPO_ID, repoId);
intent.putExtra(DownloaderService.EXTRA_MIRROR_URL, uri.toString());
localBroadcastManager.sendBroadcast(intent);
}
@ -303,8 +326,8 @@ public class DownloaderService extends Service {
Intent intent = new Intent(context, DownloaderService.class);
intent.setAction(ACTION_QUEUE);
intent.setData(Uri.parse(canonicalUrl));
intent.putExtra(Downloader.EXTRA_REPO_ID, repoId);
intent.putExtra(Downloader.EXTRA_CANONICAL_URL, canonicalUrl);
intent.putExtra(DownloaderService.EXTRA_REPO_ID, repoId);
intent.putExtra(DownloaderService.EXTRA_CANONICAL_URL, canonicalUrl);
context.startService(intent);
}
@ -325,7 +348,7 @@ public class DownloaderService extends Service {
Intent intent = new Intent(context, DownloaderService.class);
intent.setAction(ACTION_CANCEL);
intent.setData(Uri.parse(canonicalUrl));
intent.putExtra(Downloader.EXTRA_CANONICAL_URL, canonicalUrl);
intent.putExtra(DownloaderService.EXTRA_CANONICAL_URL, canonicalUrl);
context.startService(intent);
}
@ -359,11 +382,11 @@ public class DownloaderService extends Service {
public static IntentFilter getIntentFilter(String canonicalUrl) {
Uri uri = Uri.parse(canonicalUrl);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Downloader.ACTION_STARTED);
intentFilter.addAction(Downloader.ACTION_PROGRESS);
intentFilter.addAction(Downloader.ACTION_COMPLETE);
intentFilter.addAction(Downloader.ACTION_INTERRUPTED);
intentFilter.addAction(Downloader.ACTION_CONNECTION_FAILED);
intentFilter.addAction(DownloaderService.ACTION_STARTED);
intentFilter.addAction(DownloaderService.ACTION_PROGRESS);
intentFilter.addAction(DownloaderService.ACTION_COMPLETE);
intentFilter.addAction(DownloaderService.ACTION_INTERRUPTED);
intentFilter.addAction(DownloaderService.ACTION_CONNECTION_FAILED);
intentFilter.addDataScheme(uri.getScheme());
intentFilter.addDataAuthority(uri.getHost(), String.valueOf(uri.getPort()));
intentFilter.addDataPath(uri.getPath(), PatternMatcher.PATTERN_LITERAL);

@ -45,7 +45,6 @@ import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.badge.BadgeDrawable;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import org.fdroid.download.Downloader;
import org.fdroid.fdroid.AppUpdateStatusManager;
import org.fdroid.fdroid.AppUpdateStatusManager.AppUpdateStatus;
import org.fdroid.fdroid.FDroidApp;
@ -60,6 +59,7 @@ import org.fdroid.fdroid.nearby.SwapService;
import org.fdroid.fdroid.nearby.SwapWorkflowActivity;
import org.fdroid.fdroid.nearby.TreeUriScannerIntentService;
import org.fdroid.fdroid.nearby.WifiStateChangeService;
import org.fdroid.fdroid.net.DownloaderService;
import org.fdroid.fdroid.views.AppDetailsActivity;
import org.fdroid.fdroid.views.ManageReposActivity;
import org.fdroid.fdroid.views.apps.AppListActivity;
@ -431,7 +431,7 @@ public class MainActivity extends AppCompatActivity {
// Check if we have moved into the ReadyToInstall or Installed state.
AppUpdateStatus status = manager.get(
intent.getStringExtra(Downloader.EXTRA_CANONICAL_URL));
intent.getStringExtra(DownloaderService.EXTRA_CANONICAL_URL));
boolean isStatusChange = intent.getBooleanExtra(AppUpdateStatusManager.EXTRA_IS_STATUS_UPDATE, false);
if (isStatusChange
&& status != null

@ -1,15 +1,11 @@
buildscript {
ext {
kotlin_version = "1.6.10"
glide_version = "4.12.0"
}
repositories {
mavenCentral()
maven { url 'https://maven.google.com/' }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10"
}
}
allprojects {

@ -1,6 +1,7 @@
plugins {
id 'org.jetbrains.kotlin.multiplatform'
id 'com.android.library'
id "org.jlleitschuh.gradle.ktlint" version "10.1.0"
}
group = 'org.fdroid'
@ -28,8 +29,7 @@ kotlin {
all {
languageSettings {
optIn('kotlin.RequiresOptIn')
explicitApi()
explicitApi = 'strict'
explicitApi('strict')
}
}
commonMain {
@ -58,10 +58,10 @@ kotlin {
androidMain {
dependencies {
implementation "io.ktor:ktor-client-okhttp:$ktor_version"
implementation("com.github.bumptech.glide:glide:$glide_version") {
implementation("com.github.bumptech.glide:glide:4.12.0") {
transitive = false // we don't need all that it pulls in, just the basics
}
implementation "com.github.bumptech.glide:annotations:$glide_version"
implementation "com.github.bumptech.glide:annotations:4.12.0"
implementation 'ch.qos.logback:logback-classic:1.2.5'
}
}
@ -96,3 +96,5 @@ android {
disable "InvalidPackage" // FIXME remove when Ktor 2.0 has been released
}
}
apply from: "${rootProject.rootDir}/gradle/ktlint.gradle"

@ -15,29 +15,6 @@ public abstract class Downloader constructor(
public companion object {
private val log = KotlinLogging.logger {}
public const val ACTION_STARTED: String = "org.fdroid.fdroid.net.Downloader.action.STARTED"
public const val ACTION_PROGRESS: String = "org.fdroid.fdroid.net.Downloader.action.PROGRESS"
public const val ACTION_INTERRUPTED: String = "org.fdroid.fdroid.net.Downloader.action.INTERRUPTED"
public const val ACTION_CONNECTION_FAILED: String =
"org.fdroid.fdroid.net.Downloader.action.CONNECTION_FAILED"
public const val ACTION_COMPLETE: String = "org.fdroid.fdroid.net.Downloader.action.COMPLETE"
public const val EXTRA_DOWNLOAD_PATH: String = "org.fdroid.fdroid.net.Downloader.extra.DOWNLOAD_PATH"
public const val EXTRA_BYTES_READ: String = "org.fdroid.fdroid.net.Downloader.extra.BYTES_READ"
public const val EXTRA_TOTAL_BYTES: String = "org.fdroid.fdroid.net.Downloader.extra.TOTAL_BYTES"
public const val EXTRA_ERROR_MESSAGE: String = "org.fdroid.fdroid.net.Downloader.extra.ERROR_MESSAGE"
public const val EXTRA_REPO_ID: String = "org.fdroid.fdroid.net.Downloader.extra.REPO_ID"
public const val EXTRA_MIRROR_URL: String = "org.fdroid.fdroid.net.Downloader.extra.MIRROR_URL"
/**
* Unique ID used to represent this specific package's install process,
* including [android.app.Notification]s, also known as `canonicalUrl`.
* Careful about types, this should always be a [String], so it can
* be handled on the receiving side by [android.content.Intent.getStringArrayExtra].
*
* @see android.content.Intent.EXTRA_ORIGINATING_URI
*/
public const val EXTRA_CANONICAL_URL: String = "org.fdroid.fdroid.net.Downloader.extra.CANONICAL_URL"
}
/**

@ -140,10 +140,12 @@ public class HttpDownloader constructor(
var resumable = false
val fileLength = outputFile.length()
if (fileLength > fileSize) {
if (!outputFile.delete()) log.warn { "Warning: " + outputFile.absolutePath + " not deleted" }
if (!outputFile.delete()) log.warn {
"Warning: " + outputFile.absolutePath + " not deleted"
}
} else if (fileLength == fileSize && outputFile.isFile) {
log.debug { "Already have outputFile, not download. ${outputFile.absolutePath}" }
return // already have it!
return // already have it!
} else if (fileLength > 0) {
resumable = true
}
@ -153,7 +155,9 @@ public class HttpDownloader constructor(
downloadFromBytesReceiver(resumable)
} catch (e: NoResumeException) {
require(resumable) { "Got $e even though download was not resumable" }
if (!outputFile.delete()) log.warn { "Warning: " + outputFile.absolutePath + " not deleted" }
if (!outputFile.delete()) log.warn {
"Warning: " + outputFile.absolutePath + " not deleted"
}
downloadFromBytesReceiver(false)
}
}

@ -30,7 +30,9 @@ public class DownloadRequestLoader(
public class Factory(
private val httpManager: HttpManager,
) : ModelLoaderFactory<DownloadRequest, InputStream> {
override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader<DownloadRequest, InputStream> {
override fun build(
multiFactory: MultiModelLoaderFactory,
): ModelLoader<DownloadRequest, InputStream> {
return DownloadRequestLoader(httpManager)
}

@ -25,7 +25,8 @@ internal class HttpFetcher(
@Deprecated("Use DownloadRequests with other constructor instead")
constructor(
httpManager: HttpManager,
glideUrl: GlideUrl, proxy: ProxyConfig?,
glideUrl: GlideUrl,
proxy: ProxyConfig?,
) : this(httpManager, getDownloadRequest(glideUrl, proxy))
companion object {

@ -25,7 +25,12 @@ public class HttpGlideUrlLoader(
return true
}
override fun buildLoadData(glideUrl: GlideUrl, width: Int, height: Int, options: Options): LoadData<InputStream> {
override fun buildLoadData(
glideUrl: GlideUrl,
width: Int,
height: Int,
options: Options,
): LoadData<InputStream> {
log.warn { "Not using mirrors when loading $glideUrl" }
return LoadData(glideUrl, HttpFetcher(httpManager, glideUrl, proxyGetter()))
}
@ -34,7 +39,9 @@ public class HttpGlideUrlLoader(
private val httpManager: HttpManager,
private val proxyGetter: () -> ProxyConfig?,
) : ModelLoaderFactory<GlideUrl, InputStream> {
override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader<GlideUrl, InputStream> {
override fun build(
multiFactory: MultiModelLoaderFactory,
): ModelLoader<GlideUrl, InputStream> {
return HttpGlideUrlLoader(httpManager, proxyGetter)
}

@ -159,7 +159,8 @@ class HttpDownloaderTest {
val file = folder.newFile()
val httpManager = HttpManager(userAgent, null)
val torHost = "http://2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion" // tor-project.org
// tor-project.org
val torHost = "http://2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion"
val proxy = ProxyBuilder.socks("localhost", TOR_SOCKS_PORT)
val downloadRequest = DownloadRequest("index.html", listOf(Mirror(torHost)), proxy)
val httpDownloader = HttpDownloader(httpManager, downloadRequest, file)

@ -157,7 +157,7 @@ public open class HttpManager @JvmOverloads constructor(
// increase connect timeout if using Tor mirror
if (mirror.isOnion()) timeout { connectTimeoutMillis = 20_000 }
// add range header if set
if (skipFirstBytes != null) header(Range, "bytes=${skipFirstBytes}-")
if (skipFirstBytes != null) header(Range, "bytes=$skipFirstBytes-")
}
}
}
@ -178,7 +178,10 @@ public open class HttpManager @JvmOverloads constructor(
* Thus, this is intentionally visible internally only.
* Does not use [getChannel] so, it gets the [NoResumeException] as in the public API.
*/
internal suspend fun getBytes(request: DownloadRequest, skipFirstBytes: Long? = null): ByteArray {
internal suspend fun getBytes(
request: DownloadRequest,
skipFirstBytes: Long? = null,
): ByteArray {
val channel = ByteChannel()
get(request, skipFirstBytes) { bytes ->
channel.writeFully(bytes)
@ -198,7 +201,9 @@ public open class HttpManager @JvmOverloads constructor(
private fun resetProxyIfNeeded(proxyConfig: ProxyConfig?, mirror: Mirror? = null) {
// force no-proxy when trying to hit a local mirror
val newProxy = if (mirror.isLocal() && proxyConfig != null) {
if (currentProxy != null) log.info { "Forcing mirror to null, because mirror is local: $mirror" }
if (currentProxy != null) log.info {
"Forcing mirror to null, because mirror is local: $mirror"
}
null
} else proxyConfig
if (currentProxy != newProxy) {

@ -58,7 +58,7 @@ internal fun Url.isLocal(): Boolean {
return num in 16..31
}
return host.startsWith("169.254.") ||
host.startsWith("10.") ||
host.startsWith("192.168.") ||
host == "127.0.0.1"
host.startsWith("10.") ||
host.startsWith("192.168.") ||
host == "127.0.0.1"
}

@ -27,9 +27,10 @@ internal abstract class MirrorChooserImpl : MirrorChooser {
): T {
val mirrors = if (downloadRequest.proxy == null) {
// if we don't use a proxy, filter out onion mirrors (won't work without Orbot)
val orderedMirrors = orderMirrors(downloadRequest).filter { mirror -> !mirror.isOnion() }
val orderedMirrors =
orderMirrors(downloadRequest).filter { mirror -> !mirror.isOnion() }
// if we only have onion mirrors, take what we have and expect errors
if (orderedMirrors.isEmpty()) downloadRequest.mirrors else orderedMirrors
orderedMirrors.ifEmpty { downloadRequest.mirrors }
} else {
orderMirrors(downloadRequest)
}
@ -39,7 +40,10 @@ internal abstract class MirrorChooserImpl : MirrorChooser {
return request(mirror, url)
} catch (e: ResponseException) {
val wasLastMirror = index == downloadRequest.mirrors.size - 1
log.warn(e) { if (wasLastMirror) "Last mirror, rethrowing..." else "Trying other mirror now..." }
log.warn(e) {
if (wasLastMirror) "Last mirror, rethrowing..."
else "Trying other mirror now..."
}
if (wasLastMirror) throw e
}
}

@ -16,5 +16,5 @@ internal fun ProxyConfig?.isTor(): Boolean {
if (this == null || !hostIsIp(DEFAULT_PROXY_HOST)) return false
val address = resolveAddress()
return (type == HTTP && address.port == DEFAULT_PROXY_HTTP_PORT) ||
(type == SOCKS && address.port == DEFAULT_PROXY_SOCKS_PORT)
(type == SOCKS && address.port == DEFAULT_PROXY_SOCKS_PORT)
}

@ -2,9 +2,9 @@ package org.fdroid.download
import io.ktor.client.engine.ProxyBuilder
import io.ktor.http.Url
import io.ktor.utils.io.errors.IOException
import org.fdroid.getRandomString
import org.fdroid.runSuspend
import java.net.ConnectException
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
@ -28,7 +28,7 @@ class HttpManagerIntegrationTest {
val proxyRequest = downloadRequest.copy(proxy = ProxyBuilder.http(Url("http://127.0.0.1")))
val httpManager = HttpManager(userAgent, null)
val e = assertFailsWith<ConnectException> {
val e = assertFailsWith<IOException> {
httpManager.getBytes(proxyRequest)
}
assertEquals("Failed to connect to /127.0.0.1:80", e.message)

@ -60,7 +60,8 @@ class HttpManagerTest {
val version = getRandomString()
val queryString = "id=$id&client_version=$version"
val mockEngine = MockEngine { respondOk() }
val httpManager = HttpManager(userAgent, queryString, httpClientEngineFactory = get(mockEngine))
val httpManager =
HttpManager(userAgent, queryString, httpClientEngineFactory = get(mockEngine))
httpManager.head(downloadRequest)
httpManager.getBytes(downloadRequest)
@ -119,8 +120,11 @@ class HttpManagerTest {
var requestNum = 1
val mockEngine = MockEngine { request ->
assertNotNull(request.headers[Range])
val (fromStr, endStr) = request.headers[Range]!!.replace("bytes=", "").split('-')
val from = fromStr.toIntOrNull() ?: fail("No valid content range ${request.headers[Range]}")
val (fromStr, endStr) = request.headers[Range]!!
.replace("bytes=", "")
.split('-')
val from =
fromStr.toIntOrNull() ?: fail("No valid content range ${request.headers[Range]}")
assertEquals("", endStr)
assertEquals(skipBytes, from)
if (requestNum++ == 1) respond(content.copyOfRange(from, content.size), PartialContent)
@ -129,8 +133,10 @@ class HttpManagerTest {
val httpManager = HttpManager(userAgent, null, httpClientEngineFactory = get(mockEngine))
// first request gets only the skipped bytes
assertContentEquals(content.copyOfRange(skipBytes, content.size),
httpManager.getBytes(downloadRequest, skipBytes.toLong()))
assertContentEquals(
content.copyOfRange(skipBytes, content.size),
httpManager.getBytes(downloadRequest, skipBytes.toLong())
)
// second request fails, because it responds with OK and full content
assertFailsWith<NoResumeException> {
httpManager.getBytes(downloadRequest, skipBytes.toLong())
@ -238,7 +244,8 @@ class HttpManagerTest {
}
}
}
val httpManager = HttpManager(userAgent, null, proxyConfig, httpClientEngineFactory = factory)
val httpManager =
HttpManager(userAgent, null, proxyConfig, httpClientEngineFactory = factory)
assertEquals(proxyConfig, httpManager.currentProxy)
// does not need a new engine, because also does use a proxy (1)

@ -22,7 +22,11 @@ class MirrorTest {
@Test
fun testIsOnion() {
assertTrue(Mirror("http://ftpfaudev4triw2vxiwzf4334e3mynz7osqgtozhbc77fixncqzbyoyd.onion/fdroid/repo").isOnion())
assertTrue(
Mirror(
"http://ftpfaudev4triw2vxiwzf4334e3mynz7osqgtozhbc77fixncqzbyoyd.onion/fdroid/repo"
).isOnion()
)
assertFalse(Mirror("https://www.f-droid.org/fdroid/repo").isOnion())
assertFalse(Mirror("http://192.168.0.1/fdroid/repo").isOnion())
}

@ -0,0 +1,10 @@
ktlint {
version = "0.43.2"
android = true
enableExperimentalRules = false
verbose = true
disabledRules = [
"import-ordering",
"no-blank-line-before-rbrace",
]
}

Binary file not shown.

@ -7,6 +7,10 @@
<trust file=".*-javadoc[.]jar" regex="true"/>
<trust file=".*-sources[.]jar" regex="true"/>
</trusted-artifacts>
<ignored-keys>
<ignored-key id="3967d4eda591b991" reason="Key couldn't be downloaded from any key server"/>
<ignored-key id="02216ed811210daa" reason="Key couldn't be downloaded from any key server"/>
</ignored-keys>
<trusted-keys>
<trusted-key id="0394681addddb4f6388a64d295123567c1886c47" group="ch.acra" name="acra" version="4.9.1"/>
<trusted-key id="042b29e928995b9db963c636c7ca19b7b620d787" group="org.apache.maven" name="maven-ant-tasks" version="2.1.3"/>
@ -99,11 +103,16 @@
<trusted-key id="984460dfd8f76a226f7dede2e483332711b8c7d6" group="com.ashokvarma.android" name="bottom-navigation-bar" version="2.0.5"/>
<trusted-key id="998af0e2b935996f5cebd56b9b1fda9f3c062231" group="^org[.]apache($|([.].*))" regex="true"/>
<trusted-key id="9ffed7a118d45a44e4a1e47130e6f80434a72a7f" group="^org[.]apache[.]maven($|([.].*))" regex="true"/>
<trusted-key id="a2570288e10932263e8326cbaa49c633b4734832">
<trusting group="com.pinterest"/>
<trusting group="com.pinterest.ktlint"/>
</trusted-key>
<trusted-key id="a6d6c97108b8585f91b158748671a8df71296252">
<trusting group="com.squareup" name="javapoet" version="1.10.0"/>
<trusting group="^com[.]squareup($|([.].*))" regex="true"/>
</trusted-key>
<trusted-key id="a7892505cf1a58076453e52d7999befba1039e8b" group="net.bytebuddy"/>
<trusted-key id="adbc987d1a7b91db6b0aaa81995efbf4a3d20beb" group="^com[.]pinterest($|([.].*))" regex="true"/>
<trusted-key id="ae2b18e836c5f30687f37efdcc6346f2ce3872d9" group="com.google.protobuf" name="protobuf-java" version="2.6.1"/>
<trusted-key id="afcc4c7594d09e2182c60e0f7a01b0f236e5430f">
<trusting group="com.google.code.gson"/>
@ -861,6 +870,16 @@
<sha256 value="68b010ca532615ccfe212310e38cfd32f6ef93804d5a389be797dd67bef8afa4" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="ch.qos.logback" name="logback-classic" version="1.2.5">
<artifact name="logback-classic-1.2.5.jar">
<sha256 value="056b300701b7cb53e22315b29103d1cd6e7346b04b47655448675c1fa71916a5" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="ch.qos.logback" name="logback-core" version="1.2.5">
<artifact name="logback-core-1.2.5.jar">
<sha256 value="fc98d2d927bd2991d5f45d0ccd9039a08d162c6d0611e2f71172deae9dbe122c" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="classworlds" name="classworlds" version="1.1-alpha-2">
<artifact name="classworlds-1.1-alpha-2.jar">
<sha256 value="2bf4e59f3acd106fea6145a9a88fe8956509f8b9c0fdd11eb96fee757269e3f3" origin="Generated by Gradle because artifact wasn't signed"/>
@ -1477,6 +1496,12 @@
<sha256 value="ed971f009354e68c09414c964fbe1a2c85c2c8bbd460122b7497a7b8c5d4f388" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.github.shyiko.klob" name="klob" version="0.2.1">
<artifact name="klob-0.2.1.jar">
<pgp value="160a7a9cf46221a56b06ad64461a804f2609fd89"/>
<sha256 value="2f6174e3049008f263fd832813390df645ac5c7cfa79f170ace58690810476f2" origin=