Fix notification refresh + Post messages

This commit is contained in:
Thomas 2022-09-21 15:49:13 +02:00
parent bd43af4ab8
commit 927433a7bf
6 changed files with 135 additions and 123 deletions

View file

@ -108,9 +108,6 @@
android:name="com.theartofdev.edmodo.cropper.CropImageActivity" android:name="com.theartofdev.edmodo.cropper.CropImageActivity"
android:theme="@style/Base.Theme.AppCompat" /> android:theme="@style/Base.Theme.AppCompat" />
<service
android:name=".services.PostMessageService"
android:label="@string/post_message" />
<activity <activity
android:name=".activities.SearchResultTabActivity" android:name=".activities.SearchResultTabActivity"

View file

@ -53,6 +53,7 @@ import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.work.Data; import androidx.work.Data;
import androidx.work.OneTimeWorkRequest; import androidx.work.OneTimeWorkRequest;
import androidx.work.OutOfQuotaPolicy;
import androidx.work.WorkManager; import androidx.work.WorkManager;
import java.io.File; import java.io.File;
@ -87,8 +88,8 @@ import app.fedilab.android.helper.MastodonHelper;
import app.fedilab.android.helper.MediaHelper; import app.fedilab.android.helper.MediaHelper;
import app.fedilab.android.helper.ThemeHelper; import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.interfaces.OnDownloadInterface; import app.fedilab.android.interfaces.OnDownloadInterface;
import app.fedilab.android.jobs.ComposeWorker;
import app.fedilab.android.jobs.ScheduleThreadWorker; import app.fedilab.android.jobs.ScheduleThreadWorker;
import app.fedilab.android.services.PostMessageService;
import app.fedilab.android.services.ThreadMessageService; import app.fedilab.android.services.ThreadMessageService;
import app.fedilab.android.ui.drawer.AccountsReplyAdapter; import app.fedilab.android.ui.drawer.AccountsReplyAdapter;
import app.fedilab.android.ui.drawer.ComposeAdapter; import app.fedilab.android.ui.drawer.ComposeAdapter;
@ -846,17 +847,17 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
mediaCount += status.media_attachments != null ? status.media_attachments.size() : 0; mediaCount += status.media_attachments != null ? status.media_attachments.size() : 0;
} }
if (mediaCount > 0) { if (mediaCount > 0) {
Intent intent = new Intent(ComposeActivity.this, PostMessageService.class); Data inputData = new Data.Builder()
intent.putExtra(Helper.ARG_STATUS_DRAFT, statusDraft); .putString(Helper.ARG_STATUS_DRAFT, ComposeWorker.serialize(statusDraft))
intent.putExtra(Helper.ARG_INSTANCE, instance); .putString(Helper.ARG_INSTANCE, instance)
intent.putExtra(Helper.ARG_TOKEN, token); .putString(Helper.ARG_TOKEN, token)
intent.putExtra(Helper.ARG_USER_ID, account.user_id); .putString(Helper.ARG_USER_ID, account.user_id)
intent.putExtra(Helper.ARG_SCHEDULED_DATE, scheduledDate); .putString(Helper.ARG_SCHEDULED_DATE, scheduledDate).build();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(ComposeWorker.class)
startForegroundService(intent); .setInputData(inputData)
} else { .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
startService(intent); .build();
} WorkManager.getInstance(ComposeActivity.this).enqueue(request);
} else { } else {
new ThreadMessageService(ComposeActivity.this, instance, account.user_id, token, statusDraft, scheduledDate); new ThreadMessageService(ComposeActivity.this, instance, account.user_id, token, statusDraft, scheduledDate);
} }

View file

