Skip to content

Commit 1cf059c

Browse files
fix: Unfinished downloads disappear from the download list after app get killed
1 parent d719bfa commit 1cf059c

2 files changed

Lines changed: 53 additions & 15 deletions

File tree

app/src/main/java/us/shandian/giga/get/DownloadMission.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ public class DownloadMission extends Mission {
145145
public transient Thread[] threads = new Thread[0];
146146
public transient Thread init = null;
147147

148-
public Context context;
148+
public transient Context context;
149149

150150
public DownloadMission(String[] urls, StoredFileHelper storage, char kind, Postprocessing psInstance, Context context) {
151151
if (Objects.requireNonNull(urls).length < 1)
@@ -668,7 +668,8 @@ public void psContinue(boolean recover) {
668668
* @return {@code true}, if storage is invalid and cannot be used
669669
*/
670670
public boolean hasInvalidStorage() {
671-
return errCode == ERROR_PROGRESS_LOST || storage == null || !storage.existsAsFile();
671+
// Don't consider ERROR_PROGRESS_LOST as invalid storage - it can be recovered
672+
return storage == null || !storage.existsAsFile();
672673
}
673674

674675
/**

app/src/main/java/us/shandian/giga/service/DownloadManager.java

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import us.shandian.giga.util.Utility;
2222

2323
import static org.schabi.newpipe.BuildConfig.DEBUG;
24+
import static us.shandian.giga.get.DownloadMission.ERROR_NOTHING;
25+
import static us.shandian.giga.get.DownloadMission.ERROR_PROGRESS_LOST;
2426

2527
public class DownloadManager {
2628
private static final String TAG = DownloadManager.class.getSimpleName();
@@ -146,12 +148,31 @@ private void loadPendingMissions(Context ctx) {
146148
if (sub.getName().equals(".tmp")) continue;
147149

148150
DownloadMission mis = Utility.readFromFile(sub);
149-
if (mis == null || mis.isFinished() || mis.hasInvalidStorage()) {
151+
if (mis == null) {
150152
//noinspection ResultOfMethodCallIgnored
151153
sub.delete();
152154
continue;
153155
}
154156

157+
// DON'T delete missions that are truly finished - let them be moved to finished list
158+
if (mis.isFinished()) {
159+
// Move to finished missions instead of deleting
160+
setFinished(mis);
161+
//noinspection ResultOfMethodCallIgnored
162+
sub.delete();
163+
continue;
164+
}
165+
166+
// DON'T delete missions with storage issues - try to recover them
167+
if (mis.hasInvalidStorage() && mis.errCode != ERROR_PROGRESS_LOST) {
168+
// Only delete if it's truly unrecoverable (not just progress lost)
169+
if (mis.storage == null && mis.errCode != ERROR_PROGRESS_LOST) {
170+
//noinspection ResultOfMethodCallIgnored
171+
sub.delete();
172+
continue;
173+
}
174+
}
175+
155176
mis.threads = new Thread[0];
156177

157178
boolean exists;
@@ -160,28 +181,25 @@ private void loadPendingMissions(Context ctx) {
160181
exists = !mis.storage.isInvalid() && mis.storage.existsAsFile();
161182
} catch (Exception ex) {
162183
Log.e(TAG, "Failed to load the file source of " + mis.storage.toString(), ex);
163-
mis.storage.invalidate();
184+
// Don't invalidate storage immediately - try to recover first
164185
exists = false;
165186
}
166187

167188
if (mis.isPsRunning()) {
168189
if (mis.psAlgorithm.worksOnSameFile) {
169190
// Incomplete post-processing results in a corrupted download file
170-
// because the selected algorithm works on the same file to save space.
171-
// the file will be deleted if the storage API
172-
// is Java IO (avoid showing the "Save as..." dialog)
173191
if (exists && mis.storage.isDirect() && !mis.storage.delete())
174192
Log.w(TAG, "Unable to delete incomplete download file: " + sub.getPath());
175193
}
176-
177194
mis.psState = 0;
178195
mis.errCode = DownloadMission.ERROR_POSTPROCESSING_STOPPED;
179196
} else if (!exists) {
180197
tryRecover(mis);
181-
182-
// the progress is lost, reset mission state
183-
if (mis.isInitialized())
184-
mis.resetState(true, true, DownloadMission.ERROR_PROGRESS_LOST);
198+
// Keep the mission even if recovery fails - don't reset to ERROR_PROGRESS_LOST
199+
// This allows user to see the failed download and potentially retry
200+
if (mis.isInitialized() && mis.errCode == ERROR_NOTHING) {
201+
mis.resetState(true, true, ERROR_PROGRESS_LOST);
202+
}
185203
}
186204

187205
if (mis.psAlgorithm != null) {
@@ -192,6 +210,7 @@ private void loadPendingMissions(Context ctx) {
192210
mis.metadata = sub;
193211
mis.maxRetry = mPrefMaxRetry;
194212
mis.mHandler = mHandler;
213+
mis.context = ctx;
195214

196215
mMissionsPending.add(mis);
197216
}
@@ -200,6 +219,7 @@ private void loadPendingMissions(Context ctx) {
200219
Collections.sort(mMissionsPending, Comparator.comparingLong(Mission::getTimestamp));
201220
}
202221

222+
203223
/**
204224
* Start a new download mission
205225
*
@@ -446,7 +466,7 @@ boolean runMissions() {
446466
continue;
447467

448468
resumeMission(mission);
449-
if (mission.errCode != DownloadMission.ERROR_NOTHING) continue;
469+
if (mission.errCode != ERROR_NOTHING) continue;
450470

451471
if (mPrefQueueLimit) return true;
452472
flag = true;
@@ -510,6 +530,15 @@ void updateMaximumAttempts() {
510530
}
511531
}
512532

533+
public boolean canRecoverMission(DownloadMission mission) {
534+
if (mission == null) return false;
535+
536+
// Can recover missions with progress lost or storage issues
537+
return mission.errCode == ERROR_PROGRESS_LOST ||
538+
mission.storage == null ||
539+
!mission.storage.existsAsFile();
540+
}
541+
513542
public MissionState checkForExistingMission(StoredFileHelper storage) {
514543
synchronized (this) {
515544
DownloadMission pending = getPendingMission(storage);
@@ -582,8 +611,16 @@ private ArrayList<Object> getSpecialItems() {
582611
ArrayList<Mission> finished = new ArrayList<>(mMissionsFinished);
583612
List<Mission> remove = new ArrayList<>(hidden);
584613

585-
// hide missions (if required)
586-
remove.removeIf(mission -> pending.remove(mission) || finished.remove(mission));
614+
// Don't hide recoverable missions
615+
remove.removeIf(mission -> {
616+
if (mission instanceof DownloadMission) {
617+
DownloadMission dm = (DownloadMission) mission;
618+
if (canRecoverMission(dm)) {
619+
return false; // Don't remove recoverable missions
620+
}
621+
}
622+
return pending.remove(mission) || finished.remove(mission);
623+
});
587624

588625
int fakeTotal = pending.size();
589626
if (fakeTotal > 0) fakeTotal++;

0 commit comments

Comments
 (0)