Fix ANR when uploading large video files. Fix uploading gif as image.

This commit is contained in:
Alex Ning 2020-07-16 17:42:07 +08:00
parent 7742a19abd
commit 2d002b42d9
7 changed files with 176 additions and 80 deletions

View File

@ -50,6 +50,7 @@ import ml.docilealligator.infinityforreddit.AsyncTask.LoadSubredditIconAsyncTask
import ml.docilealligator.infinityforreddit.BottomSheetFragment.FlairBottomSheetFragment;
import ml.docilealligator.infinityforreddit.CustomTheme.CustomThemeWrapper;
import ml.docilealligator.infinityforreddit.Event.SubmitImagePostEvent;
import ml.docilealligator.infinityforreddit.Event.SubmitVideoOrGifPostEvent;
import ml.docilealligator.infinityforreddit.Event.SwitchAccountEvent;
import ml.docilealligator.infinityforreddit.Flair;
import ml.docilealligator.infinityforreddit.Infinity;
@ -518,7 +519,12 @@ public class PostImageActivity extends BaseActivity implements FlairBottomSheetF
intent.putExtra(SubmitPostService.EXTRA_FLAIR, flair);
intent.putExtra(SubmitPostService.EXTRA_IS_SPOILER, isSpoiler);
intent.putExtra(SubmitPostService.EXTRA_IS_NSFW, isNSFW);
intent.putExtra(SubmitPostService.EXTRA_POST_TYPE, SubmitPostService.EXTRA_POST_TYPE_IMAGE);
String mimeType = getContentResolver().getType(imageUri);
if (mimeType != null && mimeType.contains("gif")) {
intent.putExtra(SubmitPostService.EXTRA_POST_TYPE, SubmitPostService.EXTRA_POST_TYPE_VIDEO);
} else {
intent.putExtra(SubmitPostService.EXTRA_POST_TYPE, SubmitPostService.EXTRA_POST_TYPE_IMAGE);
}
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@ -643,4 +649,29 @@ public class PostImageActivity extends BaseActivity implements FlairBottomSheetF
}
}
}
@Subscribe
public void onSubmitVideoOrGifPostEvent(SubmitVideoOrGifPostEvent submitVideoOrGifPostEvent) {
isPosting = false;
mPostingSnackbar.dismiss();
mMemu.findItem(R.id.action_send_post_image_activity).setEnabled(true);
mMemu.findItem(R.id.action_send_post_image_activity).getIcon().setAlpha(255);
if (submitVideoOrGifPostEvent.postSuccess) {
Intent intent = new Intent(this, ViewUserDetailActivity.class);
intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY,
mAccountName);
startActivity(intent);
finish();
} else if (submitVideoOrGifPostEvent.errorProcessingVideoOrGif) {
Snackbar.make(coordinatorLayout, R.string.error_processing_image, Snackbar.LENGTH_SHORT).show();
} else {
if (submitVideoOrGifPostEvent.errorMessage == null || submitVideoOrGifPostEvent.errorMessage.equals("")) {
Snackbar.make(coordinatorLayout, R.string.post_failed, Snackbar.LENGTH_SHORT).show();
} else {
Snackbar.make(coordinatorLayout, submitVideoOrGifPostEvent.errorMessage.substring(0, 1).toUpperCase()
+ submitVideoOrGifPostEvent.errorMessage.substring(1), Snackbar.LENGTH_SHORT).show();
}
}
}
}

View File

