Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add java docs for methods added in this class. :)


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);
}

}
26 changes: 14 additions & 12 deletions app/src/main/java/fr/free/nrw/commons/upload/UploadClient.java
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -31,11 +28,16 @@ public UploadClient(UploadInterface uploadInterface, @Named(NAMED_COMMONS_CSRF)
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 {
Expand Down
47 changes: 16 additions & 31 deletions app/src/main/java/fr/free/nrw/commons/upload/UploadService.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,8 @@
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;
Expand All @@ -40,6 +25,13 @@
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> {
Expand Down Expand Up @@ -80,7 +72,7 @@ public UploadService() {
super("UploadService");
}

private class NotificationUpdateProgressListener implements MediaWikiApi.ProgressListener {
protected class NotificationUpdateProgressListener implements MediaWikiApi.ProgressListener {

String notificationTag;
boolean notificationTitleChanged;
Expand Down Expand Up @@ -202,29 +194,20 @@ private NotificationCompat.Builder getNotificationBuilder(String channelId) {

@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();

Expand All @@ -235,7 +218,9 @@ private void uploadContribution(Contribution 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(() -> {
Expand All @@ -250,7 +235,7 @@ private void uploadContribution(Contribution 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());

Expand Down Expand Up @@ -293,7 +278,7 @@ private void uploadContribution(Contribution contribution) {
}
}, throwable -> {
Timber.w(throwable, "Exception during upload");
notificationManager.cancel(NOTIFICATION_UPLOAD_IN_PROGRESS);
notificationManager.cancel(notificationTag, NOTIFICATION_UPLOAD_IN_PROGRESS);
showFailedNotification(contribution);
});
}
Expand Down