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

View File

@ -6,11 +6,15 @@ import android.app.NotificationManager;
import android.app.Service; import android.app.Service;
import android.content.Intent; import android.content.Intent;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder; import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -19,8 +23,6 @@ import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat; import androidx.core.app.NotificationManagerCompat;
import com.bumptech.glide.Glide; import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
@ -29,22 +31,24 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; 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.customtheme.CustomThemeWrapper;
import ml.docilealligator.infinityforreddit.events.SubmitCrosspostEvent; import ml.docilealligator.infinityforreddit.events.SubmitCrosspostEvent;
import ml.docilealligator.infinityforreddit.events.SubmitImagePostEvent; import ml.docilealligator.infinityforreddit.events.SubmitImagePostEvent;
import ml.docilealligator.infinityforreddit.events.SubmitTextOrLinkPostEvent; import ml.docilealligator.infinityforreddit.events.SubmitTextOrLinkPostEvent;
import ml.docilealligator.infinityforreddit.events.SubmitVideoOrGifPostEvent; 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.Post;
import ml.docilealligator.infinityforreddit.post.SubmitPost; import ml.docilealligator.infinityforreddit.post.SubmitPost;
import ml.docilealligator.infinityforreddit.R;
import ml.docilealligator.infinityforreddit.utils.APIUtils; import ml.docilealligator.infinityforreddit.utils.APIUtils;
import ml.docilealligator.infinityforreddit.utils.NotificationUtils;
import retrofit2.Retrofit; import retrofit2.Retrofit;
public class SubmitPostService extends Service { 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_IMAGE = 1;
public static final int EXTRA_POST_TYPE_VIDEO = 2; public static final int EXTRA_POST_TYPE_VIDEO = 2;
public static final int EXTRA_POST_TYPE_CROSSPOST = 3; public static final int EXTRA_POST_TYPE_CROSSPOST = 3;
private static final String EXTRA_MEDIA_URI = "EU";
@Inject @Inject
@Named("oauth") @Named("oauth")
Retrofit mOauthRetrofit; Retrofit mOauthRetrofit;
@ -72,15 +77,7 @@ public class SubmitPostService extends Service {
Retrofit mUploadVideoRetrofit; Retrofit mUploadVideoRetrofit;
@Inject @Inject
CustomThemeWrapper mCustomThemeWrapper; CustomThemeWrapper mCustomThemeWrapper;
private String mAccessToken; private ServiceHandler serviceHandler;
private String subredditName;
private String title;
private Flair flair;
private boolean isSpoiler;
private boolean isNSFW;
private String content;
private String kind;
private Uri mediaUri;
public SubmitPostService() { public SubmitPostService() {
} }
@ -90,18 +87,60 @@ public class SubmitPostService extends Service {
return null; 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 @Override
public int onStartCommand(Intent intent, int flags, int startId) { public int onStartCommand(Intent intent, int flags, int startId) {
((Infinity) getApplication()).getAppComponent().inject(this); ((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) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel( NotificationChannel serviceChannel = new NotificationChannel(
NotificationUtils.CHANNEL_SUBMIT_POST, NotificationUtils.CHANNEL_SUBMIT_POST,
@ -113,25 +152,26 @@ public class SubmitPostService extends Service {
manager.createNotificationChannel(serviceChannel); 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) { if (postType == EXTRA_POST_TEXT_OR_LINK) {
content = intent.getStringExtra(EXTRA_CONTENT); startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID + randomNotificationIdOffset, createNotification(R.string.posting));
kind = intent.getStringExtra(EXTRA_KIND);
startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID, createNotification(R.string.posting));
submitTextOrLinkPost();
} else if (postType == EXTRA_POST_TYPE_CROSSPOST) { } else if (postType == EXTRA_POST_TYPE_CROSSPOST) {
content = intent.getStringExtra(EXTRA_CONTENT); startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID + randomNotificationIdOffset, createNotification(R.string.posting));
startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID, createNotification(R.string.posting));
submitCrosspost();
} else if (postType == EXTRA_POST_TYPE_IMAGE) { } else if (postType == EXTRA_POST_TYPE_IMAGE) {
mediaUri = intent.getData(); bundle.putString(EXTRA_MEDIA_URI, intent.getData().toString());
startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID, createNotification(R.string.posting_image)); startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID + randomNotificationIdOffset, createNotification(R.string.posting_image));
submitImagePost();
} else { } else {
mediaUri = intent.getData(); bundle.putString(EXTRA_MEDIA_URI, intent.getData().toString());
startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID, createNotification(R.string.posting_video)); startForeground(NotificationUtils.SUBMIT_POST_SERVICE_NOTIFICATION_ID + randomNotificationIdOffset, createNotification(R.string.posting_video));
submitVideoPost();
} }
Message msg = serviceHandler.obtainMessage();
msg.setData(bundle);
serviceHandler.sendMessage(msg);
return START_NOT_STICKY; return START_NOT_STICKY;
} }
@ -144,8 +184,8 @@ public class SubmitPostService extends Service {
.build(); .build();
} }
private void submitTextOrLinkPost() { private void submitTextOrLinkPost(String accessToken, String subredditName, String title, String content, Flair flair, boolean isSpoiler, boolean isNSFW, String kind) {
SubmitPost.submitTextOrLinkPost(mOauthRetrofit, mAccessToken, getResources().getConfiguration().locale, SubmitPost.submitTextOrLinkPost(mOauthRetrofit, accessToken, getResources().getConfiguration().locale,
subredditName, title, content, flair, isSpoiler, isNSFW, kind, new SubmitPost.SubmitPostListener() { subredditName, title, content, flair, isSpoiler, isNSFW, kind, new SubmitPost.SubmitPostListener() {
@Override @Override
public void submitSuccessful(Post post) { public void submitSuccessful(Post post) {
@ -163,9 +203,9 @@ public class SubmitPostService extends Service {
}); });
} }
private void submitCrosspost() { private void submitCrosspost(String accessToken, String subredditName, String title, String content, Flair flair, boolean isSpoiler, boolean isNSFW) {
SubmitPost.submitCrosspost(mOauthRetrofit, mAccessToken, getResources().getConfiguration().locale, SubmitPost.submitCrosspost(mOauthRetrofit, accessToken, subredditName, title, content, flair, isSpoiler,
subredditName, title, content, flair, isSpoiler, isNSFW, APIUtils.KIND_CROSSPOST, new SubmitPost.SubmitPostListener() { isNSFW, APIUtils.KIND_CROSSPOST, new SubmitPost.SubmitPostListener() {
@Override @Override
public void submitSuccessful(Post post) { public void submitSuccessful(Post post) {
EventBus.getDefault().post(new SubmitCrosspostEvent(true, post, null)); EventBus.getDefault().post(new SubmitCrosspostEvent(true, post, null));
@ -182,49 +222,35 @@ public class SubmitPostService extends Service {
}); });
} }
private void submitImagePost() { private void submitImagePost(String accessToken, Uri mediaUri, String subredditName, String title, Flair flair, boolean isSpoiler, boolean isNSFW) {
Glide.with(this) try {
.asBitmap() Bitmap resource = Glide.with(this).asBitmap().load(mediaUri).submit().get();
.load(mediaUri) SubmitPost.submitImagePost(mOauthRetrofit, mUploadMediaRetrofit, accessToken, subredditName, title, resource,
.into(new CustomTarget<Bitmap>() { 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 stopService();
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(); @Override
} public void submitFailed(@Nullable String errorMessage) {
EventBus.getDefault().post(new SubmitImagePostEvent(false, errorMessage));
@Override stopService();
public void submitFailed(@Nullable String errorMessage) { }
EventBus.getDefault().post(new SubmitImagePostEvent(false, errorMessage)); });
} catch (ExecutionException | InterruptedException e) {
stopService(); e.printStackTrace();
} EventBus.getDefault().post(new SubmitImagePostEvent(false, getString(R.string.error_processing_image)));
}); 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) {
}
});
} }
private void submitVideoPost() { private void submitVideoPost(String accessToken, Uri mediaUri, String subredditName, String title,
Flair flair, boolean isSpoiler, boolean isNSFW) {
try { try {
InputStream in = getContentResolver().openInputStream(mediaUri); InputStream in = getContentResolver().openInputStream(mediaUri);
String type = getContentResolver().getType(mediaUri); String type = getContentResolver().getType(mediaUri);
@ -235,67 +261,39 @@ public class SubmitPostService extends Service {
cacheFilePath = getExternalCacheDir() + "/" + mediaUri.getLastPathSegment() + ".mp4"; cacheFilePath = getExternalCacheDir() + "/" + mediaUri.getLastPathSegment() + ".mp4";
} }
new CopyFileToCacheAsyncTask(in, cacheFilePath, copyFileToCache(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(); Bitmap resource = Glide.with(this).asBitmap().load(mediaUri).submit().get();
}
@Override if (type != null) {
public void submitFailed(@Nullable String errorMessage) { SubmitPost.submitVideoPost(mOauthRetrofit, mUploadMediaRetrofit, mUploadVideoRetrofit,
EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, false, errorMessage)); 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(); stopService();
} }
});
} else {
EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, true, null));
}
}
@Override @Override
public void onLoadFailed(@Nullable Drawable errorDrawable) { public void submitFailed(@Nullable String errorMessage) {
EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, true, null)); EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, false, errorMessage));
stopService(); stopService();
} }
});
} else {
EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, true, null));
@Override stopService();
public void onLoadCleared(@Nullable Drawable placeholder) { }
} catch (IOException | InterruptedException | ExecutionException e) {
}
});
}
@Override
public void failed() {
EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, true, null));
stopService();
}
}).execute();
} catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
EventBus.getDefault().post(new SubmitVideoOrGifPostEvent(false, true, null)); 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 static void copyFileToCache(InputStream fileInputStream, String destinationFilePath) throws IOException {
OutputStream out = new FileOutputStream(destinationFilePath);
private InputStream fileInputStream; byte[] buf = new byte[2048];
private String destinationFilePath; int len;
private CopyFileToCacheAsyncTaskListener copyFileToCacheAsyncTaskListener; while ((len = fileInputStream.read(buf)) > 0) {
private boolean parseFailed = false; out.write(buf, 0, len);
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();
}
} }
} }