@ -51,7 +51,7 @@ import ml.docilealligator.infinityforreddit.AsyncTask.GetCurrentAccountAsyncTask
import ml.docilealligator.infinityforreddit.AsyncTask.LoadSubredditIconAsyncTask;
import ml.docilealligator.infinityforreddit.BottomSheetFragment.FlairBottomSheetFragment;
import ml.docilealligator.infinityforreddit.CustomTheme.CustomThemeWrapper;
import ml.docilealligator.infinityforreddit.Event.SubmitVideoPostEvent;
import ml.docilealligator.infinityforreddit.Event.SubmitVideoOrGifPostEvent;
import ml.docilealligator.infinityforreddit.Event.SwitchAccountEvent;
import ml.docilealligator.infinityforreddit.Flair;
import ml.docilealligator.infinityforreddit.Infinity;
@ -652,26 +652,26 @@ public class PostVideoActivity extends BaseActivity implements FlairBottomSheetF
}
@Subscribe
public void onSubmitVideoPostEvent(SubmitVideoPostEvent submitVideoPostEvent) {
public void onSubmitVideoPostEvent(SubmitVideoOrGifPostEvent submitVideoOrGifPostEvent) {
isPosting = false;
mPostingSnackbar.dismiss();
mMemu.findItem(R.id.action_send_post_video_activity).setEnabled(true);
mMemu.findItem(R.id.action_send_post_video_activity).getIcon().setAlpha(255);
if (submitVideoPostEvent.postSuccess) {
if (submitVideoOrGifPostEvent.postSuccess) {
Intent intent = new Intent(this, ViewUserDetailActivity.class);
intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY,
mAccountName);
startActivity(intent);
finish();
} else if (submitVideoPostEvent.errorProcessingVideo) {
} else if (submitVideoOrGifPostEvent.errorProcessingVideoOrGif) {
Snackbar.make(coordinatorLayout, R.string.error_processing_video, Snackbar.LENGTH_SHORT).show();
} else {
if (submitVideoPostEvent.errorMessage == null || submitVideoPostEvent.errorMessage.equals("")) {
if (submitVideoOrGifPostEvent.errorMessage == null || submitVideoOrGifPostEvent.errorMessage.equals("")) {
Snackbar.make(coordinatorLayout, R.string.post_failed, Snackbar.LENGTH_SHORT).show();
} else {
Snackbar.make(coordinatorLayout, submitVideoPostEvent.errorMessage.substring(0, 1).toUpperCase()
+ submitVideoPostEvent.errorMessage.substring(1), Snackbar.LENGTH_SHORT).show();
Snackbar.make(coordinatorLayout, submitVideoOrGifPostEvent.errorMessage.substring(0, 1).toUpperCase()
+ submitVideoOrGifPostEvent.errorMessage.substring(1), Snackbar.LENGTH_SHORT).show();
}
}
}

View File

@ -0,0 +1,13 @@
package ml.docilealligator.infinityforreddit.Event;
public class SubmitVideoOrGifPostEvent {
public boolean postSuccess;
public boolean errorProcessingVideoOrGif;
public String errorMessage;
public SubmitVideoOrGifPostEvent(boolean postSuccess, boolean errorProcessingVideoOrGif, String errorMessage) {
this.postSuccess = postSuccess;
this.errorProcessingVideoOrGif = errorProcessingVideoOrGif;
this.errorMessage = errorMessage;
}
}

View File

@ -1,13 +0,0 @@
package ml.docilealligator.infinityforreddit.Event;
public class SubmitVideoPostEvent {
public boolean postSuccess;
public boolean errorProcessingVideo;
public String errorMessage;
public SubmitVideoPostEvent(boolean postSuccess, boolean errorProcessingVideo, String errorMessage) {
this.postSuccess = postSuccess;
this.errorProcessingVideo = errorProcessingVideo;
this.errorMessage = errorMessage;
}
}

View File

@ -14,6 +14,7 @@ import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.HashMap;
@ -22,8 +23,8 @@ import java.util.Map;
import ml.docilealligator.infinityforreddit.API.RedditAPI;
import ml.docilealligator.infinityforreddit.Flair;
import ml.docilealligator.infinityforreddit.Utils.JSONUtils;
import ml.docilealligator.infinityforreddit.Utils.APIUtils;
import ml.docilealligator.infinityforreddit.Utils.JSONUtils;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
@ -63,7 +64,7 @@ public class SubmitPost {
public static void submitVideoPost(Retrofit oauthRetrofit, Retrofit uploadMediaRetrofit,
Retrofit uploadVideoRetrofit, String accessToken,
Locale locale, String subredditName, String title, byte[] buffer, String mimeType,
Locale locale, String subredditName, String title, File buffer, String mimeType,
Bitmap posterBitmap, Flair flair, boolean isSpoiler, boolean isNSFW,
SubmitPostListener submitPostListener) {
RedditAPI api = oauthRetrofit.create(RedditAPI.class);
@ -82,7 +83,7 @@ public class SubmitPost {
new ParseJSONResponseFromAWSAsyncTask(response.body(), new ParseJSONResponseFromAWSAsyncTask.ParseJSONResponseFromAWSListener() {
@Override
public void parseSuccessful(Map<String, RequestBody> nameValuePairsMap) {
RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), buffer);
RequestBody fileBody = RequestBody.create(buffer, MediaType.parse("application/octet-stream"));
MultipartBody.Part fileToUpload = MultipartBody.Part.createFormData("file", "post_video." + fileType, fileBody);
RedditAPI uploadVideoToAWSApi;

View File

@ -8,9 +8,9 @@ import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.widget.Toast;
import androidx.annotation.NonNull;
@ -24,8 +24,11 @@ import com.bumptech.glide.request.transition.Transition;
import org.greenrobot.eventbus.EventBus;
import java.io.FileInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.inject.Inject;
import javax.inject.Named;
@ -33,7 +36,7 @@ import javax.inject.Named;
import ml.docilealligator.infinityforreddit.CustomTheme.CustomThemeWrapper;
import ml.docilealligator.infinityforreddit.Event.SubmitImagePostEvent;
import ml.docilealligator.infinityforreddit.Event.SubmitTextOrLinkPostEvent;
import ml.docilealligator.infinityforreddit.Event.SubmitVideoPostEvent;
import ml.docilealligator.infinityforreddit.Event.SubmitVideoOrGifPostEvent;
import ml.docilealligator.infinityforreddit.Flair;
import ml.docilealligator.infinityforreddit.Infinity;
import ml.docilealligator.infinityforreddit.NotificationUtils;
@ -196,68 +199,128 @@ public class SubmitPostService extends Service {
}
private void submitVideoPost() {
try (ParcelFileDescriptor pfd = getContentResolver().openFileDescriptor(mediaUri, "r")) {
if (pfd != null) {
FileInputStream in = new FileInputStream(pfd.getFileDescriptor());
byte[] buffer;
buffer = new byte[in.available()];
while (in.read(buffer) != -1) ;
Glide.with(this)
.asBitmap()
.load(mediaUri)
.into(new CustomTarget<Bitmap>() {
@Override
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
String type = getContentResolver().getType(mediaUri);
if (type != null) {
SubmitPost.submitVideoPost(mOauthRetrofit, mUploadMediaRetrofit, mUploadVideoRetrofit,
mAccessToken, getResources().getConfiguration().locale, subredditName, title,
buffer, type, resource, flair, isSpoiler, isNSFW,
new SubmitPost.SubmitPostListener() {
@Override
public void submitSuccessful(Post post) {
EventBus.getDefault().post(new SubmitVideoPostEvent(true, false, null));
Toast.makeText(SubmitPostService.this, R.string.video_is_processing, Toast.LENGTH_SHORT).show();
stopService();
}
@Override
public void submitFailed(@Nullable String errorMessage) {
EventBus.getDefault().post(new SubmitVideoPostEvent(false, false, errorMessage));
stopService();
}
});
} else {
EventBus.getDefault().post(new SubmitVideoPostEvent(false, true, null));
}
}
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
EventBus.getDefault().post(new SubmitVideoPostEvent(false, true, null));
stopService();
}
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
}
});
try {
InputStream in = getContentResolver().openInputStream(mediaUri);
String type = getContentResolver().getType(mediaUri);
String cacheFilePath;
if (type != null && type.contains("gif")) {
cacheFilePath = getExternalCacheDir() + "/" + mediaUri.getLastPathSegment() + ".gif";
} else {
EventBus.getDefault().post(new SubmitVideoPostEvent(false, true, null));
cacheFilePath = getExternalCacheDir() + "/" + mediaUri.getLastPathSegment() + ".mp4";
}
new CopyFileToCacheAsyncTask(in, cacheFilePath,
new CopyFileToCacheAsyncTask.CopyFileToCacheAsyncTaskListener() {
@Override
public void success() {
Glide.with(SubmitPostService.this)
.asBitmap()
.load(mediaUri)
.into(new CustomTarget<Bitmap>() {
@Override
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
if (type != null) {
SubmitPost.submitVideoPost(mOauthRetrofit, mUploadMediaRetrofit, mUploadVideoRetrofit,
mAccessToken, getResources().getConfiguration().locale, subredditName, title,
new File(cacheFilePath), type, resource, flair, isSpoiler, isNSFW,
new SubmitPost.SubmitPostListener() {
@Override
public void submitSuccessful(Post post) {
EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(true, false, null));
if (type.contains("gif")) {
Toast.makeText(SubmitPostService.this, R.string.gif_is_processing, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(SubmitPostService.this, R.string.video_is_processing, Toast.LENGTH_SHORT).show();
}
stopService();
}
@Override
public void submitFailed(@Nullable String errorMessage) {
EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, false, errorMessage));
stopService();
}
});
} else {
EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, true, null));
}
}
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, true, null));
stopService();
}
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
}
});
}
@Override
public void failed() {
EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, true, null));
stopService();
}
}).execute();
} catch (IOException e) {
e.printStackTrace();
EventBus.getDefault().post(new SubmitVideoPostEvent(false, true, null));
EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, true, null));
stopService();
}
}
private static class CopyFileToCacheAsyncTask extends AsyncTask<Void, Void, Void> {
private InputStream fileInputStream;
private String destinationFilePath;
private CopyFileToCacheAsyncTaskListener copyFileToCacheAsyncTaskListener;
private boolean parseFailed = false;
interface CopyFileToCacheAsyncTaskListener {
void success();
void failed();
}
public CopyFileToCacheAsyncTask(InputStream fileInputStream, String destinationFilePath, CopyFileToCacheAsyncTaskListener copyFileToCacheAsyncTaskListener) {
this.fileInputStream = fileInputStream;
this.destinationFilePath = destinationFilePath;
this.copyFileToCacheAsyncTaskListener = copyFileToCacheAsyncTaskListener;
}
@Override
protected Void doInBackground(Void... voids) {
try (OutputStream out = new FileOutputStream(destinationFilePath)) {
byte[] buf = new byte[2048];
int len;
while ((len = fileInputStream.read(buf)) > 0) {
out.write(buf, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
parseFailed = true;
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
if (parseFailed) {
copyFileToCacheAsyncTaskListener.failed();
} else {
copyFileToCacheAsyncTaskListener.success();
}
}
}
private void stopService() {
stopForeground(true);
stopSelf();

View File

@ -209,6 +209,7 @@
<string name="video_is_processing">Video is processing. Please wait.</string>
<string name="image_is_processing">Image is processing. Please wait.</string>
<string name="gif_is_processing">Gif is processing. Please wait.</string>
<string name="flair">Flair</string>
<string name="spoiler">Spoiler</string>