Rewrite SubmitPostService to run the service in a background thread.

This commit is contained in:
Alex Ning 2021-01-26 10:36:38 +08:00
parent 7ca511d3f1
commit b6c00df82f
2 changed files with 273 additions and 480 deletions

View File

@ -1,9 +1,7 @@
package ml.docilealligator.infinityforreddit.post;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.json.JSONArray;
@ -21,15 +19,14 @@ import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import ml.docilealligator.infinityforreddit.apis.RedditAPI;
import ml.docilealligator.infinityforreddit.Flair;
import ml.docilealligator.infinityforreddit.apis.RedditAPI;
import ml.docilealligator.infinityforreddit.utils.APIUtils;
import ml.docilealligator.infinityforreddit.utils.JSONUtils;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
@ -38,33 +35,31 @@ public class SubmitPost {
Locale locale, String subredditName, String title, String content,
Flair flair, boolean isSpoiler, boolean isNSFW, String kind,
SubmitPostListener submitPostListener) {
submitPost(oauthRetrofit, accessToken, locale, subredditName, title, content,
submitPost(oauthRetrofit, accessToken, subredditName, title, content,
flair, isSpoiler, isNSFW, kind, null, submitPostListener);
}
public static void submitImagePost(Retrofit oauthRetrofit, Retrofit uploadMediaRetrofit,
String accessToken, Locale locale,
String subredditName, String title, Bitmap image, Flair flair,
boolean isSpoiler, boolean isNSFW, SubmitPostListener submitPostListener) {
uploadImage(oauthRetrofit, uploadMediaRetrofit, accessToken, image,
new UploadImageListener() {
@Override
public void uploaded(String imageUrl) {
submitPost(oauthRetrofit, accessToken, locale,
subredditName, title, imageUrl, flair, isSpoiler, isNSFW,
APIUtils.KIND_IMAGE, null, submitPostListener);
}
@Override
public void uploadFailed(@Nullable String errorMessage) {
submitPostListener.submitFailed(errorMessage);
}
});
String accessToken, String subredditName, String title, Bitmap image,
Flair flair, boolean isSpoiler, boolean isNSFW, SubmitPostListener submitPostListener) {
try {
String imageUrlOrError = uploadImage(oauthRetrofit, uploadMediaRetrofit, accessToken, image);
if (imageUrlOrError != null && !imageUrlOrError.startsWith("Error: ")) {
submitPost(oauthRetrofit, accessToken,
subredditName, title, imageUrlOrError, flair, isSpoiler, isNSFW,
APIUtils.KIND_IMAGE, null, submitPostListener);
} else {
submitPostListener.submitFailed(imageUrlOrError);
}
} catch (IOException | JSONException | XmlPullParserException e) {
e.printStackTrace();
submitPostListener.submitFailed(e.getMessage());
}
}
public static void submitVideoPost(Retrofit oauthRetrofit, Retrofit uploadMediaRetrofit,
Retrofit uploadVideoRetrofit, String accessToken,
Locale locale, String subredditName, String title, File buffer, String mimeType,
String subredditName, String title, File buffer, String mimeType,
Bitmap posterBitmap, Flair flair, boolean isSpoiler, boolean isNSFW,
SubmitPostListener submitPostListener) {
RedditAPI api = oauthRetrofit.create(RedditAPI.class);
@ -76,97 +71,64 @@ public class SubmitPost {
uploadImageParams.put(APIUtils.MIMETYPE_KEY, mimeType);
Call<String> uploadImageCall = api.uploadImage(APIUtils.getOAuthHeader(accessToken), uploadImageParams);
uploadImageCall.enqueue(new Callback<String>() {
@Override
public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) {
if (response.isSuccessful()) {
new ParseJSONResponseFromAWSAsyncTask(response.body(), new ParseJSONResponseFromAWSAsyncTask.ParseJSONResponseFromAWSListener() {
@Override
public void parseSuccessful(Map<String, RequestBody> nameValuePairsMap) {
RequestBody fileBody = RequestBody.create(buffer, MediaType.parse("application/octet-stream"));
MultipartBody.Part fileToUpload = MultipartBody.Part.createFormData("file", "post_video." + fileType, fileBody);
try {
Response<String> uploadImageResponse = uploadImageCall.execute();
if (uploadImageResponse.isSuccessful()) {
Map<String, RequestBody> nameValuePairsMap = parseJSONResponseFromAWS(uploadImageResponse.body());
RedditAPI uploadVideoToAWSApi;
if (fileType.equals("gif")) {
uploadVideoToAWSApi = uploadMediaRetrofit.create(RedditAPI.class);
} else {
uploadVideoToAWSApi = uploadVideoRetrofit.create(RedditAPI.class);
}
Call<String> uploadMediaToAWS = uploadVideoToAWSApi.uploadMediaToAWS(nameValuePairsMap, fileToUpload);
RequestBody fileBody = RequestBody.create(buffer, MediaType.parse("application/octet-stream"));
MultipartBody.Part fileToUpload = MultipartBody.Part.createFormData("file", "post_video." + fileType, fileBody);
uploadMediaToAWS.enqueue(new Callback<String>() {
@Override
public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) {
if (response.isSuccessful()) {
new ParseXMLReponseFromAWSAsyncTask(response.body(), new ParseXMLReponseFromAWSAsyncTask.ParseXMLResponseFromAWSListener() {
@Override
public void parseSuccessful(String url) {
uploadImage(oauthRetrofit, uploadMediaRetrofit, accessToken,
posterBitmap, new UploadImageListener() {
@Override
public void uploaded(String imageUrl) {
if (fileType.equals("gif")) {
submitPost(oauthRetrofit, accessToken, locale,
subredditName, title, url, flair, isSpoiler, isNSFW,
APIUtils.KIND_VIDEOGIF, imageUrl, submitPostListener);
} else {
submitPost(oauthRetrofit, accessToken, locale,
subredditName, title, url, flair, isSpoiler, isNSFW,
APIUtils.KIND_VIDEO, imageUrl, submitPostListener);
}
}
@Override
public void uploadFailed(@Nullable String errorMessage) {
submitPostListener.submitFailed(errorMessage);
}
});
}
@Override
public void parseFailed() {
submitPostListener.submitFailed(null);
}
}).execute();
} else {
submitPostListener.submitFailed(response.message());
}
}
@Override
public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
submitPostListener.submitFailed(t.getMessage());
}
});
}
@Override
public void parseFailed() {
submitPostListener.submitFailed(null);
}
}).execute();
RedditAPI uploadVideoToAWSApi;
if (fileType.equals("gif")) {
uploadVideoToAWSApi = uploadMediaRetrofit.create(RedditAPI.class);
} else {
submitPostListener.submitFailed(response.message());
uploadVideoToAWSApi = uploadVideoRetrofit.create(RedditAPI.class);
}
Call<String> uploadMediaToAWS = uploadVideoToAWSApi.uploadMediaToAWS(nameValuePairsMap, fileToUpload);
Response<String> uploadMediaToAWSResponse = uploadMediaToAWS.execute();
if (uploadMediaToAWSResponse.isSuccessful()) {
String url = parseXMLResponseFromAWS(uploadMediaToAWSResponse.body());
if (url == null) {
submitPostListener.submitFailed(null);
return;
}
String imageUrlOrError = uploadImage(oauthRetrofit, uploadMediaRetrofit, accessToken, posterBitmap);
if (imageUrlOrError != null && !imageUrlOrError.startsWith("Error: ")) {
if (fileType.equals("gif")) {
submitPost(oauthRetrofit, accessToken,
subredditName, title, url, flair, isSpoiler, isNSFW,
APIUtils.KIND_VIDEOGIF, imageUrlOrError, submitPostListener);
} else {
submitPost(oauthRetrofit, accessToken,
subredditName, title, url, flair, isSpoiler, isNSFW,
APIUtils.KIND_VIDEO, imageUrlOrError, submitPostListener);
}
} else {
submitPostListener.submitFailed(imageUrlOrError);
}
} else {
submitPostListener.submitFailed(uploadMediaToAWSResponse.code() + " " + uploadMediaToAWSResponse.message());
}
} else {
submitPostListener.submitFailed(uploadImageResponse.code() + " " + uploadImageResponse.message());
}
@Override
public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
submitPostListener.submitFailed(t.getMessage());
}
});
} catch (IOException | XmlPullParserException | JSONException e) {
e.printStackTrace();
submitPostListener.submitFailed(e.getMessage());
}
}
public static void submitCrosspost(Retrofit oauthRetrofit, String accessToken,
Locale locale, String subredditName, String title, String crosspostFullname,
String subredditName, String title, String crosspostFullname,
Flair flair, boolean isSpoiler, boolean isNSFW, String kind,
SubmitPostListener submitPostListener) {
submitPost(oauthRetrofit, accessToken, locale, subredditName, title, crosspostFullname,
submitPost(oauthRetrofit, accessToken, subredditName, title, crosspostFullname,
flair, isSpoiler, isNSFW, kind, null, submitPostListener);
}
private static void submitPost(Retrofit oauthRetrofit, String accessToken,
Locale locale, String subredditName, String title, String content,
String subredditName, String title, String content,
Flair flair, boolean isSpoiler, boolean isNSFW, String kind,
@Nullable String posterUrl, SubmitPostListener submitPostListener) {
RedditAPI api = oauthRetrofit.create(RedditAPI.class);
@ -206,32 +168,23 @@ public class SubmitPost {
params.put(APIUtils.NSFW_KEY, Boolean.toString(isNSFW));
Call<String> submitPostCall = api.submit(APIUtils.getOAuthHeader(accessToken), params);
submitPostCall.enqueue(new Callback<String>() {
@Override
public void onResponse(@NonNull Call<String> call, @NonNull retrofit2.Response<String> response) {
if (response.isSuccessful()) {
try {
getSubmittedPost(response.body(), kind, oauthRetrofit, accessToken,
locale, submitPostListener);
} catch (JSONException e) {
e.printStackTrace();
submitPostListener.submitFailed(null);
}
} else {
submitPostListener.submitFailed(response.message());
}
}
@Override
public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
submitPostListener.submitFailed(t.getMessage());
try {
Response<String> response = submitPostCall.execute();
if (response.isSuccessful()) {
getSubmittedPost(response.body(), kind, oauthRetrofit, accessToken, submitPostListener);
} else {
submitPostListener.submitFailed(response.message());
}
});
} catch (IOException | JSONException e) {
e.printStackTrace();
submitPostListener.submitFailed(e.getMessage());
}
}
private static void uploadImage(Retrofit oauthRetrofit, Retrofit uploadMediaRetrofit,
String accessToken, Bitmap image,
UploadImageListener uploadImageListener) {
@Nullable
private static String uploadImage(Retrofit oauthRetrofit, Retrofit uploadMediaRetrofit,
String accessToken, Bitmap image) throws IOException, JSONException, XmlPullParserException {
RedditAPI api = oauthRetrofit.create(RedditAPI.class);
Map<String, String> uploadImageParams = new HashMap<>();
@ -239,70 +192,32 @@ public class SubmitPost {
uploadImageParams.put(APIUtils.MIMETYPE_KEY, "image/jpeg");
Call<String> uploadImageCall = api.uploadImage(APIUtils.getOAuthHeader(accessToken), uploadImageParams);
uploadImageCall.enqueue(new Callback<String>() {
@Override
public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) {
if (response.isSuccessful()) {
new ParseJSONResponseFromAWSAsyncTask(response.body(), new ParseJSONResponseFromAWSAsyncTask.ParseJSONResponseFromAWSListener() {
@Override
public void parseSuccessful(Map<String, RequestBody> nameValuePairsMap) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte[] byteArray = stream.toByteArray();
Response<String> uploadImageResponse = uploadImageCall.execute();
if (uploadImageResponse.isSuccessful()) {
Map<String, RequestBody> nameValuePairsMap = parseJSONResponseFromAWS(uploadImageResponse.body());
RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), byteArray);
MultipartBody.Part fileToUpload = MultipartBody.Part.createFormData("file", "post_image.jpg", fileBody);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte[] byteArray = stream.toByteArray();
RedditAPI uploadMediaToAWSApi = uploadMediaRetrofit.create(RedditAPI.class);
Call<String> uploadMediaToAWS = uploadMediaToAWSApi.uploadMediaToAWS(nameValuePairsMap, fileToUpload);
RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), byteArray);
MultipartBody.Part fileToUpload = MultipartBody.Part.createFormData("file", "post_image.jpg", fileBody);
uploadMediaToAWS.enqueue(new Callback<String>() {
@Override
public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) {
if (response.isSuccessful()) {
new ParseXMLReponseFromAWSAsyncTask(response.body(), new ParseXMLReponseFromAWSAsyncTask.ParseXMLResponseFromAWSListener() {
@Override
public void parseSuccessful(String url) {
uploadImageListener.uploaded(url);
}
@Override
public void parseFailed() {
uploadImageListener.uploadFailed(null);
}
}).execute();
} else {
uploadImageListener.uploadFailed("Error: " + response.code());
}
}
@Override
public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
uploadImageListener.uploadFailed(t.getMessage());
}
});
}
@Override
public void parseFailed() {
uploadImageListener.uploadFailed(null);
}
}).execute();
} else {
uploadImageListener.uploadFailed(response.message());
}
RedditAPI uploadMediaToAWSApi = uploadMediaRetrofit.create(RedditAPI.class);
Call<String> uploadMediaToAWS = uploadMediaToAWSApi.uploadMediaToAWS(nameValuePairsMap, fileToUpload);
Response<String> uploadMediaToAWSResponse = uploadMediaToAWS.execute();
if (uploadMediaToAWSResponse.isSuccessful()) {
return parseXMLResponseFromAWS(uploadMediaToAWSResponse.body());
} else {
return "Error: " + uploadMediaToAWSResponse.code();
}
@Override
public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
uploadImageListener.uploadFailed(t.getMessage());
}
});
} else {
return "Error: " + uploadImageResponse.message();
}
}
private static void getSubmittedPost(String response, String kind, Retrofit oauthRetrofit,
String accessToken, Locale locale,
SubmitPostListener submitPostListener) throws JSONException {
String accessToken, SubmitPostListener submitPostListener) throws JSONException, IOException {
JSONObject responseObject = new JSONObject(response).getJSONObject(JSONUtils.JSON_KEY);
if (responseObject.getJSONArray(JSONUtils.ERRORS_KEY).length() != 0) {
JSONArray error = responseObject.getJSONArray(JSONUtils.ERRORS_KEY)
@ -328,31 +243,22 @@ public class SubmitPost {
RedditAPI api = oauthRetrofit.create(RedditAPI.class);
Call<String> getPostCall = api.getPostOauth(postId, APIUtils.getOAuthHeader(accessToken));
getPostCall.enqueue(new Callback<String>() {
@Override
public void onResponse(@NonNull Call<String> call, @NonNull retrofit2.Response<String> response) {
if (response.isSuccessful()) {
ParsePost.parsePost(response.body(), new ParsePost.ParsePostListener() {
@Override
public void onParsePostSuccess(Post post) {
submitPostListener.submitSuccessful(post);
}
@Override
public void onParsePostFail() {
submitPostListener.submitFailed(null);
}
});
} else {
submitPostListener.submitFailed(response.message());
Response<String> getPostCallResponse = getPostCall.execute();
if (getPostCallResponse.isSuccessful()) {
ParsePost.parsePost(getPostCallResponse.body(), new ParsePost.ParsePostListener() {
@Override
public void onParsePostSuccess(Post post) {
submitPostListener.submitSuccessful(post);
}
}
@Override
public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
submitPostListener.submitFailed(t.getMessage());
}
});
@Override
public void onParsePostFail() {
submitPostListener.submitFailed(null);
}
});
} else {
submitPostListener.submitFailed(getPostCallResponse.message());
}
} else {
submitPostListener.submitSuccessful(null);
}
@ -364,115 +270,39 @@ public class SubmitPost {
void submitFailed(@Nullable String errorMessage);
}
private interface UploadImageListener {
void uploaded(String imageUrl);
private static Map<String, RequestBody> parseJSONResponseFromAWS(String response) throws JSONException {
JSONObject responseObject = new JSONObject(response);
JSONArray nameValuePairs = responseObject.getJSONObject(JSONUtils.ARGS_KEY).getJSONArray(JSONUtils.FIELDS_KEY);
void uploadFailed(@Nullable String errorMessage);
Map<String, RequestBody> nameValuePairsMap = new HashMap<>();
for (int i = 0; i < nameValuePairs.length(); i++) {
nameValuePairsMap.put(nameValuePairs.getJSONObject(i).getString(JSONUtils.NAME_KEY),
APIUtils.getRequestBody(nameValuePairs.getJSONObject(i).getString(JSONUtils.VALUE_KEY)));
}
return nameValuePairsMap;
}
private static class ParseJSONResponseFromAWSAsyncTask extends AsyncTask<Void, Void, Void> {
private String response;
private ParseJSONResponseFromAWSListener parseJSONResponseFromAWSListener;
private Map<String, RequestBody> nameValuePairsMap;
private boolean successful;
ParseJSONResponseFromAWSAsyncTask(String response, ParseJSONResponseFromAWSListener parseJSONResponseFromAWSListener) {
this.response = response;
this.parseJSONResponseFromAWSListener = parseJSONResponseFromAWSListener;
nameValuePairsMap = new HashMap<>();
successful = false;
}
@Nullable
private static String parseXMLResponseFromAWS(String response) throws XmlPullParserException, IOException {
XmlPullParser xmlPullParser = XmlPullParserFactory.newInstance().newPullParser();
xmlPullParser.setInput(new StringReader(response));
@Override
protected Void doInBackground(Void... voids) {
try {
JSONObject responseObject = new JSONObject(response);
JSONArray nameValuePairs = responseObject.getJSONObject(JSONUtils.ARGS_KEY).getJSONArray(JSONUtils.FIELDS_KEY);
nameValuePairsMap = new HashMap<>();
for (int i = 0; i < nameValuePairs.length(); i++) {
nameValuePairsMap.put(nameValuePairs.getJSONObject(i).getString(JSONUtils.NAME_KEY),
APIUtils.getRequestBody(nameValuePairs.getJSONObject(i).getString(JSONUtils.VALUE_KEY)));
boolean isLocationTag = false;
int eventType = xmlPullParser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
if (xmlPullParser.getName().equals("Location")) {
isLocationTag = true;
}
successful = true;
} catch (JSONException e) {
e.printStackTrace();
successful = false;
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
if (successful) {
parseJSONResponseFromAWSListener.parseSuccessful(nameValuePairsMap);
} else {
parseJSONResponseFromAWSListener.parseFailed();
}
}
interface ParseJSONResponseFromAWSListener {
void parseSuccessful(Map<String, RequestBody> nameValuePairsMap);
void parseFailed();
}
}
private static class ParseXMLReponseFromAWSAsyncTask extends AsyncTask<Void, Void, Void> {
private String response;
private ParseXMLResponseFromAWSListener parseXMLResponseFromAWSListener;
private String imageUrl;
private boolean successful;
ParseXMLReponseFromAWSAsyncTask(String response, ParseXMLResponseFromAWSListener parseXMLResponseFromAWSListener) {
this.response = response;
this.parseXMLResponseFromAWSListener = parseXMLResponseFromAWSListener;
successful = false;
}
@Override
protected Void doInBackground(Void... voids) {
try {
XmlPullParser xmlPullParser = XmlPullParserFactory.newInstance().newPullParser();
xmlPullParser.setInput(new StringReader(response));
boolean isLocationTag = false;
int eventType = xmlPullParser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
if (xmlPullParser.getName().equals("Location")) {
isLocationTag = true;
}
} else if (eventType == XmlPullParser.TEXT) {
if (isLocationTag) {
imageUrl = xmlPullParser.getText();
successful = true;
return null;
}
}
eventType = xmlPullParser.next();
} else if (eventType == XmlPullParser.TEXT) {
if (isLocationTag) {
return xmlPullParser.getText();
}
} catch (XmlPullParserException | IOException e) {
e.printStackTrace();
successful = false;
}
return null;
eventType = xmlPullParser.next();
}
@Override
protected void onPostExecute(Void aVoid) {
if (successful) {
parseXMLResponseFromAWSListener.parseSuccessful(imageUrl);
} else {
parseXMLResponseFromAWSListener.parseFailed();
}
}
interface ParseXMLResponseFromAWSListener {
void parseSuccessful(String url);
void parseFailed();
}
return null;
}
}

View File

@ -6,11 +6,15 @@ import android.app.NotificationManager;
import android.app.Service;
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.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.widget.Toast;
import androidx.annotation.NonNull;
@ -19,8 +23,6 @@ import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
import org.greenrobot.eventbus.EventBus;
@ -29,22 +31,24 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import javax.inject.Inject;
import javax.inject.Named;
import ml.docilealligator.infinityforreddit.Flair;
import ml.docilealligator.infinityforreddit.Infinity;
import ml.docilealligator.infinityforreddit.R;
import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper;
import ml.docilealligator.infinityforreddit.events.SubmitCrosspostEvent;
import ml.docilealligator.infinityforreddit.events.SubmitImagePostEvent;
import ml.docilealligator.infinityforreddit.events.SubmitTextOrLinkPostEvent;
import ml.docilealligator.infinityforreddit.events.SubmitVideoOrGifPostEvent;
import ml.docilealligator.infinityforreddit.Flair;
import ml.docilealligator.infinityforreddit.Infinity;
import ml.docilealligator.infinityforreddit.utils.NotificationUtils;
import ml.docilealligator.infinityforreddit.post.Post;
import ml.docilealligator.infinityforreddit.post.SubmitPost;
import ml.docilealligator.infinityforreddit.R;
import ml.docilealligator.infinityforreddit.utils.APIUtils;
import ml.docilealligator.infinityforreddit.utils.NotificationUtils;
import retrofit2.Retrofit;
public class SubmitPostService extends Service {
@ -61,6 +65,7 @@ public class SubmitPostService extends Service {
public static final int EXTRA_POST_TYPE_IMAGE = 1;
public static final int EXTRA_POST_TYPE_VIDEO = 2;
public static final int EXTRA_POST_TYPE_CROSSPOST = 3;
private static final String EXTRA_MEDIA_URI = "EU";
@Inject
@Named("oauth")
Retrofit mOauthRetrofit;
@ -72,15 +77,7 @@ public class SubmitPostService extends Service {
Retrofit mUploadVideoRetrofit;
@Inject
CustomThemeWrapper mCustomThemeWrapper;
private String mAccessToken;
private String subredditName;
private String title;
private Flair flair;
private boolean isSpoiler;
private boolean isNSFW;
private String content;
private String kind;
private Uri mediaUri;
private ServiceHandler serviceHandler;
public SubmitPostService() {
}
@ -90,18 +87,60 @@ public class SubmitPostService extends Service {
return null;
}
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
Bundle bundle = msg.getData();
String accessToken = bundle.getString(EXTRA_ACCESS_TOKEN);
String subredditName = bundle.getString(EXTRA_SUBREDDIT_NAME);
String title = bundle.getString(EXTRA_TITLE);
Flair flair = bundle.getParcelable(EXTRA_FLAIR);
boolean isSpoiler = bundle.getBoolean(EXTRA_IS_SPOILER, false);
boolean isNSFW = bundle.getBoolean(EXTRA_IS_NSFW, false);
int postType = bundle.getInt(EXTRA_POST_TYPE, EXTRA_POST_TEXT_OR_LINK);
if (postType == EXTRA_POST_TEXT_OR_LINK) {
String content = bundle.getString(EXTRA_CONTENT);
String kind = bundle.getString(EXTRA_KIND);
submitTextOrLinkPost(accessToken, subredditName, title, content, flair, isSpoiler, isNSFW, kind);
} else if (postType == EXTRA_POST_TYPE_CROSSPOST) {
String content = bundle.getString(EXTRA_CONTENT);
submitCrosspost(accessToken, subredditName, title, content, flair, isSpoiler, isNSFW);
} else if (postType == EXTRA_POST_TYPE_IMAGE) {
Uri mediaUri = Uri.parse(bundle.getString(EXTRA_MEDIA_URI));
submitImagePost(accessToken, mediaUri, subredditName, title, flair, isSpoiler, isNSFW);
} else {
Uri mediaUri = Uri.parse(bundle.getString(EXTRA_MEDIA_URI));
submitVideoPost(accessToken, mediaUri, subredditName, title, flair, isSpoiler, isNSFW);
}
}
}
@Override
public void onCreate() {
((Infinity) getApplication()).getAppComponent().inject(this);
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work doesn't disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
serviceHandler = new ServiceHandler(thread.getLooper());
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
((Infinity) getApplication()).getAppComponent().inject(this);
mAccessToken = intent.getStringExtra(EXTRA_ACCESS_TOKEN);
subredditName = intent.getStringExtra(EXTRA_SUBREDDIT_NAME);
title = intent.getStringExtra(EXTRA_TITLE);
flair = intent.getParcelableExtra(EXTRA_FLAIR);
isSpoiler = intent.getBooleanExtra(EXTRA_IS_SPOILER, false);
isNSFW = intent.getBooleanExtra(EXTRA_IS_NSFW, false);
int postType = intent.getIntExtra(EXTRA_POST_TYPE, EXTRA_POST_TEXT_OR_LINK);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
NotificationUtils.CHANNEL_SUBMIT_POST,
@ -113,25 +152,26 @@ public class SubmitPostService extends Service {
manager.createNotificationChannel(serviceChannel);
}
int randomNotificationIdOffset = new Random().nextInt(10000);
int postType = intent.getIntExtra(EXTRA_POST_TYPE, EXTRA_POST_TEXT_OR_LINK);
Bundle bundle = intent.getExtras();
if (postType == EXTRA_POST_TEXT_OR_LINK) {
content = intent.getStringExtra(EXTRA_CONTENT);
kind = intent.getStringExtra(EXTRA_KIND);
startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID, createNotification(R.string.posting));
submitTextOrLinkPost();
startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID + randomNotificationIdOffset, createNotification(R.string.posting));
} else if (postType == EXTRA_POST_TYPE_CROSSPOST) {
content = intent.getStringExtra(EXTRA_CONTENT);
startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID, createNotification(R.string.posting));
submitCrosspost();
startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID + randomNotificationIdOffset, createNotification(R.string.posting));
} else if (postType == EXTRA_POST_TYPE_IMAGE) {
mediaUri = intent.getData();
startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID, createNotification(R.string.posting_image));
submitImagePost();
bundle.putString(EXTRA_MEDIA_URI, intent.getData().toString());
startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID + randomNotificationIdOffset, createNotification(R.string.posting_image));
} else {
mediaUri = intent.getData();
startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID, createNotification(R.string.posting_video));
submitVideoPost();
bundle.putString(EXTRA_MEDIA_URI, intent.getData().toString());
startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID + randomNotificationIdOffset, createNotification(R.string.posting_video));
}
Message msg = serviceHandler.obtainMessage();
msg.setData(bundle);
serviceHandler.sendMessage(msg);
return START_NOT_STICKY;
}
@ -144,8 +184,8 @@ public class SubmitPostService extends Service {
.build();
}
private void submitTextOrLinkPost() {
SubmitPost.submitTextOrLinkPost(mOauthRetrofit, mAccessToken, getResources().getConfiguration().locale,
private void submitTextOrLinkPost(String accessToken, String subredditName, String title, String content, Flair flair, boolean isSpoiler, boolean isNSFW, String kind) {
SubmitPost.submitTextOrLinkPost(mOauthRetrofit, accessToken, getResources().getConfiguration().locale,
subredditName, title, content, flair, isSpoiler, isNSFW, kind, new SubmitPost.SubmitPostListener() {
@Override
public void submitSuccessful(Post post) {
@ -163,9 +203,9 @@ public class SubmitPostService extends Service {
});
}
private void submitCrosspost() {
SubmitPost.submitCrosspost(mOauthRetrofit, mAccessToken, getResources().getConfiguration().locale,
subredditName, title, content, flair, isSpoiler, isNSFW, APIUtils.KIND_CROSSPOST, new SubmitPost.SubmitPostListener() {
private void submitCrosspost(String accessToken, String subredditName, String title, String content, Flair flair, boolean isSpoiler, boolean isNSFW) {
SubmitPost.submitCrosspost(mOauthRetrofit, accessToken, subredditName, title, content, flair, isSpoiler,
isNSFW, APIUtils.KIND_CROSSPOST, new SubmitPost.SubmitPostListener() {
@Override
public void submitSuccessful(Post post) {
EventBus.getDefault().post(new SubmitCrosspostEvent(true, post, null));
@ -182,49 +222,35 @@ public class SubmitPostService extends Service {
});
}
private void submitImagePost() {
Glide.with(this)
.asBitmap()
.load(mediaUri)
.into(new CustomTarget<Bitmap>() {
private void submitImagePost(String accessToken, Uri mediaUri, String subredditName, String title, Flair flair, boolean isSpoiler, boolean isNSFW) {
try {
Bitmap resource = Glide.with(this).asBitmap().load(mediaUri).submit().get();
SubmitPost.submitImagePost(mOauthRetrofit, mUploadMediaRetrofit, accessToken, subredditName, title, resource,
flair, isSpoiler, isNSFW, new SubmitPost.SubmitPostListener() {
@Override
public void submitSuccessful(Post post) {
EventBus.getDefault().post(new SubmitImagePostEvent(true, null));
Toast.makeText(SubmitPostService.this, R.string.image_is_processing, Toast.LENGTH_SHORT).show();
@Override
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
SubmitPost.submitImagePost(mOauthRetrofit, mUploadMediaRetrofit, mAccessToken,
getResources().getConfiguration().locale, subredditName, title, resource,
flair, isSpoiler, isNSFW, new SubmitPost.SubmitPostListener() {
@Override
public void submitSuccessful(Post post) {
EventBus.getDefault().post(new SubmitImagePostEvent(true, null));
Toast.makeText(SubmitPostService.this, R.string.image_is_processing, Toast.LENGTH_SHORT).show();
stopService();
}
stopService();
}
@Override
public void submitFailed(@Nullable String errorMessage) {
EventBus.getDefault().post(new SubmitImagePostEvent(false, errorMessage));
@Override
public void submitFailed(@Nullable String errorMessage) {
EventBus.getDefault().post(new SubmitImagePostEvent(false, errorMessage));
stopService();
}
});
}
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
EventBus.getDefault().post(new SubmitImagePostEvent(false, getString(R.string.error_processing_image)));
stopService();
}
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
}
});
stopService();
}
});
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
EventBus.getDefault().post(new SubmitImagePostEvent(false, getString(R.string.error_processing_image)));
stopService();
}
}
private void submitVideoPost() {
private void submitVideoPost(String accessToken, Uri mediaUri, String subredditName, String title,
Flair flair, boolean isSpoiler, boolean isNSFW) {
try {
InputStream in = getContentResolver().openInputStream(mediaUri);
String type = getContentResolver().getType(mediaUri);
@ -235,67 +261,39 @@ public class SubmitPostService extends Service {
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();
}
copyFileToCache(in, cacheFilePath);
stopService();
}
Bitmap resource = Glide.with(this).asBitmap().load(mediaUri).submit().get();
@Override
public void submitFailed(@Nullable String errorMessage) {
EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, false, errorMessage));
if (type != null) {
SubmitPost.submitVideoPost(mOauthRetrofit, mUploadMediaRetrofit, mUploadVideoRetrofit,
accessToken, 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();
}
});
} else {
EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, true, null));
}
}
stopService();
}
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, true, null));
@Override
public void submitFailed(@Nullable String errorMessage) {
EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, false, errorMessage));
stopService();
}
stopService();
}
});
} else {
EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, true, null));
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
}
});
}
@Override
public void failed() {
EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, true, null));
stopService();
}
}).execute();
} catch (IOException e) {
stopService();
}
} catch (IOException | InterruptedException | ExecutionException e) {
e.printStackTrace();
EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, true, null));
@ -303,47 +301,12 @@ public class SubmitPostService extends Service {
}
}
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 static void copyFileToCache(InputStream fileInputStream, String destinationFilePath) throws IOException {
OutputStream out = new FileOutputStream(destinationFilePath);
byte[] buf = new byte[2048];
int len;
while ((len = fileInputStream.read(buf)) > 0) {
out.write(buf, 0, len);
}
}