diff --git a/app/src/main/java/com/hippo/ehviewer/download/DownloadInfo.java b/app/src/main/java/com/hippo/ehviewer/download/DownloadInfo.java index 3b31f4373..af026b314 100644 --- a/app/src/main/java/com/hippo/ehviewer/download/DownloadInfo.java +++ b/app/src/main/java/com/hippo/ehviewer/download/DownloadInfo.java @@ -31,8 +31,12 @@ public class DownloadInfo { public int state = STATE_NONE; // byte/second, -1 for can't get speed now public long speed; + // Remain time millis + public long remaining; // -1 for unknown - public int download = 0; + public int finished = 0; + // -1 for unknown + public int downloaded = 0; // -1 for unknown public int total = -1; // -1 for unknown diff --git a/app/src/main/java/com/hippo/ehviewer/download/DownloadManager.java b/app/src/main/java/com/hippo/ehviewer/download/DownloadManager.java index e169a37e2..ff9502789 100644 --- a/app/src/main/java/com/hippo/ehviewer/download/DownloadManager.java +++ b/app/src/main/java/com/hippo/ehviewer/download/DownloadManager.java @@ -30,8 +30,10 @@ import com.hippo.ehviewer.spider.SpiderQueen; import com.hippo.image.Image; import com.hippo.yorozuya.ConcurrentPool; import com.hippo.yorozuya.IntList; +import com.hippo.yorozuya.MathUtils; import com.hippo.yorozuya.ObjectUtils; import com.hippo.yorozuya.SimpleHandler; +import com.hippo.yorozuya.sparse.SparseIJArray; import java.util.Collections; import java.util.Comparator; @@ -40,7 +42,6 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.concurrent.atomic.AtomicLong; import de.greenrobot.dao.query.LazyList; @@ -211,8 +212,10 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener { spider.addOnSpiderListener(this); info.state = DownloadInfo.STATE_DOWNLOAD; info.speed = -1; + info.remaining = -1; info.total = -1; - info.download = 0; + info.finished = 0; + info.downloaded = 0; info.legacy = -1; // Update in DB EhDB.updateDownloadInfo(info); @@ -726,22 +729,22 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener { } @Override - public void onPageSuccess(int index, int downloaded, int total) { + public void onPageSuccess(int index, int finished, int downloaded, int total) { NotifyTask task = mNotifyTaskPool.pop(); if (task == null) { task = new NotifyTask(); } - task.setOnPageSuccessData(index, downloaded, total); + task.setOnPageSuccessData(index, finished, downloaded, total); SimpleHandler.getInstance().post(task); } @Override - public void onPageFailure(int index, String error, int downloaded, int total) { + public void onPageFailure(int index, String error, int finished, int downloaded, int total) { NotifyTask task = mNotifyTaskPool.pop(); if (task == null) { task = new NotifyTask(); } - task.setOnPageFailureDate(index, error, downloaded, total); + task.setOnPageFailureDate(index, error, finished, downloaded, total); SimpleHandler.getInstance().post(task); } @@ -781,6 +784,7 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener { private long mReceivedSize; private int mBytesRead; private String mError; + private int mFinished; private int mDownloaded; private int mTotal; @@ -802,17 +806,19 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener { mBytesRead = bytesRead; } - public void setOnPageSuccessData(int index, int downloaded, int total) { + public void setOnPageSuccessData(int index, int finished, int downloaded, int total) { mType = TYPE_ON_PAGE_SUCCESS; mIndex = index; + mFinished = finished; mDownloaded = downloaded; mTotal = total; } - public void setOnPageFailureDate(int index, String error, int downloaded, int total) { + public void setOnPageFailureDate(int index, String error, int finished, int downloaded, int total) { mType = TYPE_ON_PAGE_FAILURE; mIndex = index; mError = error; + mFinished = finished; mDownloaded = downloaded; mTotal = total; } @@ -846,15 +852,17 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener { break; } case TYPE_ON_PAGE_DOWNLOAD: { - mSpeedReminder.up(mBytesRead); + mSpeedReminder.onDownload(mIndex, mContentLength, mReceivedSize, mBytesRead); break; } case TYPE_ON_PAGE_SUCCESS: { + mSpeedReminder.onDone(mIndex); DownloadInfo info = mCurrentTask; if (info == null) { Log.e(TAG, "Current task is null, but it should not be"); } else { - info.download = mDownloaded; + info.finished = mFinished; + info.downloaded = mDownloaded; info.total = mTotal; if (mDownloadListener != null) { mDownloadListener.onGetPage(info); @@ -867,11 +875,13 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener { break; } case TYPE_ON_PAGE_FAILURE: { + mSpeedReminder.onDone(mIndex); DownloadInfo info = mCurrentTask; if (info == null) { Log.e(TAG, "Current task is null, but it should not be"); } else { - info.download = mDownloaded; + info.finished = mFinished; + info.downloaded = mDownloaded; info.total = mTotal; List list = getInfoListForLabel(info.label); if (list != null && mDownloadInfoListener != null) { @@ -881,6 +891,7 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener { break; } case TYPE_ON_FINISH: { + mSpeedReminder.onFinish(); // Download done DownloadInfo info = mCurrentTask; mCurrentTask = null; @@ -899,9 +910,10 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener { // Stop speed count mSpeedReminder.stop(); // Update state - info.download = mDownloaded; + info.finished = mFinished; + info.downloaded = mDownloaded; info.total = mTotal; - info.legacy = mTotal - mDownloaded; + info.legacy = mTotal - mFinished; if (info.legacy == 0) { info.state = DownloadInfo.STATE_FINISH; } else { @@ -932,7 +944,11 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener { private boolean mStop = true; - private final AtomicLong mBytesRead = new AtomicLong(); + private long mBytesRead; + private long oldSpeed = -1; + + private final SparseIJArray mContentLengthMap = new SparseIJArray(); + private final SparseIJArray mReceivedSizeMap = new SparseIJArray(); public void start() { if (mStop) { @@ -944,20 +960,62 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener { public void stop() { if (!mStop) { mStop = true; - mBytesRead.lazySet(0L); + mBytesRead = 0; + oldSpeed = -1; + mContentLengthMap.clear(); + mReceivedSizeMap.clear(); SimpleHandler.getInstance().removeCallbacks(this); } } - public void up(int bytesRead) { - mBytesRead.addAndGet(bytesRead); + public void onDownload(int index, long contentLength, long receivedSize, int bytesRead) { + mContentLengthMap.put(index, contentLength); + mReceivedSizeMap.put(index, receivedSize); + mBytesRead += bytesRead; + } + + public void onDone(int index) { + mContentLengthMap.delete(index); + mReceivedSizeMap.delete(index); + } + + public void onFinish() { + mContentLengthMap.clear(); + mReceivedSizeMap.clear(); } @Override public void run() { DownloadInfo info = mCurrentTask; if (info != null) { - info.speed = mBytesRead.getAndSet(0) / 2; + long newSpeed = mBytesRead / 2; + if (oldSpeed != -1) { + newSpeed = (long) MathUtils.lerp(oldSpeed, newSpeed, 0.75f); + } + oldSpeed = newSpeed; + info.speed = newSpeed; + + // Calculate remaining + if (info.total <= 0) { + info.remaining = -1; + } else if (newSpeed == 0) { + info.remaining = 300L * 24L * 60L * 60L * 1000L; // 300 days + } else { + int downloadingCount = 0; + long downloadingContentLengthSum = 0; + long totalSize = 0; + for (int i = 0, n = Math.max(mContentLengthMap.size(), mReceivedSizeMap.size()); i < n; i++) { + long contentLength = mContentLengthMap.valueAt(i); + long receivedSize = mReceivedSizeMap.valueAt(i); + downloadingCount++; + downloadingContentLengthSum += contentLength; + totalSize += contentLength - receivedSize; + } + if (downloadingCount != 0) { + totalSize += downloadingContentLengthSum * (info.total - info.downloaded - downloadingCount) / downloadingCount; + info.remaining = totalSize / newSpeed * 1000; + } + } if (mDownloadListener != null) { mDownloadListener.onDownload(info); } @@ -967,6 +1025,8 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener { } } + mBytesRead = 0; + if (!mStop) { SimpleHandler.getInstance().postDelayed(this, 2000); } diff --git a/app/src/main/java/com/hippo/ehviewer/download/DownloadService.java b/app/src/main/java/com/hippo/ehviewer/download/DownloadService.java index 3de28e3d4..aeffcae8e 100644 --- a/app/src/main/java/com/hippo/ehviewer/download/DownloadService.java +++ b/app/src/main/java/com/hippo/ehviewer/download/DownloadService.java @@ -34,6 +34,7 @@ import android.util.SparseBooleanArray; import com.hippo.ehviewer.EhApplication; import com.hippo.ehviewer.R; import com.hippo.ehviewer.client.data.GalleryInfo; +import com.hippo.util.ReadableTime; import com.hippo.yorozuya.FileUtils; import com.hippo.yorozuya.IntList; import com.hippo.yorozuya.SimpleHandler; @@ -306,10 +307,16 @@ public class DownloadService extends Service implements DownloadManager.Download speed = 0; } String text = FileUtils.humanReadableByteCount(speed, false) + "/S"; + long remaining = info.remaining; + if (remaining >= 0) { + text = getString(R.string.download_speed_text_2, text, ReadableTime.getShortTimeInterval(remaining)); + } else { + text = getString(R.string.download_speed_text, text); + } mDownloadingBuilder.setContentTitle(info.galleryInfo.title) .setContentText(text) - .setContentInfo(info.total == -1 || info.download == -1 ? null : info.download + "/" + info.total) - .setProgress(info.total, info.download, false); + .setContentInfo(info.total == -1 || info.finished == -1 ? null : info.finished + "/" + info.total) + .setProgress(info.total, info.finished, false); mDownloadingDelay.startForeground(); } diff --git a/app/src/main/java/com/hippo/ehviewer/gallery/EhGalleryProvider.java b/app/src/main/java/com/hippo/ehviewer/gallery/EhGalleryProvider.java index 12809aff2..5d99f03c0 100644 --- a/app/src/main/java/com/hippo/ehviewer/gallery/EhGalleryProvider.java +++ b/app/src/main/java/com/hippo/ehviewer/gallery/EhGalleryProvider.java @@ -133,12 +133,12 @@ public class EhGalleryProvider extends GalleryProvider implements SpiderQueen.On } @Override - public void onPageSuccess(int index, int downloaded, int total) { + public void onPageSuccess(int index, int finished, int downloaded, int total) { notifyDataChanged(index); } @Override - public void onPageFailure(int index, String error, int downloaded, int total) { + public void onPageFailure(int index, String error, int finished, int downloaded, int total) { notifyPageFailed(index, error); } diff --git a/app/src/main/java/com/hippo/ehviewer/spider/SpiderQueen.java b/app/src/main/java/com/hippo/ehviewer/spider/SpiderQueen.java index 4fed641fd..3ab7460ad 100644 --- a/app/src/main/java/com/hippo/ehviewer/spider/SpiderQueen.java +++ b/app/src/main/java/com/hippo/ehviewer/spider/SpiderQueen.java @@ -212,7 +212,7 @@ public class SpiderQueen implements Runnable { } synchronized (mSpiderListeners) { for (OnSpiderListener listener : mSpiderListeners) { - listener.onPageSuccess(index, mFinishedPages.get(), size); + listener.onPageSuccess(index, mFinishedPages.get(), mDownloadedPages.get(), size); } } } @@ -225,7 +225,7 @@ public class SpiderQueen implements Runnable { } synchronized (mSpiderListeners) { for (OnSpiderListener listener : mSpiderListeners) { - listener.onPageFailure(index, error, mFinishedPages.get(), size); + listener.onPageFailure(index, error, mFinishedPages.get(), mDownloadedPages.get(), size); } } } @@ -1210,9 +1210,9 @@ public class SpiderQueen implements Runnable { */ void onPageDownload(int index, long contentLength, long receivedSize, int bytesRead); - void onPageSuccess(int index, int downloaded, int total); + void onPageSuccess(int index, int finished, int downloaded, int total); - void onPageFailure(int index, String error, int downloaded, int total); + void onPageFailure(int index, String error, int finished, int downloaded, int total); /** * All workers end diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/DownloadScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/DownloadScene.java index 42c86287b..3b6dd6273 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/DownloadScene.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/DownloadScene.java @@ -640,14 +640,14 @@ public class DownloadScene extends ToolbarScene holder.percent.setVisibility(View.VISIBLE); holder.speed.setVisibility(View.VISIBLE); - if (info.total <= 0 || info.download < 0) { + if (info.total <= 0 || info.finished < 0) { holder.percent.setText(null); holder.progressBar.setIndeterminate(true); } else { - holder.percent.setText(info.download + "/" + info.total); + holder.percent.setText(info.finished + "/" + info.total); holder.progressBar.setIndeterminate(false); holder.progressBar.setMax(info.total); - holder.progressBar.setProgress(info.download); + holder.progressBar.setProgress(info.finished); } long speed = info.speed; if (speed < 0) { diff --git a/app/src/main/java/com/hippo/util/ReadableTime.java b/app/src/main/java/com/hippo/util/ReadableTime.java index 7c63a698a..8b2dca541 100644 --- a/app/src/main/java/com/hippo/util/ReadableTime.java +++ b/app/src/main/java/com/hippo/util/ReadableTime.java @@ -170,6 +170,24 @@ public final class ReadableTime { return sb.toString(); } + public static String getShortTimeInterval(long time) { + StringBuilder sb = new StringBuilder(); + Resources resources = sResources; + + for (int i = 0; i < SIZE; i++) { + long multiple = MULTIPLES[i]; + long quotient = time / multiple; + if (time > multiple * 1.5 || i == SIZE - 1) { + sb.append(quotient) + .append(" ") + .append(resources.getQuantityString(UNITS[i], (int) quotient)); + break; + } + } + + return sb.toString(); + } + public static String getFilenamableTime(long time) { synchronized (sDateFormatLock2) { return FILENAMABLE_DATE_FORMAT.format(new Date(time)); diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 3df4432b5..00fea6525 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -202,6 +202,8 @@ 全部开始 全部停止 EhViewer 下载服务 + %s + %1$s,%2$s 无标签 diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 8f8f18c58..5987523cd 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -202,6 +202,8 @@ 全部開始 全部停止 EhViewer 下載服務 + %s + %1$s,%2$s 無標籤 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index fc81f75dc..5031de901 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -202,6 +202,8 @@ 全部開始 全部停止 EhViewer 下載服務 + %s + %1$s,%2$s 無標籤 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4a0a07a8a..3801784c0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -244,6 +244,8 @@ Start all Stop all EhViewer Download Service + %s + %1$s, %2$s No labels diff --git a/yorozuya b/yorozuya index b064c8a43..6d4c3d943 160000 --- a/yorozuya +++ b/yorozuya @@ -1 +1 @@ -Subproject commit b064c8a431f3513cc2f21ddfd6c90ab1588f8c8c +Subproject commit 6d4c3d943b8fb1567306b7df717d8aba3913371e