Merge branch 'jmdns-fixes-and-tor-onion-support' into 'master'
Jmdns fixes and tor onion support There are three groups of work in this collection of commits: * improvements to the `WifiStateChangeService` and related activities like JmDNS to eliminate problems that happen when there are a lot of wifi change events. * add rework the `.net.Downloader` stuff to add Tor support and lay the groundwork for Bluetooth support * add support for repos on Tor Hidden Service .onion addresses
This commit is contained in:
commit
95180512c7
@ -4,7 +4,11 @@
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="extern/symlinks-for-ant-and-eclipse"/>
|
||||
<classpathentry kind="src" path="extern/symlinks-for-ant-and-eclipse">
|
||||
<attributes>
|
||||
<attribute name="ignore_optional_problems" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" path="gen"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/AndroidPinning"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/MemorizingActivity"/>
|
||||
|
@ -8,6 +8,8 @@
|
||||
|
||||
* find local repos on the same network using Bonjour/mDNS
|
||||
|
||||
* use FDroid repos on Tor Hidden Services (.onion addresses)
|
||||
|
||||
* directly send installed apps to other devices via Bluetooth and Android Beam
|
||||
(NFC+Bluetooth), also compatible with Samsung/HTC S-Beam
|
||||
|
||||
|
@ -41,11 +41,13 @@ import com.nostra13.universalimageloader.utils.StorageUtils;
|
||||
|
||||
import de.duenndns.ssl.MemorizingTrustManager;
|
||||
|
||||
import org.fdroid.fdroid.Preferences.ChangeListener;
|
||||
import org.fdroid.fdroid.compat.PRNGFixes;
|
||||
import org.fdroid.fdroid.data.AppProvider;
|
||||
import org.fdroid.fdroid.data.InstalledAppCacheUpdater;
|
||||
import org.fdroid.fdroid.data.Repo;
|
||||
import org.fdroid.fdroid.localrepo.LocalRepoService;
|
||||
import org.fdroid.fdroid.net.IconDownloader;
|
||||
import org.fdroid.fdroid.net.WifiStateChangeService;
|
||||
import org.thoughtcrime.ssl.pinning.PinningTrustManager;
|
||||
import org.thoughtcrime.ssl.pinning.SystemKeyStore;
|
||||
@ -151,7 +153,8 @@ public class FDroidApp extends Application {
|
||||
bluetoothAdapter = getBluetoothAdapter();
|
||||
|
||||
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
|
||||
.discCache(new LimitedAgeDiscCache(
|
||||
.imageDownloader(new IconDownloader(getApplicationContext()))
|
||||
.diskCache(new LimitedAgeDiscCache(
|
||||
new File(StorageUtils.getCacheDirectory(getApplicationContext(), true),
|
||||
"icons"),
|
||||
null,
|
||||
@ -213,6 +216,13 @@ public class FDroidApp extends Application {
|
||||
if (wifiState == WifiManager.WIFI_STATE_ENABLING
|
||||
|| wifiState == WifiManager.WIFI_STATE_ENABLED)
|
||||
startService(new Intent(this, WifiStateChangeService.class));
|
||||
// if the HTTPS pref changes, then update all affected things
|
||||
Preferences.get().registerLocalRepoHttpsListeners(new ChangeListener() {
|
||||
@Override
|
||||
public void onPreferenceChange() {
|
||||
startService(new Intent(FDroidApp.this, WifiStateChangeService.class));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@TargetApi(18)
|
||||
@ -282,17 +292,21 @@ public class FDroidApp extends Application {
|
||||
public static void startLocalRepoService(Context context) {
|
||||
if (!localRepoServiceIsBound) {
|
||||
Context app = context.getApplicationContext();
|
||||
app.bindService(new Intent(app, LocalRepoService.class),
|
||||
serviceConnection, Context.BIND_AUTO_CREATE);
|
||||
localRepoServiceIsBound = true;
|
||||
Intent service = new Intent(app, LocalRepoService.class);
|
||||
localRepoServiceIsBound = app.bindService(service, serviceConnection,
|
||||
Context.BIND_AUTO_CREATE);
|
||||
if (localRepoServiceIsBound)
|
||||
app.startService(service);
|
||||
}
|
||||
}
|
||||
|
||||
public static void stopLocalRepoService(Context context) {
|
||||
Context app = context.getApplicationContext();
|
||||
if (localRepoServiceIsBound) {
|
||||
context.getApplicationContext().unbindService(serviceConnection);
|
||||
app.unbindService(serviceConnection);
|
||||
localRepoServiceIsBound = false;
|
||||
}
|
||||
app.stopService(new Intent(app, LocalRepoService.class));
|
||||
}
|
||||
|
||||
public static void restartLocalRepoService() {
|
||||
|
@ -216,25 +216,31 @@ public class LocalRepoService extends Service {
|
||||
}
|
||||
|
||||
private void registerMDNSService() {
|
||||
String repoName = Preferences.get().getLocalRepoName();
|
||||
final HashMap<String, String> values = new HashMap<String, String>();
|
||||
values.put("path", "/fdroid/repo");
|
||||
values.put("name", repoName);
|
||||
values.put("fingerprint", FDroidApp.repo.fingerprint);
|
||||
String type;
|
||||
if (Preferences.get().isLocalRepoHttpsEnabled()) {
|
||||
values.put("type", "fdroidrepos");
|
||||
type = "_https._tcp.local.";
|
||||
} else {
|
||||
values.put("type", "fdroidrepo");
|
||||
type = "_http._tcp.local.";
|
||||
}
|
||||
pairService = ServiceInfo.create(type, repoName, FDroidApp.port, 0, 0, values);
|
||||
new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
/*
|
||||
* a ServiceInfo can only be registered with a single instance
|
||||
* of JmDNS, and there is only ever a single LocalHTTPD port to
|
||||
* advertise anyway.
|
||||
*/
|
||||
if (pairService != null || jmdns != null)
|
||||
clearCurrentMDNSService();
|
||||
String repoName = Preferences.get().getLocalRepoName();
|
||||
HashMap<String, String> values = new HashMap<String, String>();
|
||||
values.put("path", "/fdroid/repo");
|
||||
values.put("name", repoName);
|
||||
values.put("fingerprint", FDroidApp.repo.fingerprint);
|
||||
String type;
|
||||
if (Preferences.get().isLocalRepoHttpsEnabled()) {
|
||||
values.put("type", "fdroidrepos");
|
||||
type = "_https._tcp.local.";
|
||||
} else {
|
||||
values.put("type", "fdroidrepo");
|
||||
type = "_http._tcp.local.";
|
||||
}
|
||||
try {
|
||||
pairService = ServiceInfo.create(type, repoName, FDroidApp.port, 0, 0, values);
|
||||
jmdns = JmDNS.create();
|
||||
jmdns.registerService(pairService);
|
||||
} catch (IOException e) {
|
||||
@ -249,6 +255,10 @@ public class LocalRepoService extends Service {
|
||||
Preferences.get().unregisterLocalRepoBonjourListeners(localRepoBonjourChangeListener);
|
||||
localRepoBonjourChangeListener = null;
|
||||
}
|
||||
clearCurrentMDNSService();
|
||||
}
|
||||
|
||||
private void clearCurrentMDNSService() {
|
||||
if (jmdns != null) {
|
||||
if (pairService != null) {
|
||||
jmdns.unregisterService(pairService);
|
||||
|
@ -22,6 +22,7 @@ package org.fdroid.fdroid.net;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import org.fdroid.fdroid.Hasher;
|
||||
import org.fdroid.fdroid.ProgressListener;
|
||||
import org.fdroid.fdroid.data.Apk;
|
||||
@ -172,8 +173,7 @@ public class ApkDownloader implements AsyncDownloadWrapper.Listener {
|
||||
Log.d(TAG, "Downloading apk from " + remoteAddress);
|
||||
|
||||
try {
|
||||
|
||||
Downloader downloader = new HttpDownloader(remoteAddress, localFile);
|
||||
Downloader downloader = DownloaderFactory.create(remoteAddress, localFile);
|
||||
dlWrapper = new AsyncDownloadWrapper(downloader, this);
|
||||
dlWrapper.download();
|
||||
return true;
|
||||
|
@ -14,6 +14,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
public abstract class Downloader {
|
||||
|
||||
@ -23,31 +24,32 @@ public abstract class Downloader {
|
||||
private ProgressListener progressListener = null;
|
||||
private Bundle eventData = null;
|
||||
private File outputFile;
|
||||
|
||||
protected URL sourceUrl;
|
||||
protected String cacheTag = null;
|
||||
|
||||
public static final String EVENT_PROGRESS = "downloadProgress";
|
||||
|
||||
public abstract InputStream inputStream() throws IOException;
|
||||
public abstract InputStream getInputStream() throws IOException;
|
||||
|
||||
// The context is required for opening the file to write to.
|
||||
public Downloader(String destFile, Context ctx)
|
||||
Downloader(String destFile, Context ctx)
|
||||
throws FileNotFoundException, MalformedURLException {
|
||||
this(new File(ctx.getFilesDir() + File.separator + destFile));
|
||||
}
|
||||
|
||||
// The context is required for opening the file to write to.
|
||||
public Downloader(Context ctx) throws IOException {
|
||||
Downloader(Context ctx) throws IOException {
|
||||
this(File.createTempFile("dl-", "", ctx.getCacheDir()));
|
||||
}
|
||||
|
||||
public Downloader(File destFile)
|
||||
Downloader(File destFile)
|
||||
throws FileNotFoundException, MalformedURLException {
|
||||
// http://developer.android.com/guide/topics/data/data-storage.html#InternalCache
|
||||
outputFile = destFile;
|
||||
outputStream = new FileOutputStream(outputFile);
|
||||
}
|
||||
|
||||
public Downloader(OutputStream output)
|
||||
Downloader(OutputStream output)
|
||||
throws MalformedURLException {
|
||||
outputStream = output;
|
||||
outputFile = null;
|
||||
@ -118,13 +120,13 @@ public abstract class Downloader {
|
||||
Log.d(TAG, "Downloading from stream");
|
||||
InputStream input = null;
|
||||
try {
|
||||
input = inputStream();
|
||||
input = getInputStream();
|
||||
|
||||
// Getting the input stream is slow(ish) for HTTP downloads, so we'll check if
|
||||
// we were interrupted before proceeding to the download.
|
||||
throwExceptionIfInterrupted();
|
||||
|
||||
copyInputToOutputStream(inputStream());
|
||||
copyInputToOutputStream(getInputStream());
|
||||
} finally {
|
||||
Utils.closeQuietly(outputStream);
|
||||
Utils.closeQuietly(input);
|
||||
|
32
src/org/fdroid/fdroid/net/DownloaderFactory.java
Normal file
32
src/org/fdroid/fdroid/net/DownloaderFactory.java
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
package org.fdroid.fdroid.net;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class DownloaderFactory {
|
||||
|
||||
public static Downloader create(String url, Context context)
|
||||
throws IOException {
|
||||
if (isOnionAddress(url)) {
|
||||
return new TorHttpDownloader(url, context);
|
||||
} else {
|
||||
return new HttpDownloader(url, context);
|
||||
}
|
||||
}
|
||||
|
||||
public static Downloader create(String url, File destFile)
|
||||
throws IOException {
|
||||
if (isOnionAddress(url)) {
|
||||
return new TorHttpDownloader(url, destFile);
|
||||
} else {
|
||||
return new HttpDownloader(url, destFile);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isOnionAddress(String url) {
|
||||
return url.matches("^[a-zA-Z0-9]+://[^/]+\\.onion/.*");
|
||||
}
|
||||
}
|
@ -7,33 +7,23 @@ import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
|
||||
public class HttpDownloader extends Downloader {
|
||||
private static final String TAG = "org.fdroid.fdroid.net.HttpDownloader";
|
||||
|
||||
private static final String HEADER_IF_NONE_MATCH = "If-None-Match";
|
||||
private static final String HEADER_FIELD_ETAG = "ETag";
|
||||
protected static final String HEADER_IF_NONE_MATCH = "If-None-Match";
|
||||
protected static final String HEADER_FIELD_ETAG = "ETag";
|
||||
|
||||
private URL sourceUrl;
|
||||
private HttpURLConnection connection;
|
||||
protected HttpURLConnection connection;
|
||||
private int statusCode = -1;
|
||||
|
||||
// The context is required for opening the file to write to.
|
||||
public HttpDownloader(String source, String destFile, Context ctx)
|
||||
throws FileNotFoundException, MalformedURLException {
|
||||
super(destFile, ctx);
|
||||
sourceUrl = new URL(source);
|
||||
}
|
||||
|
||||
// The context is required for opening the file to write to.
|
||||
public HttpDownloader(String source, File destFile)
|
||||
HttpDownloader(String source, File destFile)
|
||||
throws FileNotFoundException, MalformedURLException {
|
||||
super(destFile);
|
||||
sourceUrl = new URL(source);
|
||||
@ -42,20 +32,17 @@ public class HttpDownloader extends Downloader {
|
||||
/**
|
||||
* Downloads to a temporary file, which *you must delete yourself when
|
||||
* you are done*.
|
||||
* @see org.fdroid.fdroid.net.HttpDownloader#getFile()
|
||||
* @see org.fdroid.fdroid.net.Downloader#getFile()
|
||||
*/
|
||||
public HttpDownloader(String source, Context ctx) throws IOException {
|
||||
HttpDownloader(String source, Context ctx) throws IOException {
|
||||
super(ctx);
|
||||
sourceUrl = new URL(source);
|
||||
}
|
||||
|
||||
public HttpDownloader(String source, OutputStream output)
|
||||
throws MalformedURLException {
|
||||
super(output);
|
||||
sourceUrl = new URL(source);
|
||||
}
|
||||
|
||||
public InputStream inputStream() throws IOException {
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
setupConnection();
|
||||
// TODO check out BaseImageDownloader.getStreamFromNetwork() for optims
|
||||
return connection.getInputStream();
|
||||
}
|
||||
|
||||
@ -68,31 +55,41 @@ public class HttpDownloader extends Downloader {
|
||||
@Override
|
||||
public void download() throws IOException, InterruptedException {
|
||||
try {
|
||||
connection = (HttpURLConnection)sourceUrl.openConnection();
|
||||
|
||||
if (wantToCheckCache()) {
|
||||
setupCacheCheck();
|
||||
Log.i(TAG, "Checking cached status of " + sourceUrl);
|
||||
statusCode = connection.getResponseCode();
|
||||
}
|
||||
|
||||
if (isCached()) {
|
||||
Log.i(TAG, sourceUrl + " is cached, so not downloading (HTTP " + statusCode + ")");
|
||||
} else {
|
||||
Log.i(TAG, "Downloading from " + sourceUrl);
|
||||
downloadFromStream();
|
||||
updateCacheCheck();
|
||||
}
|
||||
setupConnection();
|
||||
doDownload();
|
||||
} catch (SSLHandshakeException e) {
|
||||
// TODO this should be handled better, it is not internationalised here.
|
||||
// TODO this should be handled better, it is not internationalised here
|
||||
throw new IOException(
|
||||
"A problem occurred while establishing an SSL " +
|
||||
"connection. If this problem persists, AND you have a " +
|
||||
"very old device, you could try using http instead of " +
|
||||
"https for the repo URL." + Log.getStackTraceString(e) );
|
||||
"https for the repo URL." + Log.getStackTraceString(e));
|
||||
}
|
||||
}
|
||||
|
||||
protected void setupConnection() throws IOException {
|
||||
if (connection != null)
|
||||
return;
|
||||
connection = (HttpURLConnection) sourceUrl.openConnection();
|
||||
}
|
||||
|
||||
protected void doDownload() throws IOException, InterruptedException {
|
||||
if (wantToCheckCache()) {
|
||||
setupCacheCheck();
|
||||
Log.i(TAG, "Checking cached status of " + sourceUrl);
|
||||
statusCode = connection.getResponseCode();
|
||||
}
|
||||
|
||||
if (isCached()) {
|
||||
Log.i(TAG, sourceUrl + " is cached, so not downloading (HTTP " + statusCode + ")");
|
||||
} else {
|
||||
Log.i(TAG, "Downloading from " + sourceUrl);
|
||||
downloadFromStream();
|
||||
updateCacheCheck();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCached() {
|
||||
return wantToCheckCache() && statusCode == 304;
|
||||
}
|
||||
|
32
src/org/fdroid/fdroid/net/IconDownloader.java
Normal file
32
src/org/fdroid/fdroid/net/IconDownloader.java
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
package org.fdroid.fdroid.net;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.nostra13.universalimageloader.core.download.BaseImageDownloader;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class IconDownloader extends BaseImageDownloader {
|
||||
|
||||
public IconDownloader(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public IconDownloader(Context context, int connectTimeout, int readTimeout) {
|
||||
super(context, connectTimeout, readTimeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getStream(String imageUri, Object extra) throws IOException {
|
||||
switch (Scheme.ofUri(imageUri)) {
|
||||
case HTTP:
|
||||
case HTTPS:
|
||||
Downloader downloader = DownloaderFactory.create(imageUri, context);
|
||||
return downloader.getInputStream();
|
||||
default:
|
||||
return super.getStream(imageUri, extra);
|
||||
}
|
||||
}
|
||||
}
|
32
src/org/fdroid/fdroid/net/TorHttpDownloader.java
Normal file
32
src/org/fdroid/fdroid/net/TorHttpDownloader.java
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
package org.fdroid.fdroid.net;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.Proxy;
|
||||
import java.net.SocketAddress;
|
||||
|
||||
public class TorHttpDownloader extends HttpDownloader {
|
||||
|
||||
TorHttpDownloader(String url, Context ctx) throws IOException {
|
||||
super(url, ctx);
|
||||
}
|
||||
|
||||
TorHttpDownloader(String url, File destFile)
|
||||
throws FileNotFoundException, MalformedURLException {
|
||||
super(url, destFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupConnection() throws IOException {
|
||||
SocketAddress sa = new InetSocketAddress("127.0.0.1", 8118);
|
||||
Proxy tor = new Proxy(Proxy.Type.HTTP, sa);
|
||||
connection = (HttpURLConnection) sourceUrl.openConnection(tor);
|
||||
}
|
||||
}
|
@ -23,9 +23,14 @@ import java.util.Locale;
|
||||
public class WifiStateChangeService extends Service {
|
||||
public static final String BROADCAST = "org.fdroid.fdroid.action.WIFI_CHANGE";
|
||||
|
||||
private static WaitForWifiAsyncTask asyncTask;
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
new WaitForWifiAsyncTask().execute();
|
||||
if (asyncTask != null)
|
||||
asyncTask.cancel(true);
|
||||
asyncTask = new WaitForWifiAsyncTask();
|
||||
asyncTask.execute();
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
@ -38,15 +43,21 @@ public class WifiStateChangeService extends Service {
|
||||
wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
|
||||
try {
|
||||
while (!wifiManager.isWifiEnabled()) {
|
||||
if (isCancelled())
|
||||
return null;
|
||||
Log.i(TAG, "waiting for the wifi to be enabled...");
|
||||
Thread.sleep(3000);
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
int ipAddress = wifiManager.getConnectionInfo().getIpAddress();
|
||||
while (ipAddress == 0) {
|
||||
if (isCancelled())
|
||||
return null;
|
||||
Log.i(TAG, "waiting for an IP address...");
|
||||
Thread.sleep(3000);
|
||||
Thread.sleep(1000);
|
||||
ipAddress = wifiManager.getConnectionInfo().getIpAddress();
|
||||
}
|
||||
if (isCancelled())
|
||||
return null;
|
||||
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
|
||||
ipAddress = wifiInfo.getIpAddress();
|
||||
FDroidApp.ipAddressString = String.format(Locale.ENGLISH, "%d.%d.%d.%d",
|
||||
@ -67,6 +78,9 @@ public class WifiStateChangeService extends Service {
|
||||
FDroidApp.repo.address = String.format(Locale.ENGLISH, "%s://%s:%d/fdroid/repo",
|
||||
scheme, FDroidApp.ipAddressString, FDroidApp.port);
|
||||
|
||||
if (isCancelled())
|
||||
return null;
|
||||
|
||||
Context context = WifiStateChangeService.this.getApplicationContext();
|
||||
LocalRepoKeyStore localRepoKeyStore = LocalRepoKeyStore.get(context);
|
||||
Certificate localCert = localRepoKeyStore.getCertificate();
|
||||
@ -75,6 +89,9 @@ public class WifiStateChangeService extends Service {
|
||||
lrm.setUriString(FDroidApp.repo.address);
|
||||
lrm.writeIndexPage(Utils.getSharingUri(context, FDroidApp.repo).toString());
|
||||
|
||||
if (isCancelled())
|
||||
return null;
|
||||
|
||||
/*
|
||||
* Once the IP address is known we need to generate a self
|
||||
* signed certificate to use for HTTPS that has a CN field set
|
||||
|
@ -13,7 +13,7 @@ import org.fdroid.fdroid.data.App;
|
||||
import org.fdroid.fdroid.data.Repo;
|
||||
import org.fdroid.fdroid.data.RepoProvider;
|
||||
import org.fdroid.fdroid.net.Downloader;
|
||||
import org.fdroid.fdroid.net.HttpDownloader;
|
||||
import org.fdroid.fdroid.net.DownloaderFactory;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
@ -89,7 +89,7 @@ abstract public class RepoUpdater {
|
||||
protected Downloader downloadIndex() throws UpdateException {
|
||||
Downloader downloader = null;
|
||||
try {
|
||||
downloader = new HttpDownloader(getIndexAddress(), context);
|
||||
downloader = DownloaderFactory.create(getIndexAddress(), context);
|
||||
downloader.setCacheTag(repo.lastetag);
|
||||
|
||||
if (progressListener != null) { // interactive session, show progress
|
||||
|
Loading…
x
Reference in New Issue
Block a user