Skip to content

Commit f13a4d4

Browse files
ashishkumar468misaochan
authored andcommitted
Added progress updater in UploadService to show upload progress in no… (commons-app#3156)
* added progress updater in UploadService to show upload progress in notification * formatting changes
1 parent 4178998 commit f13a4d4

File tree

3 files changed

+116
-43
lines changed

3 files changed

+116
-43
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package fr.free.nrw.commons.upload;
2+
3+
4+
import java.io.IOException;
5+
import okhttp3.MediaType;
6+
import okhttp3.RequestBody;
7+
import okio.Buffer;
8+
import okio.BufferedSink;
9+
import okio.ForwardingSink;
10+
import okio.Okio;
11+
import okio.Sink;
12+
13+
/**
14+
* Decorates an OkHttp request body to count the number of bytes written when writing it. Can
15+
* decorate any request body, but is most useful for tracking the upload progress of large multipart
16+
* requests.
17+
*
18+
* @author Ashish Kumar
19+
*/
20+
public class CountingRequestBody extends RequestBody {
21+
22+
protected RequestBody delegate;
23+
protected Listener listener;
24+
25+
protected CountingSink countingSink;
26+
27+
public CountingRequestBody(RequestBody delegate, Listener listener) {
28+
this.delegate = delegate;
29+
this.listener = listener;
30+
}
31+
32+
@Override
33+
public MediaType contentType() {
34+
return delegate.contentType();
35+
}
36+
37+
@Override
38+
public long contentLength() {
39+
try {
40+
return delegate.contentLength();
41+
} catch (IOException e) {
42+
e.printStackTrace();
43+
}
44+
return -1;
45+
}
46+
47+
@Override
48+
public void writeTo(BufferedSink sink) throws IOException {
49+
50+
countingSink = new CountingSink(sink);
51+
BufferedSink bufferedSink = Okio.buffer(countingSink);
52+
53+
delegate.writeTo(bufferedSink);
54+
55+
bufferedSink.flush();
56+
}
57+
58+
protected final class CountingSink extends ForwardingSink {
59+
60+
private long bytesWritten = 0;
61+
62+
public CountingSink(Sink delegate) {
63+
super(delegate);
64+
}
65+
66+
@Override
67+
public void write(Buffer source, long byteCount) throws IOException {
68+
super.write(source, byteCount);
69+
70+
bytesWritten += byteCount;
71+
listener.onRequestProgress(bytesWritten, contentLength());
72+
}
73+
74+
}
75+
76+
public interface Listener {
77+
78+
/**
79+
* Will be triggered when write progresses
80+
* @param bytesWritten
81+
* @param contentLength
82+
*/
83+
void onRequestProgress(long bytesWritten, long contentLength);
84+
}
85+
86+
}

app/src/main/java/fr/free/nrw/commons/upload/UploadClient.java

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,20 @@
11
package fr.free.nrw.commons.upload;
22

3+
import static fr.free.nrw.commons.di.NetworkingModule.NAMED_COMMONS_CSRF;
4+
35
import android.content.Context;
46
import android.net.Uri;
5-
6-
import org.wikipedia.csrf.CsrfTokenClient;
7-
7+
import fr.free.nrw.commons.contributions.Contribution;
8+
import fr.free.nrw.commons.upload.UploadService.NotificationUpdateProgressListener;
9+
import io.reactivex.Observable;
810
import java.io.File;
9-
1011
import javax.inject.Inject;
1112
import javax.inject.Named;
1213
import javax.inject.Singleton;
13-
14-
import fr.free.nrw.commons.contributions.Contribution;
15-
import io.reactivex.Observable;
1614
import okhttp3.MediaType;
1715
import okhttp3.MultipartBody;
1816
import okhttp3.RequestBody;
19-
20-
import static fr.free.nrw.commons.di.NetworkingModule.NAMED_COMMONS_CSRF;
17+
import org.wikipedia.csrf.CsrfTokenClient;
2118

2219
@Singleton
2320
public class UploadClient {
@@ -31,11 +28,16 @@ public UploadClient(UploadInterface uploadInterface, @Named(NAMED_COMMONS_CSRF)
3128
this.csrfTokenClient = csrfTokenClient;
3229
}
3330

34-
Observable<UploadResult> uploadFileToStash(Context context, String filename, File file) {
35-
RequestBody requestFile = RequestBody
31+
Observable<UploadResult> uploadFileToStash(Context context, String filename, File file,
32+
NotificationUpdateProgressListener notificationUpdater) {
33+
RequestBody requestBody = RequestBody
3634
.create(MediaType.parse(FileUtils.getMimeType(context, Uri.parse(file.getPath()))), file);
3735

38-
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", filename, requestFile);
36+
CountingRequestBody countingRequestBody = new CountingRequestBody(requestBody,
37+
(bytesWritten, contentLength) -> notificationUpdater
38+
.onProgress(bytesWritten, contentLength));
39+
40+
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", filename, countingRequestBody);
3941
RequestBody fileNameRequestBody = RequestBody.create(okhttp3.MultipartBody.FORM, filename);
4042
RequestBody tokenRequestBody;
4143
try {

app/src/main/java/fr/free/nrw/commons/upload/UploadService.java

Lines changed: 16 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,8 @@
88
import android.graphics.BitmapFactory;
99
import android.net.Uri;
1010
import android.os.Bundle;
11-
import android.widget.Toast;
12-
1311
import androidx.core.app.NotificationCompat;
1412
import androidx.core.app.NotificationManagerCompat;
15-
16-
import java.io.File;
17-
import java.io.FileInputStream;
18-
import java.io.FileNotFoundException;
19-
import java.io.IOException;
20-
import java.io.InputStream;
21-
import java.util.HashSet;
22-
import java.util.Set;
23-
import java.util.regex.Matcher;
24-
import java.util.regex.Pattern;
25-
26-
import javax.inject.Inject;
27-
2813
import fr.free.nrw.commons.BuildConfig;
2914
import fr.free.nrw.commons.CommonsApplication;
3015
import fr.free.nrw.commons.HandlerService;
@@ -40,6 +25,13 @@
4025
import fr.free.nrw.commons.wikidata.WikidataEditService;
4126
import io.reactivex.Observable;
4227
import io.reactivex.schedulers.Schedulers;
28+
import java.io.File;
29+
import java.io.IOException;
30+
import java.util.HashSet;
31+
import java.util.Set;
32+
import java.util.regex.Matcher;
33+
import java.util.regex.Pattern;
34+
import javax.inject.Inject;
4335
import timber.log.Timber;
4436

4537
public class UploadService extends HandlerService<Contribution> {
@@ -80,7 +72,7 @@ public UploadService() {
8072
super("UploadService");
8173
}
8274

83-
private class NotificationUpdateProgressListener implements MediaWikiApi.ProgressListener {
75+
protected class NotificationUpdateProgressListener implements MediaWikiApi.ProgressListener {
8476

8577
String notificationTag;
8678
boolean notificationTitleChanged;
@@ -202,29 +194,20 @@ private NotificationCompat.Builder getNotificationBuilder(String channelId) {
202194

203195
@SuppressLint("CheckResult")
204196
private void uploadContribution(Contribution contribution) {
205-
InputStream fileInputStream;
206197
Uri localUri = contribution.getLocalUri();
207198
if (localUri == null || localUri.getPath() == null) {
208199
Timber.d("localUri/path is null");
209200
return;
210201
}
211202
String notificationTag = localUri.toString();
212-
File file1;
213-
try {
214-
file1 = new File(localUri.getPath());
215-
fileInputStream = new FileInputStream(file1);
216-
} catch (FileNotFoundException e) {
217-
Timber.d("File not found");
218-
Toast fileNotFound = Toast.makeText(this, R.string.upload_failed, Toast.LENGTH_LONG);
219-
fileNotFound.show();
220-
return;
221-
}
203+
File localFile = new File(localUri.getPath());
222204

223205
Timber.d("Before execution!");
224206
curNotification.setContentTitle(getString(R.string.upload_progress_notification_title_start, contribution.getDisplayTitle()))
225207
.setContentText(getResources().getQuantityString(R.plurals.uploads_pending_notification_indicator, toUpload, toUpload))
226208
.setTicker(getString(R.string.upload_progress_notification_title_in_progress, contribution.getDisplayTitle()));
227-
notificationManager.notify(notificationTag, NOTIFICATION_UPLOAD_IN_PROGRESS, curNotification.build());
209+
notificationManager
210+
.notify(notificationTag, NOTIFICATION_UPLOAD_IN_PROGRESS, curNotification.build());
228211

229212
String filename = contribution.getFilename();
230213

@@ -235,7 +218,9 @@ private void uploadContribution(Contribution contribution) {
235218
);
236219

237220
Observable.fromCallable(() -> "Temp_" + contribution.hashCode() + filename)
238-
.flatMap(stashFilename -> uploadClient.uploadFileToStash(getApplicationContext(), stashFilename, file1))
221+
.flatMap(stashFilename -> uploadClient
222+
.uploadFileToStash(getApplicationContext(), stashFilename, localFile,
223+
notificationUpdater))
239224
.subscribeOn(Schedulers.io())
240225
.observeOn(Schedulers.io())
241226
.doFinally(() -> {
@@ -250,7 +235,7 @@ private void uploadContribution(Contribution contribution) {
250235
}
251236
})
252237
.flatMap(uploadStash -> {
253-
notificationManager.cancel(NOTIFICATION_UPLOAD_IN_PROGRESS);
238+
notificationManager.cancel(notificationTag, NOTIFICATION_UPLOAD_IN_PROGRESS);
254239

255240
Timber.d("Stash upload response 1 is %s", uploadStash.toString());
256241

@@ -293,7 +278,7 @@ private void uploadContribution(Contribution contribution) {
293278
}
294279
}, throwable -> {
295280
Timber.w(throwable, "Exception during upload");
296-
notificationManager.cancel(NOTIFICATION_UPLOAD_IN_PROGRESS);
281+
notificationManager.cancel(notificationTag, NOTIFICATION_UPLOAD_IN_PROGRESS);
297282
showFailedNotification(contribution);
298283
});
299284
}

0 commit comments

Comments
 (0)