package com.mercandalli.android.apps.files.file.cloud; import android.os.Handler; import android.os.Looper; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import com.mercandalli.android.library.base.precondition.Preconditions; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.nio.charset.Charset; import okhttp3.MediaType; import okhttp3.RequestBody; import okhttp3.internal.Util; import okio.BufferedSink; public class ProgressRequestBody extends RequestBody { private static final int DEFAULT_BUFFER_SIZE = 2_048; private static final int TIME_REFRESH_MS = 50; private File mFile; private long mUploadedSize; private long mTotalSize; @Nullable private UploadCallbacks mListener; private final MediaType mMediaType; private final Handler mHandler = new Handler(Looper.getMainLooper()); private final ProgressUpdater mProgressUpdater = new ProgressUpdater(); public interface UploadCallbacks { void onUploadProgressUpdate(final long progress, final long length); void onUploadError(); void onUploadFinish(); } public ProgressRequestBody(MediaType mediaType) { mMediaType = mediaType; } public ProgressRequestBody(final MediaType mediaType, final File file, @Nullable final UploadCallbacks listener) { mFile = file; mListener = listener; mMediaType = mediaType; } @Override public MediaType contentType() { return mMediaType; } @Override public void writeTo(BufferedSink sink) throws IOException { mTotalSize = mFile.length(); byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; FileInputStream in = new FileInputStream(mFile); mUploadedSize = 0; if (mListener != null) { mHandler.postDelayed(mProgressUpdater, TIME_REFRESH_MS); } try { int read; while ((read = in.read(buffer)) != -1) { mUploadedSize += read; sink.write(buffer, 0, read); } } finally { in.close(); } if (mListener != null) { mHandler.removeCallbacks(mProgressUpdater); mListener.onUploadFinish(); } } @Override public long contentLength() { if (mFile != null) { return mFile.length(); } return 0; } private class ProgressUpdater implements Runnable { public ProgressUpdater() { } @Override public void run() { if (mListener != null) { mListener.onUploadProgressUpdate(mUploadedSize, mTotalSize); } mHandler.postDelayed(mProgressUpdater, TIME_REFRESH_MS); } } /** * Returns a new request body that transmits the content of {@code file}. */ public static ProgressRequestBody create( @NonNull final MediaType contentType, @NonNull final File file, @Nullable final UploadCallbacks listener) { Preconditions.checkNotNull(contentType); Preconditions.checkNotNull(file); return new ProgressRequestBody(contentType, file, listener); } /** * Returns a new request body that transmits {@code content}. If {@code contentType} is non-null * and lacks a charset, this will use UTF-8. */ public static ProgressRequestBody create(final MediaType contentTypeParam, final String contentStr) { Charset charset; final MediaType contentType; if (contentTypeParam != null) { charset = contentTypeParam.charset(); if (charset == null) { charset = Util.UTF_8; contentType = MediaType.parse(contentTypeParam + "; charset=utf-8"); } else { contentType = contentTypeParam; } } else { throw new IllegalStateException("contentTypeParam == null"); } final byte[] content = contentStr.getBytes(charset); Util.checkOffsetAndCount(content.length, 0, content.length); return new ProgressRequestBody(contentType) { @Override public MediaType contentType() { return contentType; } @Override public long contentLength() { return content.length; } @Override public void writeTo(BufferedSink sink) throws IOException { sink.write(content, 0, content.length); } }; } }