From 5e58f8a4818efc73db36786b25831930357511dc Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 20 May 2022 11:11:02 +0200 Subject: [PATCH] Use thread instead of a service when no media attached when posting - avoid top notification --- .../android/activities/ComposeActivity.java | 25 ++- .../android/services/PostMessageService.java | 177 ++++++++++-------- .../services/ThreadMessageService.java | 33 ++++ 3 files changed, 151 insertions(+), 84 deletions(-) create mode 100644 app/src/main/java/app/fedilab/android/services/ThreadMessageService.java diff --git a/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java b/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java index 2fc897e99..b43df0c2c 100644 --- a/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java @@ -75,6 +75,7 @@ import app.fedilab.android.helper.SpannableHelper; import app.fedilab.android.helper.ThemeHelper; import app.fedilab.android.jobs.ScheduleThreadWorker; import app.fedilab.android.services.PostMessageService; +import app.fedilab.android.services.ThreadMessageService; import app.fedilab.android.ui.drawer.AccountsReplyAdapter; import app.fedilab.android.ui.drawer.ComposeAdapter; import app.fedilab.android.viewmodel.mastodon.AccountsVM; @@ -561,15 +562,23 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana } } else if (sendMessage) { - Intent intent = new Intent(ComposeActivity.this, PostMessageService.class); - intent.putExtra(Helper.ARG_STATUS_DRAFT, statusDraft); - intent.putExtra(Helper.ARG_INSTANCE, instance); - intent.putExtra(Helper.ARG_TOKEN, token); - intent.putExtra(Helper.ARG_SCHEDULED_DATE, scheduledDate); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - startForegroundService(intent); + int mediaCount = 0; + for (Status status : statusDraft.statusDraftList) { + mediaCount += status.media_attachments != null ? status.media_attachments.size() : 0; + } + if (mediaCount > 0) { + Intent intent = new Intent(ComposeActivity.this, PostMessageService.class); + intent.putExtra(Helper.ARG_STATUS_DRAFT, statusDraft); + intent.putExtra(Helper.ARG_INSTANCE, instance); + intent.putExtra(Helper.ARG_TOKEN, token); + intent.putExtra(Helper.ARG_SCHEDULED_DATE, scheduledDate); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + startForegroundService(intent); + } else { + startService(intent); + } } else { - startService(intent); + new ThreadMessageService(ComposeActivity.this, instance, token, statusDraft, scheduledDate); } finish(); } diff --git a/app/src/main/java/app/fedilab/android/services/PostMessageService.java b/app/src/main/java/app/fedilab/android/services/PostMessageService.java index bf7b786cb..f01a3816f 100644 --- a/app/src/main/java/app/fedilab/android/services/PostMessageService.java +++ b/app/src/main/java/app/fedilab/android/services/PostMessageService.java @@ -61,12 +61,9 @@ public class PostMessageService extends IntentService { private static final int NOTIFICATION_INT_CHANNEL_ID = 1; public static String CHANNEL_ID = "post_messages"; - private long totalMediaSize; - private long totalBitRead; + private NotificationCompat.Builder notificationBuilder; private NotificationManager notificationManager; - private int messageToSend; - private int messageSent; /** * @param name - String @@ -97,83 +94,66 @@ public class PostMessageService extends IntentService { notificationBuilder.setSmallIcon(R.drawable.ic_notification) .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_foreground)) .setContentTitle(getString(R.string.post_message)) - .setContentText(getString(R.string.post_message_text, messageSent, messageToSend)) .setDefaults(NotificationCompat.DEFAULT_ALL) .setPriority(Notification.PRIORITY_DEFAULT); startForeground(NOTIFICATION_INT_CHANNEL_ID, notificationBuilder.build()); } - private OkHttpClient getOkHttpClient() { + private static OkHttpClient getOkHttpClient(Context context) { return new OkHttpClient.Builder() .readTimeout(120, TimeUnit.SECONDS) .connectTimeout(120, TimeUnit.SECONDS) - .proxy(Helper.getProxy(getApplication().getApplicationContext())) + .proxy(Helper.getProxy(context.getApplicationContext())) .build(); } - private MastodonStatusesService init(@NonNull String instance) { + private static MastodonStatusesService init(Context context, @NonNull String instance) { Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://" + instance + "/api/v1/") .addConverterFactory(GsonConverterFactory.create()) - .client(getOkHttpClient()) + .client(getOkHttpClient(context)) .build(); return retrofit.create(MastodonStatusesService.class); } - @Override - protected void onHandleIntent(@Nullable Intent intent) { - StatusDraft statusDraft = null; - String token = null, instance = null; - String scheduledDate = null; - if (intent != null && intent.getExtras() != null) { - Bundle b = intent.getExtras(); - statusDraft = (StatusDraft) b.getSerializable(Helper.ARG_STATUS_DRAFT); - token = b.getString(Helper.ARG_TOKEN); - instance = b.getString(Helper.ARG_INSTANCE); - scheduledDate = b.getString(Helper.ARG_SCHEDULED_DATE); - } - //Should not be null, but a simple security - if (token == null) { - token = BaseMainActivity.currentToken; - } - if (instance == null) { - instance = BaseMainActivity.currentInstance; - } - MastodonStatusesService mastodonStatusesService = init(instance); + static void publishMessage(Context context, DataPost dataPost) { + long totalMediaSize; + long totalBitRead; + MastodonStatusesService mastodonStatusesService = init(context, dataPost.instance); boolean error = false; Status firstSendMessage = null; - if (statusDraft != null && statusDraft.statusDraftList != null && statusDraft.statusDraftList.size() > 0) { + if (dataPost.statusDraft != null && dataPost.statusDraft.statusDraftList != null && dataPost.statusDraft.statusDraftList.size() > 0) { //If state is null, it is created (typically when submitting the status the first time) - if (statusDraft.state == null) { - statusDraft.state = new PostState(); - statusDraft.state.posts = new ArrayList<>(); - statusDraft.state.number_of_posts = statusDraft.statusDraftList.size(); - for (Status status : statusDraft.statusDraftList) { + if (dataPost.statusDraft.state == null) { + dataPost.statusDraft.state = new PostState(); + dataPost.statusDraft.state.posts = new ArrayList<>(); + dataPost.statusDraft.state.number_of_posts = dataPost.statusDraft.statusDraftList.size(); + for (Status status : dataPost.statusDraft.statusDraftList) { PostState.Post post = new PostState.Post(); post.number_of_media = status.media_attachments != null ? status.media_attachments.size() : 0; - statusDraft.state.posts.add(post); + dataPost.statusDraft.state.posts.add(post); } } //Check if previous messages in thread have already been published (ie: when resending after a fail) int startingPosition = 0; - for (PostState.Post post : statusDraft.state.posts) { + for (PostState.Post post : dataPost.statusDraft.state.posts) { if (post.id == null) { break; } startingPosition++; } - List statuses = statusDraft.statusDraftList; + List statuses = dataPost.statusDraft.statusDraftList; String in_reply_to_status = null; - if (statusDraft.statusReplyList != null && statusDraft.statusReplyList.size() > 0) { - in_reply_to_status = statusDraft.statusReplyList.get(statusDraft.statusReplyList.size() - 1).id; + if (dataPost.statusDraft.statusReplyList != null && dataPost.statusDraft.statusReplyList.size() > 0) { + in_reply_to_status = dataPost.statusDraft.statusReplyList.get(dataPost.statusDraft.statusReplyList.size() - 1).id; } totalMediaSize = 0; totalBitRead = 0; - SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(PostMessageService.this); - boolean watermark = sharedPreferences.getBoolean(getString(R.string.SET_WATERMARK), false); - String watermarkText = sharedPreferences.getString(getString(R.string.SET_WATERMARK_TEXT) + MainActivity.currentUserID + MainActivity.currentInstance, null); + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); + boolean watermark = sharedPreferences.getBoolean(context.getString(R.string.SET_WATERMARK), false); + String watermarkText = sharedPreferences.getString(context.getString(R.string.SET_WATERMARK_TEXT) + MainActivity.currentUserID + MainActivity.currentInstance, null); for (int i = startingPosition; i < statuses.size(); i++) { if (statuses.get(i).media_attachments != null && statuses.get(i).media_attachments.size() > 0) { for (Attachment attachment : statuses.get(i).media_attachments) { @@ -183,20 +163,20 @@ public class PostMessageService extends IntentService { } if (watermarkText == null) { try { - Account account = new Account(PostMessageService.this).getAccountByToken(token); + Account account = new Account(context).getAccountByToken(dataPost.token); watermarkText = account.mastodon_account.username + "@" + account.instance; } catch (DBException e) { e.printStackTrace(); } } - messageToSend = statuses.size() - startingPosition; - messageSent = 0; + dataPost.messageToSend = statuses.size() - startingPosition; + dataPost.messageSent = 0; for (int i = startingPosition; i < statuses.size(); i++) { - if (notificationBuilder != null) { - notificationBuilder.setProgress(100, messageSent * 100 / messageToSend, true); - notificationBuilder.setContentText(getString(R.string.post_message_text, messageSent, messageToSend)); - notificationManager.notify(NOTIFICATION_INT_CHANNEL_ID, notificationBuilder.build()); + if (dataPost.notificationBuilder != null) { + dataPost.notificationBuilder.setProgress(100, dataPost.messageSent * 100 / dataPost.messageToSend, true); + dataPost.notificationBuilder.setContentText(context.getString(R.string.post_message_text, dataPost.messageSent, dataPost.messageToSend)); + dataPost.notificationManager.notify(NOTIFICATION_INT_CHANNEL_ID, dataPost.notificationBuilder.build()); } //post media first List attachmentIds = null; @@ -208,11 +188,11 @@ public class PostMessageService extends IntentService { } else { MultipartBody.Part fileMultipartBody; if (watermark && attachment.mimeType != null && attachment.mimeType.contains("image")) { - fileMultipartBody = Helper.getMultipartBodyWithWM(PostMessageService.this, watermarkText, "file", attachment); + fileMultipartBody = Helper.getMultipartBodyWithWM(context, watermarkText, "file", attachment); } else { fileMultipartBody = Helper.getMultipartBody("file", attachment); } - Call attachmentCall = mastodonStatusesService.postMedia(token, fileMultipartBody, null, attachment.description, null); + Call attachmentCall = mastodonStatusesService.postMedia(dataPost.token, fileMultipartBody, null, attachment.description, null); if (attachmentCall != null) { try { @@ -246,8 +226,8 @@ public class PostMessageService extends IntentService { poll_hide_totals = false; } Call statusCall; - if (scheduledDate == null) { - statusCall = mastodonStatusesService.createStatus(null, token, statuses.get(i).text, attachmentIds, poll_options, poll_expire_in, + if (dataPost.scheduledDate == null) { + statusCall = mastodonStatusesService.createStatus(null, dataPost.token, statuses.get(i).text, attachmentIds, poll_options, poll_expire_in, poll_multiple, poll_hide_totals, in_reply_to_status, statuses.get(i).sensitive, statuses.get(i).spoiler_text, statuses.get(i).visibility.toLowerCase(), statuses.get(i).language); try { Response statusResponse = statusCall.execute(); @@ -255,28 +235,30 @@ public class PostMessageService extends IntentService { if (statusResponse.isSuccessful()) { Status statusReply = statusResponse.body(); if (statusReply != null) { - StatusAdapter.sendAction(this, Helper.ARG_STATUS_POSTED, statusReply, null); + StatusAdapter.sendAction(context, Helper.ARG_STATUS_POSTED, statusReply, null); } if (firstSendMessage == null && statusReply != null) { firstSendMessage = statusReply; } if (statusReply != null) { in_reply_to_status = statusReply.id; - statusDraft.state.posts_successfully_sent = i; - statusDraft.state.posts.get(i).id = statusReply.id; - statusDraft.state.posts.get(i).in_reply_to_id = statusReply.in_reply_to_id; + dataPost.statusDraft.state.posts_successfully_sent = i; + dataPost.statusDraft.state.posts.get(i).id = statusReply.id; + dataPost.statusDraft.state.posts.get(i).in_reply_to_id = statusReply.in_reply_to_id; try { - new StatusDraft(getApplicationContext()).updatePostState(statusDraft); + new StatusDraft(context.getApplicationContext()).updatePostState(dataPost.statusDraft); } catch (DBException e) { e.printStackTrace(); } - if (!error && i >= statusDraft.statusDraftList.size()) { + if (!error && i >= dataPost.statusDraft.statusDraftList.size()) { try { - new StatusDraft(PostMessageService.this).removeDraft(statusDraft); + new StatusDraft(context).removeDraft(dataPost.statusDraft); } catch (DBException e) { e.printStackTrace(); } - stopSelf(); + if (dataPost.service != null) { + dataPost.service.stopSelf(); + } } } } @@ -285,8 +267,8 @@ public class PostMessageService extends IntentService { error = true; } } else { - Call scheduledStatusCall = mastodonStatusesService.createScheduledStatus(null, token, statuses.get(i).text, attachmentIds, poll_options, poll_expire_in, - poll_multiple, poll_hide_totals, in_reply_to_status, statuses.get(i).sensitive, statuses.get(i).spoiler_text, statuses.get(i).visibility.toLowerCase(), scheduledDate, statuses.get(i).language); + Call scheduledStatusCall = mastodonStatusesService.createScheduledStatus(null, dataPost.token, statuses.get(i).text, attachmentIds, poll_options, poll_expire_in, + poll_multiple, poll_hide_totals, in_reply_to_status, statuses.get(i).sensitive, statuses.get(i).spoiler_text, statuses.get(i).visibility.toLowerCase(), dataPost.scheduledDate, statuses.get(i).language); try { Response statusResponse = scheduledStatusCall.execute(); @@ -294,21 +276,23 @@ public class PostMessageService extends IntentService { ScheduledStatus statusReply = statusResponse.body(); if (statusReply != null) { in_reply_to_status = statusReply.id; - statusDraft.state.posts_successfully_sent = i; - statusDraft.state.posts.get(i).id = statusReply.id; - statusDraft.state.posts.get(i).in_reply_to_id = statusReply.params.in_reply_to_id; + dataPost.statusDraft.state.posts_successfully_sent = i; + dataPost.statusDraft.state.posts.get(i).id = statusReply.id; + dataPost.statusDraft.state.posts.get(i).in_reply_to_id = statusReply.params.in_reply_to_id; try { - new StatusDraft(getApplicationContext()).updatePostState(statusDraft); + new StatusDraft(context.getApplicationContext()).updatePostState(dataPost.statusDraft); } catch (DBException e) { e.printStackTrace(); } - if (!error && i >= statusDraft.statusDraftList.size()) { + if (!error && i >= dataPost.statusDraft.statusDraftList.size()) { try { - new StatusDraft(PostMessageService.this).removeDraft(statusDraft); + new StatusDraft(context).removeDraft(dataPost.statusDraft); } catch (DBException e) { e.printStackTrace(); } - stopSelf(); + if (dataPost.service != null) { + dataPost.service.stopSelf(); + } } } } @@ -317,22 +301,63 @@ public class PostMessageService extends IntentService { error = true; } } - messageSent++; - if (messageSent > messageToSend) { - messageSent = messageToSend; + dataPost.messageSent++; + if (dataPost.messageSent > dataPost.messageToSend) { + dataPost.messageSent = dataPost.messageToSend; } } } - if (scheduledDate == null && token != null && firstSendMessage != null) { + if (dataPost.scheduledDate == null && dataPost.token != null && firstSendMessage != null) { Bundle b = new Bundle(); b.putBoolean(Helper.RECEIVE_NEW_MESSAGE, true); Intent intentBD = new Intent(Helper.BROADCAST_DATA); b.putSerializable(Helper.RECEIVE_STATUS_ACTION, firstSendMessage); intentBD.putExtras(b); - LocalBroadcastManager.getInstance(PostMessageService.this).sendBroadcast(intentBD); + LocalBroadcastManager.getInstance(context).sendBroadcast(intentBD); } + } + + @Override + protected void onHandleIntent(@Nullable Intent intent) { + StatusDraft statusDraft = null; + String token = null, instance = null; + String scheduledDate = null; + if (intent != null && intent.getExtras() != null) { + Bundle b = intent.getExtras(); + statusDraft = (StatusDraft) b.getSerializable(Helper.ARG_STATUS_DRAFT); + token = b.getString(Helper.ARG_TOKEN); + instance = b.getString(Helper.ARG_INSTANCE); + scheduledDate = b.getString(Helper.ARG_SCHEDULED_DATE); + } + //Should not be null, but a simple security + if (token == null) { + token = BaseMainActivity.currentToken; + } + if (instance == null) { + instance = BaseMainActivity.currentInstance; + } + DataPost dataPost = new DataPost(); + dataPost.instance = instance; + dataPost.token = token; + dataPost.statusDraft = statusDraft; + dataPost.scheduledDate = scheduledDate; + dataPost.notificationBuilder = notificationBuilder; + dataPost.notificationManager = notificationManager; + publishMessage(PostMessageService.this, dataPost); notificationManager.cancel(NOTIFICATION_INT_CHANNEL_ID); } + static class DataPost { + String instance; + String token; + StatusDraft statusDraft; + int messageToSend; + int messageSent; + NotificationCompat.Builder notificationBuilder; + String scheduledDate; + NotificationManager notificationManager; + IntentService service; + } + } diff --git a/app/src/main/java/app/fedilab/android/services/ThreadMessageService.java b/app/src/main/java/app/fedilab/android/services/ThreadMessageService.java new file mode 100644 index 000000000..3d59ba38a --- /dev/null +++ b/app/src/main/java/app/fedilab/android/services/ThreadMessageService.java @@ -0,0 +1,33 @@ +package app.fedilab.android.services; +/* Copyright 2022 Thomas Schneider + * + * This file is a part of Fedilab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Fedilab; if not, + * see . */ + +import static app.fedilab.android.services.PostMessageService.publishMessage; + +import android.content.Context; + +import app.fedilab.android.client.entities.StatusDraft; + +public class ThreadMessageService { + + public ThreadMessageService(Context context, String instance, String token, StatusDraft statusDraft, String scheduledDate) { + PostMessageService.DataPost dataPost = new PostMessageService.DataPost(); + dataPost.instance = instance; + dataPost.token = token; + dataPost.scheduledDate = scheduledDate; + dataPost.statusDraft = statusDraft; + publishMessage(context, dataPost); + } +}