From 927433a7bf66655fcf0fe67c02aaf964074aba53 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 21 Sep 2022 15:49:13 +0200 Subject: [PATCH] Fix notification refresh + Post messages --- app/src/main/AndroidManifest.xml | 3 - .../android/activities/ComposeActivity.java | 25 +-- .../ComposeWorker.java} | 153 +++++++++++------- .../android/jobs/NotificationsWorker.java | 38 ++--- .../android/jobs/ScheduleThreadWorker.java | 33 ++-- .../services/ThreadMessageService.java | 6 +- 6 files changed, 135 insertions(+), 123 deletions(-) rename app/src/main/java/app/fedilab/android/{services/PostMessageService.java => jobs/ComposeWorker.java} (83%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f013f62d..3a3c685e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -108,9 +108,6 @@ android:name="com.theartofdev.edmodo.cropper.CropImageActivity" android:theme="@style/Base.Theme.AppCompat" /> - 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_USER_ID, account.user_id); - intent.putExtra(Helper.ARG_SCHEDULED_DATE, scheduledDate); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - startForegroundService(intent); - } else { - startService(intent); - } + Data inputData = new Data.Builder() + .putString(Helper.ARG_STATUS_DRAFT, ComposeWorker.serialize(statusDraft)) + .putString(Helper.ARG_INSTANCE, instance) + .putString(Helper.ARG_TOKEN, token) + .putString(Helper.ARG_USER_ID, account.user_id) + .putString(Helper.ARG_SCHEDULED_DATE, scheduledDate).build(); + OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(ComposeWorker.class) + .setInputData(inputData) + .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) + .build(); + WorkManager.getInstance(ComposeActivity.this).enqueue(request); } else { new ThreadMessageService(ComposeActivity.this, instance, account.user_id, token, statusDraft, scheduledDate); } diff --git a/app/src/main/java/app/fedilab/android/services/PostMessageService.java b/app/src/main/java/app/fedilab/android/jobs/ComposeWorker.java similarity index 83% rename from app/src/main/java/app/fedilab/android/services/PostMessageService.java rename to app/src/main/java/app/fedilab/android/jobs/ComposeWorker.java index 1c0a9566..3236d83a 100644 --- a/app/src/main/java/app/fedilab/android/services/PostMessageService.java +++ b/app/src/main/java/app/fedilab/android/jobs/ComposeWorker.java @@ -1,5 +1,5 @@ -package app.fedilab.android.services; -/* Copyright 2021 Thomas Schneider +package app.fedilab.android.jobs; +/* Copyright 2022 Thomas Schneider * * This file is a part of Fedilab * @@ -14,10 +14,13 @@ package app.fedilab.android.services; * You should have received a copy of the GNU General Public License along with Fedilab; if not, * see . */ +import static android.content.Context.NOTIFICATION_SERVICE; + import android.app.IntentService; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; +import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -26,10 +29,17 @@ import android.os.Build; import android.os.Bundle; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.core.app.NotificationCompat; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.preference.PreferenceManager; +import androidx.work.Data; +import androidx.work.ForegroundInfo; +import androidx.work.WorkManager; +import androidx.work.Worker; +import androidx.work.WorkerParameters; + +import com.google.gson.Gson; import java.io.IOException; import java.util.ArrayList; @@ -57,25 +67,19 @@ import retrofit2.Response; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; -public class PostMessageService extends IntentService { +public class ComposeWorker extends Worker { private static final int NOTIFICATION_INT_CHANNEL_ID = 1; public static String CHANNEL_ID = "post_messages"; - + private final NotificationManager notificationManager; private NotificationCompat.Builder notificationBuilder; - private NotificationManager notificationManager; - /** - * @param name - String - * @deprecated - */ - public PostMessageService(String name) { - super(name); - } - - @SuppressWarnings("unused") - public PostMessageService() { - super("PostMessageService"); + public ComposeWorker( + @NonNull Context context, + @NonNull WorkerParameters parameters) { + super(context, parameters); + notificationManager = (NotificationManager) + context.getSystemService(NOTIFICATION_SERVICE); } private static OkHttpClient getOkHttpClient(Context context) { @@ -95,7 +99,7 @@ public class PostMessageService extends IntentService { return retrofit.create(MastodonStatusesService.class); } - static void publishMessage(Context context, DataPost dataPost) { + public static void publishMessage(Context context, DataPost dataPost) { long totalMediaSize; long totalBitRead; MastodonStatusesService mastodonStatusesService = init(context, dataPost.instance); @@ -337,41 +341,33 @@ public class PostMessageService extends IntentService { return null; } - @Override - public void onCreate() { - super.onCreate(); - notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - if (Build.VERSION.SDK_INT >= 26) { - String channelName = "Post messages"; - String channelDescription = "Post messages in background"; - NotificationChannel notifChannel = new NotificationChannel(CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_HIGH); - notifChannel.setDescription(channelDescription); - notificationManager.createNotificationChannel(notifChannel); - + public static String serialize(StatusDraft statusDraft) { + Gson gson = new Gson(); + try { + return gson.toJson(statusDraft); + } catch (Exception e) { + return null; } - notificationBuilder = new NotificationCompat.Builder(getBaseContext(), CHANNEL_ID); - notificationBuilder.setSmallIcon(R.drawable.ic_notification) - .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_foreground)) - .setContentTitle(getString(R.string.post_message)) - .setDefaults(NotificationCompat.DEFAULT_ALL) - .setPriority(Notification.PRIORITY_DEFAULT); - startForeground(NOTIFICATION_INT_CHANNEL_ID, notificationBuilder.build()); } - @Override - protected void onHandleIntent(@Nullable Intent intent) { - StatusDraft statusDraft = null; - String token = null, instance = null; - String scheduledDate = null; - String userId = 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); - userId = b.getString(Helper.ARG_USER_ID); - scheduledDate = b.getString(Helper.ARG_SCHEDULED_DATE); + public static StatusDraft restore(String serialized) { + Gson gson = new Gson(); + try { + return gson.fromJson(serialized, StatusDraft.class); + } catch (Exception e) { + return null; } + } + + @NonNull + @Override + public Result doWork() { + Data inputData = getInputData(); + StatusDraft statusDraft = restore(inputData.getString(Helper.ARG_STATUS_DRAFT)); + String token = inputData.getString(Helper.ARG_TOKEN); + String instance = inputData.getString(Helper.ARG_INSTANCE); + String userId = inputData.getString(Helper.ARG_USER_ID); + String scheduledDate = inputData.getString(Helper.ARG_SCHEDULED_DATE); //Should not be null, but a simple security if (token == null) { token = BaseMainActivity.currentToken; @@ -387,21 +383,54 @@ public class PostMessageService extends IntentService { dataPost.scheduledDate = scheduledDate; dataPost.notificationBuilder = notificationBuilder; dataPost.notificationManager = notificationManager; - publishMessage(PostMessageService.this, dataPost); - notificationManager.cancel(NOTIFICATION_INT_CHANNEL_ID); + // Mark the Worker as important + setForegroundAsync(createForegroundInfo()); + publishMessage(getApplicationContext(), dataPost); + return Result.success(); } - static class DataPost { - String instance; - String token; - String userId; - StatusDraft statusDraft; - int messageToSend; - int messageSent; - NotificationCompat.Builder notificationBuilder; - String scheduledDate; - NotificationManager notificationManager; - IntentService service; + @NonNull + private ForegroundInfo createForegroundInfo() { + // Build a notification using bytesRead and contentLength + + Context context = getApplicationContext(); + // This PendingIntent can be used to cancel the worker + PendingIntent intent = WorkManager.getInstance(context) + .createCancelPendingIntent(getId()); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + createChannel(); + } + notificationBuilder = new NotificationCompat.Builder(context, CHANNEL_ID); + notificationBuilder.setSmallIcon(R.drawable.ic_notification) + .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher_foreground)) + .setContentTitle(context.getString(R.string.post_message)) + .setOngoing(true) + .setDefaults(NotificationCompat.DEFAULT_ALL) + .setPriority(Notification.PRIORITY_DEFAULT); + + return new ForegroundInfo(NOTIFICATION_INT_CHANNEL_ID, notificationBuilder.build()); } + @RequiresApi(Build.VERSION_CODES.O) + private void createChannel() { + String channelName = "Post messages"; + String channelDescription = "Post messages in background"; + NotificationChannel notifChannel = new NotificationChannel(CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_HIGH); + notifChannel.setDescription(channelDescription); + notificationManager.createNotificationChannel(notifChannel); + } + + public static class DataPost { + public String instance; + public String token; + public String userId; + public StatusDraft statusDraft; + public int messageToSend; + public int messageSent; + public NotificationCompat.Builder notificationBuilder; + public String scheduledDate; + public NotificationManager notificationManager; + public IntentService service; + } } diff --git a/app/src/main/java/app/fedilab/android/jobs/NotificationsWorker.java b/app/src/main/java/app/fedilab/android/jobs/NotificationsWorker.java index c9566e9c..a84d9c7a 100644 --- a/app/src/main/java/app/fedilab/android/jobs/NotificationsWorker.java +++ b/app/src/main/java/app/fedilab/android/jobs/NotificationsWorker.java @@ -18,7 +18,6 @@ import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.content.Context; -import android.content.Intent; import android.graphics.BitmapFactory; import android.os.Build; @@ -29,11 +28,13 @@ import androidx.work.ForegroundInfo; import androidx.work.Worker; import androidx.work.WorkerParameters; +import java.util.List; + import app.fedilab.android.R; -import app.fedilab.android.client.entities.app.StatusDraft; +import app.fedilab.android.client.entities.app.Account; +import app.fedilab.android.client.entities.app.BaseAccount; import app.fedilab.android.exception.DBException; -import app.fedilab.android.helper.Helper; -import app.fedilab.android.services.PostMessageService; +import app.fedilab.android.helper.NotificationsHelper; public class NotificationsWorker extends Worker { @@ -69,32 +70,19 @@ public class NotificationsWorker extends Worker { @NonNull @Override public Result doWork() { - setForegroundAsync(createForegroundInfo()); - Data outputData; - String instance = getInputData().getString(Helper.ARG_INSTANCE); - String token = getInputData().getString(Helper.ARG_TOKEN); - String statusDraftId = getInputData().getString(Helper.ARG_STATUS_DRAFT_ID); - String userId = getInputData().getString(Helper.ARG_USER_ID); - StatusDraft statusDraft; try { - statusDraft = new StatusDraft(getApplicationContext()).geStatusDraft(statusDraftId); - Intent intent = new Intent(getApplicationContext(), 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_USER_ID, userId); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - getApplicationContext().startForegroundService(intent); - } else { - getApplicationContext().startService(intent); + List accounts = new Account(getApplicationContext()).getAll(); + for (BaseAccount account : accounts) { + try { + NotificationsHelper.task(getApplicationContext(), account.user_id + "@" + account.instance); + } catch (DBException e) { + e.printStackTrace(); + } } } catch (DBException e) { e.printStackTrace(); - outputData = new Data.Builder().putString("WORK_RESULT", getApplicationContext().getString(R.string.toast_error)).build(); - return Result.failure(outputData); } - - return Result.success(new Data.Builder().putString("WORK_RESULT", getApplicationContext().getString(R.string.toot_sent)).build()); + return Result.success(new Data.Builder().putString("WORK_RESULT", getApplicationContext().getString(R.string.notifications)).build()); } } diff --git a/app/src/main/java/app/fedilab/android/jobs/ScheduleThreadWorker.java b/app/src/main/java/app/fedilab/android/jobs/ScheduleThreadWorker.java index 5a6da3ba..741eb49a 100644 --- a/app/src/main/java/app/fedilab/android/jobs/ScheduleThreadWorker.java +++ b/app/src/main/java/app/fedilab/android/jobs/ScheduleThreadWorker.java @@ -14,17 +14,17 @@ package app.fedilab.android.jobs; * You should have received a copy of the GNU General Public License along with Fedilab; if not, * see . */ +import static app.fedilab.android.jobs.ComposeWorker.publishMessage; + import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.content.Context; -import android.content.Intent; import android.graphics.BitmapFactory; import android.os.Build; import androidx.annotation.NonNull; import androidx.core.app.NotificationCompat; -import androidx.work.Data; import androidx.work.ForegroundInfo; import androidx.work.Worker; import androidx.work.WorkerParameters; @@ -33,7 +33,6 @@ import app.fedilab.android.R; import app.fedilab.android.client.entities.app.StatusDraft; import app.fedilab.android.exception.DBException; import app.fedilab.android.helper.Helper; -import app.fedilab.android.services.PostMessageService; public class ScheduleThreadWorker extends Worker { @@ -69,9 +68,7 @@ public class ScheduleThreadWorker extends Worker { @NonNull @Override public Result doWork() { - setForegroundAsync(createForegroundInfo()); - Data outputData; String instance = getInputData().getString(Helper.ARG_INSTANCE); String token = getInputData().getString(Helper.ARG_TOKEN); String userId = getInputData().getString(Helper.ARG_USER_ID); @@ -79,22 +76,20 @@ public class ScheduleThreadWorker extends Worker { StatusDraft statusDraft; try { statusDraft = new StatusDraft(getApplicationContext()).geStatusDraft(statusDraftId); - Intent intent = new Intent(getApplicationContext(), 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_USER_ID, userId); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - getApplicationContext().startForegroundService(intent); - } else { - getApplicationContext().startService(intent); - } + ComposeWorker.DataPost dataPost = new ComposeWorker.DataPost(); + dataPost.instance = instance; + dataPost.token = token; + dataPost.userId = userId; + dataPost.statusDraft = statusDraft; + dataPost.scheduledDate = null; + dataPost.notificationManager = notificationManager; + // Mark the Worker as important + setForegroundAsync(createForegroundInfo()); + publishMessage(getApplicationContext(), dataPost); + return Result.success(); } catch (DBException e) { e.printStackTrace(); - outputData = new Data.Builder().putString("WORK_RESULT", getApplicationContext().getString(R.string.toast_error)).build(); - return Result.failure(outputData); + return Result.failure(); } - - return Result.success(new Data.Builder().putString("WORK_RESULT", getApplicationContext().getString(R.string.toot_sent)).build()); } } diff --git a/app/src/main/java/app/fedilab/android/services/ThreadMessageService.java b/app/src/main/java/app/fedilab/android/services/ThreadMessageService.java index a6fa0596..39eb323a 100644 --- a/app/src/main/java/app/fedilab/android/services/ThreadMessageService.java +++ b/app/src/main/java/app/fedilab/android/services/ThreadMessageService.java @@ -14,16 +14,18 @@ package app.fedilab.android.services; * 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 static app.fedilab.android.jobs.ComposeWorker.publishMessage; import android.content.Context; import app.fedilab.android.client.entities.app.StatusDraft; +import app.fedilab.android.jobs.ComposeWorker; public class ThreadMessageService { public ThreadMessageService(Context context, String instance, String userId, String token, StatusDraft statusDraft, String scheduledDate) { - PostMessageService.DataPost dataPost = new PostMessageService.DataPost(); + ComposeWorker.DataPost dataPost = new ComposeWorker.DataPost(); dataPost.instance = instance; dataPost.userId = userId; dataPost.token = token;