2013-04-06 21:47:24 +02:00
|
|
|
/*
|
|
|
|
This file is part of Subsonic.
|
|
|
|
|
|
|
|
Subsonic is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Subsonic is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
Copyright 2009 (C) Sindre Mehus
|
|
|
|
*/
|
2015-07-26 18:15:07 +02:00
|
|
|
package org.moire.ultrasonic.service;
|
2013-04-06 21:47:24 +02:00
|
|
|
|
|
|
|
import android.content.Context;
|
2013-05-16 09:59:55 +02:00
|
|
|
import android.net.wifi.WifiManager;
|
2013-04-06 21:47:24 +02:00
|
|
|
import android.os.PowerManager;
|
2018-02-10 20:11:17 +01:00
|
|
|
import android.text.TextUtils;
|
2013-04-06 21:47:24 +02:00
|
|
|
import android.util.Log;
|
2013-04-19 01:21:24 +02:00
|
|
|
|
2020-06-26 15:18:14 +02:00
|
|
|
import org.jetbrains.annotations.NotNull;
|
2015-07-26 18:15:07 +02:00
|
|
|
import org.moire.ultrasonic.domain.MusicDirectory;
|
|
|
|
import org.moire.ultrasonic.util.CacheCleaner;
|
|
|
|
import org.moire.ultrasonic.util.CancellableTask;
|
|
|
|
import org.moire.ultrasonic.util.FileUtil;
|
|
|
|
import org.moire.ultrasonic.util.Util;
|
2013-04-06 21:47:24 +02:00
|
|
|
|
2013-12-04 07:36:02 +01:00
|
|
|
import java.io.File;
|
|
|
|
import java.io.FileOutputStream;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.io.OutputStream;
|
|
|
|
import java.io.RandomAccessFile;
|
|
|
|
|
2020-06-22 18:35:58 +02:00
|
|
|
import kotlin.Lazy;
|
2017-11-05 22:14:28 +01:00
|
|
|
import kotlin.Pair;
|
|
|
|
|
2013-12-04 07:36:02 +01:00
|
|
|
import static android.content.Context.POWER_SERVICE;
|
|
|
|
import static android.os.PowerManager.ON_AFTER_RELEASE;
|
|
|
|
import static android.os.PowerManager.SCREEN_DIM_WAKE_LOCK;
|
2020-06-22 18:35:58 +02:00
|
|
|
import static org.koin.java.standalone.KoinJavaComponent.inject;
|
2013-04-06 21:47:24 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @author Sindre Mehus
|
|
|
|
* @version $Id$
|
|
|
|
*/
|
2013-12-04 07:36:02 +01:00
|
|
|
public class DownloadFile
|
|
|
|
{
|
|
|
|
private static final String TAG = DownloadFile.class.getSimpleName();
|
|
|
|
private final Context context;
|
|
|
|
private final MusicDirectory.Entry song;
|
|
|
|
private final File partialFile;
|
|
|
|
private final File completeFile;
|
|
|
|
private final File saveFile;
|
|
|
|
|
|
|
|
private final MediaStoreService mediaStoreService;
|
|
|
|
private CancellableTask downloadTask;
|
2013-12-30 09:33:39 +01:00
|
|
|
private final boolean save;
|
2013-12-04 07:36:02 +01:00
|
|
|
private boolean failed;
|
|
|
|
private int bitRate;
|
|
|
|
private volatile boolean isPlaying;
|
|
|
|
private volatile boolean saveWhenDone;
|
|
|
|
private volatile boolean completeWhenDone;
|
|
|
|
|
2020-06-23 18:40:44 +02:00
|
|
|
private Lazy<Downloader> downloader = inject(Downloader.class);
|
|
|
|
|
2013-12-04 07:36:02 +01:00
|
|
|
public DownloadFile(Context context, MusicDirectory.Entry song, boolean save)
|
|
|
|
{
|
|
|
|
super();
|
|
|
|
this.context = context;
|
|
|
|
this.song = song;
|
|
|
|
this.save = save;
|
|
|
|
|
|
|
|
saveFile = FileUtil.getSongFile(context, song);
|
|
|
|
bitRate = Util.getMaxBitRate(context);
|
|
|
|
partialFile = new File(saveFile.getParent(), String.format("%s.partial.%s", FileUtil.getBaseName(saveFile.getName()), FileUtil.getExtension(saveFile.getName())));
|
|
|
|
completeFile = new File(saveFile.getParent(), String.format("%s.complete.%s", FileUtil.getBaseName(saveFile.getName()), FileUtil.getExtension(saveFile.getName())));
|
|
|
|
mediaStoreService = new MediaStoreService(context);
|
|
|
|
}
|
|
|
|
|
|
|
|
public MusicDirectory.Entry getSong()
|
|
|
|
{
|
|
|
|
return song;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the effective bit rate.
|
|
|
|
*/
|
|
|
|
public int getBitRate()
|
|
|
|
{
|
|
|
|
if (!partialFile.exists())
|
|
|
|
{
|
2013-06-07 04:27:45 +02:00
|
|
|
bitRate = Util.getMaxBitRate(context);
|
2013-05-16 09:59:55 +02:00
|
|
|
}
|
2013-12-04 07:36:02 +01:00
|
|
|
|
|
|
|
if (bitRate > 0)
|
|
|
|
{
|
|
|
|
return bitRate;
|
|
|
|
}
|
|
|
|
|
|
|
|
return song.getBitRate() == null ? 160 : song.getBitRate();
|
|
|
|
}
|
|
|
|
|
|
|
|
public synchronized void download()
|
|
|
|
{
|
|
|
|
FileUtil.createDirectoryForParent(saveFile);
|
|
|
|
failed = false;
|
|
|
|
|
|
|
|
if (!partialFile.exists())
|
|
|
|
{
|
2013-06-07 04:27:45 +02:00
|
|
|
bitRate = Util.getMaxBitRate(context);
|
2013-05-16 09:59:55 +02:00
|
|
|
}
|
2013-12-04 07:36:02 +01:00
|
|
|
|
|
|
|
downloadTask = new DownloadTask();
|
|
|
|
downloadTask.start();
|
|
|
|
}
|
|
|
|
|
|
|
|
public synchronized void cancelDownload()
|
|
|
|
{
|
|
|
|
if (downloadTask != null)
|
|
|
|
{
|
|
|
|
downloadTask.cancel();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public File getCompleteFile()
|
|
|
|
{
|
|
|
|
if (saveFile.exists())
|
|
|
|
{
|
|
|
|
return saveFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (completeFile.exists())
|
|
|
|
{
|
|
|
|
return completeFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
return saveFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
public File getPartialFile()
|
|
|
|
{
|
|
|
|
return partialFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isSaved()
|
|
|
|
{
|
|
|
|
return saveFile.exists();
|
|
|
|
}
|
|
|
|
|
|
|
|
public synchronized boolean isCompleteFileAvailable()
|
|
|
|
{
|
|
|
|
return saveFile.exists() || completeFile.exists();
|
|
|
|
}
|
|
|
|
|
|
|
|
public synchronized boolean isWorkDone()
|
|
|
|
{
|
|
|
|
return saveFile.exists() || (completeFile.exists() && !save) || saveWhenDone || completeWhenDone;
|
|
|
|
}
|
|
|
|
|
|
|
|
public synchronized boolean isDownloading()
|
|
|
|
{
|
|
|
|
return downloadTask != null && downloadTask.isRunning();
|
|
|
|
}
|
|
|
|
|
|
|
|
public synchronized boolean isDownloadCancelled()
|
|
|
|
{
|
|
|
|
return downloadTask != null && downloadTask.isCancelled();
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean shouldSave()
|
|
|
|
{
|
|
|
|
return save;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isFailed()
|
|
|
|
{
|
|
|
|
return failed;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void delete()
|
|
|
|
{
|
|
|
|
cancelDownload();
|
|
|
|
Util.delete(partialFile);
|
|
|
|
Util.delete(completeFile);
|
|
|
|
Util.delete(saveFile);
|
|
|
|
mediaStoreService.deleteFromMediaStore(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void unpin()
|
|
|
|
{
|
|
|
|
if (saveFile.exists())
|
|
|
|
{
|
|
|
|
saveFile.renameTo(completeFile);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean cleanup()
|
|
|
|
{
|
|
|
|
boolean ok = true;
|
|
|
|
|
|
|
|
if (completeFile.exists() || saveFile.exists())
|
|
|
|
{
|
|
|
|
ok = Util.delete(partialFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (saveFile.exists())
|
|
|
|
{
|
|
|
|
ok &= Util.delete(completeFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
// In support of LRU caching.
|
|
|
|
public void updateModificationDate()
|
|
|
|
{
|
|
|
|
updateModificationDate(saveFile);
|
|
|
|
updateModificationDate(partialFile);
|
|
|
|
updateModificationDate(completeFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void updateModificationDate(File file)
|
|
|
|
{
|
|
|
|
if (file.exists())
|
|
|
|
{
|
|
|
|
boolean ok = file.setLastModified(System.currentTimeMillis());
|
|
|
|
|
|
|
|
if (!ok)
|
|
|
|
{
|
|
|
|
Log.i(TAG, String.format("Failed to set last-modified date on %s, trying alternate method", file));
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// Try alternate method to update last modified date to current time
|
|
|
|
// Found at https://code.google.com/p/android/issues/detail?id=18624
|
|
|
|
RandomAccessFile raf = new RandomAccessFile(file, "rw");
|
|
|
|
long length = raf.length();
|
|
|
|
raf.setLength(length + 1);
|
|
|
|
raf.setLength(length);
|
|
|
|
raf.close();
|
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
|
|
|
Log.w(TAG, String.format("Failed to set last-modified date on %s", file));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setPlaying(boolean isPlaying)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if (saveWhenDone && !isPlaying)
|
|
|
|
{
|
2013-05-16 09:59:55 +02:00
|
|
|
Util.renameFile(completeFile, saveFile);
|
|
|
|
saveWhenDone = false;
|
2013-12-04 07:36:02 +01:00
|
|
|
}
|
|
|
|
else if (completeWhenDone && !isPlaying)
|
|
|
|
{
|
|
|
|
if (save)
|
|
|
|
{
|
2013-05-16 09:59:55 +02:00
|
|
|
Util.renameFile(partialFile, saveFile);
|
2013-12-04 07:36:02 +01:00
|
|
|
mediaStoreService.saveInMediaStore(DownloadFile.this);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-05-16 09:59:55 +02:00
|
|
|
Util.renameFile(partialFile, completeFile);
|
|
|
|
}
|
2013-12-04 07:36:02 +01:00
|
|
|
|
2013-05-16 09:59:55 +02:00
|
|
|
completeWhenDone = false;
|
|
|
|
}
|
|
|
|
}
|
2013-12-04 07:36:02 +01:00
|
|
|
catch (IOException ex)
|
|
|
|
{
|
|
|
|
Log.w(TAG, String.format("Failed to rename file %s to %s", completeFile, saveFile));
|
|
|
|
}
|
|
|
|
|
2013-05-16 09:59:55 +02:00
|
|
|
this.isPlaying = isPlaying;
|
|
|
|
}
|
2013-04-06 21:47:24 +02:00
|
|
|
|
2020-06-26 15:18:14 +02:00
|
|
|
@NotNull
|
2013-12-04 07:36:02 +01:00
|
|
|
@Override
|
|
|
|
public String toString()
|
|
|
|
{
|
|
|
|
return String.format("DownloadFile (%s)", song);
|
|
|
|
}
|
2013-04-06 21:47:24 +02:00
|
|
|
|
2013-12-04 07:36:02 +01:00
|
|
|
private class DownloadTask extends CancellableTask
|
|
|
|
{
|
|
|
|
@Override
|
|
|
|
public void execute()
|
|
|
|
{
|
|
|
|
InputStream in = null;
|
|
|
|
FileOutputStream out = null;
|
|
|
|
PowerManager.WakeLock wakeLock = null;
|
2013-05-16 09:59:55 +02:00
|
|
|
WifiManager.WifiLock wifiLock = null;
|
2013-12-04 07:36:02 +01:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if (Util.isScreenLitOnDownload(context))
|
|
|
|
{
|
|
|
|
PowerManager pm = (PowerManager) context.getSystemService(POWER_SERVICE);
|
|
|
|
wakeLock = pm.newWakeLock(SCREEN_DIM_WAKE_LOCK | ON_AFTER_RELEASE, toString());
|
2020-06-26 15:18:14 +02:00
|
|
|
wakeLock.acquire(10*60*1000L /*10 minutes*/);
|
2013-12-04 07:36:02 +01:00
|
|
|
Log.i(TAG, String.format("Acquired wake lock %s", wakeLock));
|
|
|
|
}
|
|
|
|
|
2013-05-16 09:59:55 +02:00
|
|
|
wifiLock = Util.createWifiLock(context, toString());
|
|
|
|
wifiLock.acquire();
|
2013-04-06 21:47:24 +02:00
|
|
|
|
2013-12-04 07:36:02 +01:00
|
|
|
if (saveFile.exists())
|
|
|
|
{
|
|
|
|
Log.i(TAG, String.format("%s already exists. Skipping.", saveFile));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (completeFile.exists())
|
|
|
|
{
|
|
|
|
if (save)
|
|
|
|
{
|
|
|
|
if (isPlaying)
|
|
|
|
{
|
2013-05-16 09:59:55 +02:00
|
|
|
saveWhenDone = true;
|
2013-12-04 07:36:02 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-05-16 09:59:55 +02:00
|
|
|
Util.renameFile(completeFile, saveFile);
|
|
|
|
}
|
2013-12-04 07:36:02 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Log.i(TAG, String.format("%s already exists. Skipping.", completeFile));
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2013-04-06 21:47:24 +02:00
|
|
|
|
2013-12-04 07:36:02 +01:00
|
|
|
MusicService musicService = MusicServiceFactory.getMusicService(context);
|
2013-04-06 21:47:24 +02:00
|
|
|
|
2013-05-16 09:59:55 +02:00
|
|
|
// Some devices seem to throw error on partial file which doesn't exist
|
|
|
|
boolean compare;
|
2013-12-04 07:36:02 +01:00
|
|
|
|
2013-06-07 04:27:45 +02:00
|
|
|
Integer duration = song.getDuration();
|
|
|
|
long fileLength = 0;
|
2013-12-04 07:36:02 +01:00
|
|
|
|
|
|
|
if (!partialFile.exists())
|
|
|
|
{
|
2013-06-07 04:27:45 +02:00
|
|
|
fileLength = partialFile.length();
|
|
|
|
}
|
2013-12-04 07:36:02 +01:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
2013-06-07 04:27:45 +02:00
|
|
|
compare = (bitRate == 0) || (duration == null || duration == 0) || (fileLength == 0);
|
|
|
|
//(bitRate * song.getDuration() * 1000 / 8) > partialFile.length();
|
2013-12-04 07:36:02 +01:00
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
2013-05-16 09:59:55 +02:00
|
|
|
compare = true;
|
|
|
|
}
|
2013-12-04 07:36:02 +01:00
|
|
|
|
|
|
|
if (compare)
|
|
|
|
{
|
2013-05-16 09:59:55 +02:00
|
|
|
// Attempt partial HTTP GET, appending to the file if it exists.
|
2017-11-05 22:14:28 +01:00
|
|
|
Pair<InputStream, Boolean> response = musicService
|
|
|
|
.getDownloadInputStream(context, song, partialFile.length(), bitRate,
|
|
|
|
DownloadTask.this);
|
2013-12-04 07:36:02 +01:00
|
|
|
|
2017-11-05 22:14:28 +01:00
|
|
|
if (response.getSecond())
|
2013-12-04 07:36:02 +01:00
|
|
|
{
|
|
|
|
Log.i(TAG, String.format("Executed partial HTTP GET, skipping %d bytes", partialFile.length()));
|
2013-05-16 09:59:55 +02:00
|
|
|
}
|
|
|
|
|
2017-11-05 22:14:28 +01:00
|
|
|
out = new FileOutputStream(partialFile, response.getSecond());
|
|
|
|
long n = copy(response.getFirst(), out);
|
2013-12-04 07:36:02 +01:00
|
|
|
Log.i(TAG, String.format("Downloaded %d bytes to %s", n, partialFile));
|
2013-05-16 09:59:55 +02:00
|
|
|
out.flush();
|
|
|
|
out.close();
|
|
|
|
|
2013-12-04 07:36:02 +01:00
|
|
|
if (isCancelled())
|
|
|
|
{
|
|
|
|
throw new Exception(String.format("Download of '%s' was cancelled", song));
|
2013-05-16 09:59:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
downloadAndSaveCoverArt(musicService);
|
|
|
|
}
|
|
|
|
|
2013-12-04 07:36:02 +01:00
|
|
|
if (isPlaying)
|
|
|
|
{
|
2013-05-16 09:59:55 +02:00
|
|
|
completeWhenDone = true;
|
2013-12-04 07:36:02 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (save)
|
|
|
|
{
|
2013-05-16 09:59:55 +02:00
|
|
|
Util.renameFile(partialFile, saveFile);
|
|
|
|
mediaStoreService.saveInMediaStore(DownloadFile.this);
|
2014-01-21 07:16:24 +01:00
|
|
|
|
|
|
|
if (Util.getShouldScanMedia(context))
|
|
|
|
{
|
|
|
|
Util.scanMedia(context, saveFile);
|
|
|
|
}
|
2013-12-04 07:36:02 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-05-16 09:59:55 +02:00
|
|
|
Util.renameFile(partialFile, completeFile);
|
2014-01-21 07:16:24 +01:00
|
|
|
|
|
|
|
if (Util.getShouldScanMedia(context))
|
|
|
|
{
|
|
|
|
Util.scanMedia(context, completeFile);
|
|
|
|
}
|
2013-05-16 09:59:55 +02:00
|
|
|
}
|
|
|
|
}
|
2013-12-04 07:36:02 +01:00
|
|
|
}
|
|
|
|
catch (Exception x)
|
|
|
|
{
|
|
|
|
Util.close(out);
|
|
|
|
Util.delete(completeFile);
|
|
|
|
Util.delete(saveFile);
|
2014-01-21 07:16:24 +01:00
|
|
|
|
2013-12-04 07:36:02 +01:00
|
|
|
if (!isCancelled())
|
|
|
|
{
|
|
|
|
failed = true;
|
|
|
|
Log.w(TAG, String.format("Failed to download '%s'.", song), x);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
finally
|
|
|
|
{
|
|
|
|
Util.close(in);
|
|
|
|
Util.close(out);
|
|
|
|
if (wakeLock != null)
|
|
|
|
{
|
|
|
|
wakeLock.release();
|
|
|
|
Log.i(TAG, String.format("Released wake lock %s", wakeLock));
|
|
|
|
}
|
|
|
|
if (wifiLock != null)
|
|
|
|
{
|
2013-05-16 09:59:55 +02:00
|
|
|
wifiLock.release();
|
|
|
|
}
|
2014-01-21 07:16:24 +01:00
|
|
|
|
2020-06-22 18:35:58 +02:00
|
|
|
new CacheCleaner(context).cleanSpace();
|
2014-01-21 07:16:24 +01:00
|
|
|
|
2020-06-23 18:40:44 +02:00
|
|
|
downloader.getValue().checkDownloads();
|
2013-12-04 07:36:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-26 15:18:14 +02:00
|
|
|
@NotNull
|
2013-12-04 07:36:02 +01:00
|
|
|
@Override
|
|
|
|
public String toString()
|
|
|
|
{
|
|
|
|
return String.format("DownloadTask (%s)", song);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void downloadAndSaveCoverArt(MusicService musicService) throws Exception
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2018-02-10 20:11:17 +01:00
|
|
|
if (!TextUtils.isEmpty(song.getCoverArt())) {
|
2013-12-04 07:36:02 +01:00
|
|
|
int size = Util.getMinDisplayMetric(context);
|
|
|
|
musicService.getCoverArt(context, song, size, true, true, null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (Exception x)
|
|
|
|
{
|
|
|
|
Log.e(TAG, "Failed to get cover art.", x);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private long copy(final InputStream in, OutputStream out) throws IOException
|
|
|
|
{
|
|
|
|
// Start a thread that will close the input stream if the task is
|
|
|
|
// cancelled, thus causing the copy() method to return.
|
|
|
|
new Thread()
|
|
|
|
{
|
|
|
|
@Override
|
|
|
|
public void run()
|
|
|
|
{
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
Util.sleepQuietly(3000L);
|
|
|
|
|
|
|
|
if (isCancelled())
|
|
|
|
{
|
|
|
|
Util.close(in);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isRunning())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}.start();
|
|
|
|
|
|
|
|
byte[] buffer = new byte[1024 * 16];
|
|
|
|
long count = 0;
|
|
|
|
int n;
|
|
|
|
long lastLog = System.currentTimeMillis();
|
|
|
|
|
|
|
|
while (!isCancelled() && (n = in.read(buffer)) != -1)
|
|
|
|
{
|
|
|
|
out.write(buffer, 0, n);
|
|
|
|
count += n;
|
|
|
|
|
|
|
|
long now = System.currentTimeMillis();
|
|
|
|
if (now - lastLog > 3000L)
|
|
|
|
{ // Only every so often.
|
|
|
|
Log.i(TAG, String.format("Downloaded %s of %s", Util.formatBytes(count), song));
|
|
|
|
lastLog = now;
|
2013-05-16 09:59:55 +02:00
|
|
|
}
|
2013-12-04 07:36:02 +01:00
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
}
|
2013-05-16 09:59:55 +02:00
|
|
|
}
|