@ -1,5 +1,5 @@
package app.fedilab.android.services; package app.fedilab.android.jobs;
/* Copyright 2021 Thomas Schneider /* Copyright 2022 Thomas Schneider
* *
* This file is a part of Fedilab * 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, * You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */ * see <http://www.gnu.org/licenses>. */
import static android.content.Context.NOTIFICATION_SERVICE;
import android.app.IntentService; import android.app.IntentService;
import android.app.Notification; import android.app.Notification;
import android.app.NotificationChannel; import android.app.NotificationChannel;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
@ -26,10 +29,17 @@ import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.preference.PreferenceManager; 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.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@ -57,25 +67,19 @@ import retrofit2.Response;
import retrofit2.Retrofit; import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory; import retrofit2.converter.gson.GsonConverterFactory;
public class PostMessageService extends IntentService { public class ComposeWorker extends Worker {
private static final int NOTIFICATION_INT_CHANNEL_ID = 1; private static final int NOTIFICATION_INT_CHANNEL_ID = 1;
public static String CHANNEL_ID = "post_messages"; public static String CHANNEL_ID = "post_messages";
private final NotificationManager notificationManager;
private NotificationCompat.Builder notificationBuilder; private NotificationCompat.Builder notificationBuilder;
private NotificationManager notificationManager;
/** public ComposeWorker(
* @param name - String @NonNull Context context,
* @deprecated @NonNull WorkerParameters parameters) {
*/ super(context, parameters);
public PostMessageService(String name) { notificationManager = (NotificationManager)
super(name); context.getSystemService(NOTIFICATION_SERVICE);
}
@SuppressWarnings("unused")
public PostMessageService() {
super("PostMessageService");
} }
private static OkHttpClient getOkHttpClient(Context context) { private static OkHttpClient getOkHttpClient(Context context) {
@ -95,7 +99,7 @@ public class PostMessageService extends IntentService {
return retrofit.create(MastodonStatusesService.class); return retrofit.create(MastodonStatusesService.class);
} }
static void publishMessage(Context context, DataPost dataPost) { public static void publishMessage(Context context, DataPost dataPost) {
long totalMediaSize; long totalMediaSize;
long totalBitRead; long totalBitRead;
MastodonStatusesService mastodonStatusesService = init(context, dataPost.instance); MastodonStatusesService mastodonStatusesService = init(context, dataPost.instance);
@ -337,41 +341,33 @@ public class PostMessageService extends IntentService {
return null; return null;
} }
@Override public static String serialize(StatusDraft statusDraft) {
public void onCreate() { Gson gson = new Gson();
super.onCreate(); try {
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); return gson.toJson(statusDraft);
if (Build.VERSION.SDK_INT >= 26) { } catch (Exception e) {
String channelName = "Post messages"; return null;
String channelDescription = "Post messages in background";
NotificationChannel notifChannel = new NotificationChannel(CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_HIGH);
notifChannel.setDescription(channelDescription);
notificationManager.createNotificationChannel(notifChannel);
} }
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 public static StatusDraft restore(String serialized) {
protected void onHandleIntent(@Nullable Intent intent) { Gson gson = new Gson();
StatusDraft statusDraft = null; try {
String token = null, instance = null; return gson.fromJson(serialized, StatusDraft.class);
String scheduledDate = null; } catch (Exception e) {
String userId = null; return 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);
} }
}
@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 //Should not be null, but a simple security
if (token == null) { if (token == null) {
token = BaseMainActivity.currentToken; token = BaseMainActivity.currentToken;
@ -387,21 +383,54 @@ public class PostMessageService extends IntentService {
dataPost.scheduledDate = scheduledDate; dataPost.scheduledDate = scheduledDate;
dataPost.notificationBuilder = notificationBuilder; dataPost.notificationBuilder = notificationBuilder;
dataPost.notificationManager = notificationManager; dataPost.notificationManager = notificationManager;
publishMessage(PostMessageService.this, dataPost); // Mark the Worker as important
notificationManager.cancel(NOTIFICATION_INT_CHANNEL_ID); setForegroundAsync(createForegroundInfo());
publishMessage(getApplicationContext(), dataPost);
return Result.success();
} }
static class DataPost { @NonNull
String instance; private ForegroundInfo createForegroundInfo() {
String token; // Build a notification using bytesRead and contentLength
String userId;
StatusDraft statusDraft; Context context = getApplicationContext();
int messageToSend; // This PendingIntent can be used to cancel the worker
int messageSent; PendingIntent intent = WorkManager.getInstance(context)
NotificationCompat.Builder notificationBuilder; .createCancelPendingIntent(getId());
String scheduledDate;
NotificationManager notificationManager; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
IntentService service; 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;
}
} }

View file

@ -18,7 +18,6 @@ import android.app.Notification;
import android.app.NotificationChannel; import android.app.NotificationChannel;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.os.Build; import android.os.Build;
@ -29,11 +28,13 @@ import androidx.work.ForegroundInfo;
import androidx.work.Worker; import androidx.work.Worker;
import androidx.work.WorkerParameters; import androidx.work.WorkerParameters;
import java.util.List;
import app.fedilab.android.R; 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.exception.DBException;
import app.fedilab.android.helper.Helper; import app.fedilab.android.helper.NotificationsHelper;
import app.fedilab.android.services.PostMessageService;
public class NotificationsWorker extends Worker { public class NotificationsWorker extends Worker {
@ -69,32 +70,19 @@ public class NotificationsWorker extends Worker {
@NonNull @NonNull
@Override @Override
public Result doWork() { public Result doWork() {
setForegroundAsync(createForegroundInfo()); 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 { try {
statusDraft = new StatusDraft(getApplicationContext()).geStatusDraft(statusDraftId); List<BaseAccount> accounts = new Account(getApplicationContext()).getAll();
Intent intent = new Intent(getApplicationContext(), PostMessageService.class); for (BaseAccount account : accounts) {
intent.putExtra(Helper.ARG_STATUS_DRAFT, statusDraft); try {
intent.putExtra(Helper.ARG_INSTANCE, instance); NotificationsHelper.task(getApplicationContext(), account.user_id + "@" + account.instance);
intent.putExtra(Helper.ARG_TOKEN, token); } catch (DBException e) {
intent.putExtra(Helper.ARG_USER_ID, userId); e.printStackTrace();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { }
getApplicationContext().startForegroundService(intent);
} else {
getApplicationContext().startService(intent);
} }
} catch (DBException e) { } catch (DBException e) {
e.printStackTrace(); 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.notifications)).build());
return Result.success(new Data.Builder().putString("WORK_RESULT", getApplicationContext().getString(R.string.toot_sent)).build());
} }
} }

View file

@ -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, * You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */ * see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.jobs.ComposeWorker.publishMessage;
import android.app.Notification; import android.app.Notification;
import android.app.NotificationChannel; import android.app.NotificationChannel;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.os.Build; import android.os.Build;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat;
import androidx.work.Data;
import androidx.work.ForegroundInfo; import androidx.work.ForegroundInfo;
import androidx.work.Worker; import androidx.work.Worker;
import androidx.work.WorkerParameters; 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.client.entities.app.StatusDraft;
import app.fedilab.android.exception.DBException; import app.fedilab.android.exception.DBException;
import app.fedilab.android.helper.Helper; import app.fedilab.android.helper.Helper;
import app.fedilab.android.services.PostMessageService;
public class ScheduleThreadWorker extends Worker { public class ScheduleThreadWorker extends Worker {
@ -69,9 +68,7 @@ public class ScheduleThreadWorker extends Worker {
@NonNull @NonNull
@Override @Override
public Result doWork() { public Result doWork() {
setForegroundAsync(createForegroundInfo()); setForegroundAsync(createForegroundInfo());
Data outputData;
String instance = getInputData().getString(Helper.ARG_INSTANCE); String instance = getInputData().getString(Helper.ARG_INSTANCE);
String token = getInputData().getString(Helper.ARG_TOKEN); String token = getInputData().getString(Helper.ARG_TOKEN);
String userId = getInputData().getString(Helper.ARG_USER_ID); String userId = getInputData().getString(Helper.ARG_USER_ID);
@ -79,22 +76,20 @@ public class ScheduleThreadWorker extends Worker {
StatusDraft statusDraft; StatusDraft statusDraft;
try { try {
statusDraft = new StatusDraft(getApplicationContext()).geStatusDraft(statusDraftId); statusDraft = new StatusDraft(getApplicationContext()).geStatusDraft(statusDraftId);
Intent intent = new Intent(getApplicationContext(), PostMessageService.class); ComposeWorker.DataPost dataPost = new ComposeWorker.DataPost();
intent.putExtra(Helper.ARG_STATUS_DRAFT, statusDraft); dataPost.instance = instance;
intent.putExtra(Helper.ARG_INSTANCE, instance); dataPost.token = token;
intent.putExtra(Helper.ARG_TOKEN, token); dataPost.userId = userId;
intent.putExtra(Helper.ARG_USER_ID, userId); dataPost.statusDraft = statusDraft;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { dataPost.scheduledDate = null;
getApplicationContext().startForegroundService(intent); dataPost.notificationManager = notificationManager;
} else { // Mark the Worker as important
getApplicationContext().startService(intent); setForegroundAsync(createForegroundInfo());
} publishMessage(getApplicationContext(), dataPost);
return Result.success();
} catch (DBException e) { } catch (DBException e) {
e.printStackTrace(); e.printStackTrace();
outputData = new Data.Builder().putString("WORK_RESULT", getApplicationContext().getString(R.string.toast_error)).build(); return Result.failure();
return Result.failure(outputData); }
}
return Result.success(new Data.Builder().putString("WORK_RESULT", getApplicationContext().getString(R.string.toot_sent)).build());
} }
} }

View file

@ -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, * You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */ * see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.services.PostMessageService.publishMessage;
import static app.fedilab.android.jobs.ComposeWorker.publishMessage;
import android.content.Context; import android.content.Context;
import app.fedilab.android.client.entities.app.StatusDraft; import app.fedilab.android.client.entities.app.StatusDraft;
import app.fedilab.android.jobs.ComposeWorker;
public class ThreadMessageService { public class ThreadMessageService {
public ThreadMessageService(Context context, String instance, String userId, String token, StatusDraft statusDraft, String scheduledDate) { 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.instance = instance;
dataPost.userId = userId; dataPost.userId = userId;
dataPost.token = token; dataPost.token = token;