Added progress updater in UploadService to show upload progress in no… (#3156)

* added progress updater in UploadService to show upload progress in notification

* formatting changes
This commit is contained in:
Ashish Kumar 2019-09-30 20:26:36 +05:30 committed by Josephine Lim
parent 41789980c7
commit f13a4d4da7
3 changed files with 116 additions and 43 deletions

View file

@ -0,0 +1,86 @@
package fr.free.nrw.commons.upload;
import java.io.IOException;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okio.Buffer;
import okio.BufferedSink;
import okio.ForwardingSink;
import okio.Okio;
import okio.Sink;
/**
* Decorates an OkHttp request body to count the number of bytes written when writing it. Can
* decorate any request body, but is most useful for tracking the upload progress of large multipart
* requests.
*
* @author Ashish Kumar
*/
public class CountingRequestBody extends RequestBody {
protected RequestBody delegate;
protected Listener listener;
protected CountingSink countingSink;
public CountingRequestBody(RequestBody delegate, Listener listener) {
this.delegate = delegate;
this.listener = listener;
}
@Override
public MediaType contentType() {
return delegate.contentType();
}
@Override
public long contentLength() {
try {
return delegate.contentLength();
} catch (IOException e) {
e.printStackTrace();
}
return -1;
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
countingSink = new CountingSink(sink);
BufferedSink bufferedSink = Okio.buffer(countingSink);
delegate.writeTo(bufferedSink);
bufferedSink.flush();
}
protected final class CountingSink extends ForwardingSink {
private long bytesWritten = 0;
public CountingSink(Sink delegate) {
super(delegate);
}
@Override
public void write(Buffer source, long byteCount) throws IOException {
super.write(source, byteCount);
bytesWritten += byteCount;
listener.onRequestProgress(bytesWritten, contentLength());
}
}
public interface Listener {
/**
* Will be triggered when write progresses
* @param bytesWritten
* @param contentLength
*/
void onRequestProgress(long bytesWritten, long contentLength);
}
}

View file

@ -1,23 +1,20 @@
package fr.free.nrw.commons.upload;
import static fr.free.nrw.commons.di.NetworkingModule.NAMED_COMMONS_CSRF;
import android.content.Context;
import android.net.Uri;
import org.wikipedia.csrf.CsrfTokenClient;
import fr.free.nrw.commons.contributions.Contribution;
import fr.free.nrw.commons.upload.UploadService.NotificationUpdateProgressListener;
import io.reactivex.Observable;
import java.io.File;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import fr.free.nrw.commons.contributions.Contribution;
import io.reactivex.Observable;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import static fr.free.nrw.commons.di.NetworkingModule.NAMED_COMMONS_CSRF;
import org.wikipedia.csrf.CsrfTokenClient;
@Singleton
public class UploadClient {
@ -31,11 +28,16 @@ public class UploadClient {
this.csrfTokenClient = csrfTokenClient;
}
Observable<UploadResult> uploadFileToStash(Context context, String filename, File file) {
RequestBody requestFile = RequestBody
Observable<UploadResult> uploadFileToStash(Context context, String filename, File file,
NotificationUpdateProgressListener notificationUpdater) {
RequestBody requestBody = RequestBody
.create(MediaType.parse(FileUtils.getMimeType(context, Uri.parse(file.getPath()))), file);
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", filename, requestFile);
CountingRequestBody countingRequestBody = new CountingRequestBody(requestBody,
(bytesWritten, contentLength) -> notificationUpdater
.onProgress(bytesWritten, contentLength));
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", filename, countingRequestBody);
RequestBody fileNameRequestBody = RequestBody.create(okhttp3.MultipartBody.FORM, filename);
RequestBody tokenRequestBody;
try {

View file

@ -8,23 +8,8 @@ import android.content.Intent;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.widget.Toast;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
import fr.free.nrw.commons.BuildConfig;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.HandlerService;
@ -40,6 +25,13 @@ import fr.free.nrw.commons.utils.CommonsDateUtil;
import fr.free.nrw.commons.wikidata.WikidataEditService;
import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
import timber.log.Timber;
public class UploadService extends HandlerService<Contribution> {
@ -80,7 +72,7 @@ public class UploadService extends HandlerService<Contribution> {
super("UploadService");
}
private class NotificationUpdateProgressListener implements MediaWikiApi.ProgressListener {
protected class NotificationUpdateProgressListener implements MediaWikiApi.ProgressListener {
String notificationTag;
boolean notificationTitleChanged;
@ -202,29 +194,20 @@ public class UploadService extends HandlerService<Contribution> {
@SuppressLint("CheckResult")
private void uploadContribution(Contribution contribution) {
InputStream fileInputStream;
Uri localUri = contribution.getLocalUri();
if (localUri == null || localUri.getPath() == null) {
Timber.d("localUri/path is null");
return;
}
String notificationTag = localUri.toString();
File file1;
try {
file1 = new File(localUri.getPath());
fileInputStream = new FileInputStream(file1);
} catch (FileNotFoundException e) {
Timber.d("File not found");
Toast fileNotFound = Toast.makeText(this, R.string.upload_failed, Toast.LENGTH_LONG);
fileNotFound.show();
return;
}
File localFile = new File(localUri.getPath());
Timber.d("Before execution!");
curNotification.setContentTitle(getString(R.string.upload_progress_notification_title_start, contribution.getDisplayTitle()))
.setContentText(getResources().getQuantityString(R.plurals.uploads_pending_notification_indicator, toUpload, toUpload))
.setTicker(getString(R.string.upload_progress_notification_title_in_progress, contribution.getDisplayTitle()));
notificationManager.notify(notificationTag, NOTIFICATION_UPLOAD_IN_PROGRESS, curNotification.build());
notificationManager
.notify(notificationTag, NOTIFICATION_UPLOAD_IN_PROGRESS, curNotification.build());
String filename = contribution.getFilename();
@ -235,7 +218,9 @@ public class UploadService extends HandlerService<Contribution> {
);
Observable.fromCallable(() -> "Temp_" + contribution.hashCode() + filename)
.flatMap(stashFilename -> uploadClient.uploadFileToStash(getApplicationContext(), stashFilename, file1))
.flatMap(stashFilename -> uploadClient
.uploadFileToStash(getApplicationContext(), stashFilename, localFile,
notificationUpdater))
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.doFinally(() -> {
@ -250,7 +235,7 @@ public class UploadService extends HandlerService<Contribution> {
}
})
.flatMap(uploadStash -> {
notificationManager.cancel(NOTIFICATION_UPLOAD_IN_PROGRESS);
notificationManager.cancel(notificationTag, NOTIFICATION_UPLOAD_IN_PROGRESS);
Timber.d("Stash upload response 1 is %s", uploadStash.toString());
@ -293,7 +278,7 @@ public class UploadService extends HandlerService<Contribution> {
}
}, throwable -> {
Timber.w(throwable, "Exception during upload");
notificationManager.cancel(NOTIFICATION_UPLOAD_IN_PROGRESS);
notificationManager.cancel(notificationTag, NOTIFICATION_UPLOAD_IN_PROGRESS);
showFailedNotification(contribution);
});
}