Fix push notifications in Android 12

This commit is contained in:
Adolfo Santiago 2022-05-28 12:13:13 +02:00
parent d513de70c4
commit 3e140825f5
No known key found for this signature in database
GPG key ID: 244D6F9A317B4A65
2 changed files with 131 additions and 108 deletions

View file

@ -1,21 +1,28 @@
/* Copyright 2018 Jeremiasz Nelz <remi6397(a)gmail.com> /*
* Copyright 2017 Andrew Dawson * Husky -- A Pleroma client for Android
* *
* This file is a part of Tusky. * Copyright (C) 2022 The Husky Developers
* Copyright (C) 2022 Conny Duck
* Copyright (C) 2018 Jeremiasz Nelz <remi6397(a)gmail.com>
* Copyright (C) 2017 Andrew Dawson
* *
* This program is free software; you can redistribute it and/or modify it under the terms of the * This program is free software: you can redistribute it and/or modify
* GNU General Public License as published by the Free Software Foundation; either version 3 of the * it under the terms of the GNU General Public License as published by
* License, or (at your option) any later version. * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* *
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * This program is distributed in the hope that it will be useful,
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * but WITHOUT ANY WARRANTY; without even the implied warranty of
* Public License for more details. * 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 Tusky; if not, * You should have received a copy of the GNU General Public License
* see <http://www.gnu.org/licenses>. */ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.keylesspalace.tusky.components.notifications; package com.keylesspalace.tusky.components.notifications;
import static com.keylesspalace.tusky.viewdata.PollViewDataKt.buildDescription;
import android.app.NotificationChannel; import android.app.NotificationChannel;
import android.app.NotificationChannelGroup; import android.app.NotificationChannelGroup;
import android.app.NotificationManager; import android.app.NotificationManager;
@ -28,8 +35,6 @@ import android.graphics.Color;
import android.os.Build; import android.os.Build;
import android.provider.Settings; import android.provider.Settings;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat;
@ -42,7 +47,6 @@ import androidx.work.NetworkType;
import androidx.work.PeriodicWorkRequest; import androidx.work.PeriodicWorkRequest;
import androidx.work.WorkManager; import androidx.work.WorkManager;
import androidx.work.WorkRequest; import androidx.work.WorkRequest;
import com.bumptech.glide.Glide; import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners; import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.FutureTarget; import com.bumptech.glide.request.FutureTarget;
@ -51,7 +55,6 @@ import com.keylesspalace.tusky.MainActivity;
import com.keylesspalace.tusky.R; import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.db.AccountEntity; import com.keylesspalace.tusky.db.AccountEntity;
import com.keylesspalace.tusky.db.AccountManager; import com.keylesspalace.tusky.db.AccountManager;
import com.keylesspalace.tusky.entity.ChatMessage;
import com.keylesspalace.tusky.entity.Notification; import com.keylesspalace.tusky.entity.Notification;
import com.keylesspalace.tusky.entity.Poll; import com.keylesspalace.tusky.entity.Poll;
import com.keylesspalace.tusky.entity.PollOption; import com.keylesspalace.tusky.entity.PollOption;
@ -60,21 +63,17 @@ import com.keylesspalace.tusky.receiver.NotificationClearBroadcastReceiver;
import com.keylesspalace.tusky.receiver.SendStatusBroadcastReceiver; import com.keylesspalace.tusky.receiver.SendStatusBroadcastReceiver;
import com.keylesspalace.tusky.util.StringUtils; import com.keylesspalace.tusky.util.StringUtils;
import com.keylesspalace.tusky.viewdata.PollViewDataKt; import com.keylesspalace.tusky.viewdata.PollViewDataKt;
import io.reactivex.Single;
import org.json.JSONArray; import io.reactivex.schedulers.Schedulers;
import org.json.JSONException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.json.JSONArray;
import io.reactivex.Single; import org.json.JSONException;
import io.reactivex.schedulers.Schedulers; import timber.log.Timber;
import static com.keylesspalace.tusky.viewdata.PollViewDataKt.buildDescription;
public class NotificationHelper { public class NotificationHelper {
@ -154,18 +153,18 @@ public class NotificationHelper {
public static void make(final Context context, Notification body, AccountEntity account, boolean isFirstOfBatch) { public static void make(final Context context, Notification body, AccountEntity account, boolean isFirstOfBatch) {
body = Notification.rewriteToStatusTypeIfNeeded(body, account.getAccountId()); body = Notification.rewriteToStatusTypeIfNeeded(body, account.getAccountId());
if (!filterNotification(account, body, context)) { if(!filterNotification(account, body, context)) {
return; return;
} }
// Pleroma extension: don't notify about seen notifications // Pleroma extension: don't notify about seen notifications
if (body.getPleroma() != null && body.getPleroma().getSeen()) { if(body.getPleroma() != null && body.getPleroma().getSeen()) {
return; return;
} }
if (body.getStatus() != null && if(body.getStatus() != null &&
(body.getStatus().isUserMuted() || (body.getStatus().isUserMuted() ||
body.getStatus().isThreadMuted())) { body.getStatus().isThreadMuted())) {
return; return;
} }
@ -174,18 +173,18 @@ public class NotificationHelper {
try { try {
currentNotifications = new JSONArray(rawCurrentNotifications); currentNotifications = new JSONArray(rawCurrentNotifications);
} catch (JSONException e) { } catch(JSONException e) {
currentNotifications = new JSONArray(); currentNotifications = new JSONArray();
} }
for (int i = 0; i < currentNotifications.length(); i++) { for(int i = 0; i < currentNotifications.length(); i++) {
try { try {
if (currentNotifications.getString(i).equals(body.getAccount().getName())) { if(currentNotifications.getString(i).equals(body.getAccount().getName())) {
currentNotifications.remove(i); currentNotifications.remove(i);
break; break;
} }
} catch (JSONException e) { } catch(JSONException e) {
Log.d(TAG, Log.getStackTraceString(e)); Timber.e(e);
} }
} }
@ -202,7 +201,7 @@ public class NotificationHelper {
builder.setContentTitle(titleForType(context, body, account)) builder.setContentTitle(titleForType(context, body, account))
.setContentText(bodyForType(body, context)); .setContentText(bodyForType(body, context));
if (body.getType() == Notification.Type.MENTION || body.getType() == Notification.Type.POLL) { if(body.getType() == Notification.Type.MENTION || body.getType() == Notification.Type.POLL) {
builder.setStyle(new NotificationCompat.BigTextStyle() builder.setStyle(new NotificationCompat.BigTextStyle()
.bigText(bodyForType(body, context))); .bigText(bodyForType(body, context)));
} }
@ -217,8 +216,8 @@ public class NotificationHelper {
.submit(); .submit();
accountAvatar = target.get(); accountAvatar = target.get();
} catch (ExecutionException | InterruptedException e) { } catch(ExecutionException | InterruptedException e) {
Log.d(TAG, "error loading account avatar", e); Timber.e("Error loading account avatar %s", e);
accountAvatar = BitmapFactory.decodeResource(context.getResources(), R.drawable.avatar_default); accountAvatar = BitmapFactory.decodeResource(context.getResources(), R.drawable.avatar_default);
} }
@ -280,14 +279,14 @@ public class NotificationHelper {
// ======= // =======
final NotificationCompat.Builder summaryBuilder = newNotification(context, body, account, true); final NotificationCompat.Builder summaryBuilder = newNotification(context, body, account, true);
if (currentNotifications.length() != 1) { if(currentNotifications.length() != 1) {
try { try {
String title = context.getString(R.string.notification_title_summary, currentNotifications.length()); String title = context.getString(R.string.notification_title_summary, currentNotifications.length());
String text = joinNames(context, currentNotifications); String text = joinNames(context, currentNotifications);
summaryBuilder.setContentTitle(title) summaryBuilder.setContentTitle(title)
.setContentText(text); .setContentText(text);
} catch (JSONException e) { } catch(JSONException e) {
Log.d(TAG, Log.getStackTraceString(e)); Timber.e(e);
} }
} }
@ -300,7 +299,7 @@ public class NotificationHelper {
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context); NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.notify(notificationId, builder.build()); notificationManager.notify(notificationId, builder.build());
if (currentNotifications.length() == 1) { if(currentNotifications.length() == 1) {
notificationManager.notify((int) account.getId(), builder.setGroupSummary(true).build()); notificationManager.notify((int) account.getId(), builder.setGroupSummary(true).build());
} else { } else {
notificationManager.notify((int) account.getId(), summaryBuilder.build()); notificationManager.notify((int) account.getId(), summaryBuilder.build());
@ -314,8 +313,10 @@ public class NotificationHelper {
summaryStackBuilder.addParentStack(MainActivity.class); summaryStackBuilder.addParentStack(MainActivity.class);
summaryStackBuilder.addNextIntent(summaryResultIntent); summaryStackBuilder.addNextIntent(summaryResultIntent);
PendingIntent summaryResultPendingIntent = summaryStackBuilder.getPendingIntent((int) (notificationId + account.getId() * 10000), PendingIntent summaryResultPendingIntent = summaryStackBuilder.getPendingIntent(
PendingIntent.FLAG_UPDATE_CURRENT); (int) (notificationId + account.getId() * 10000),
pendingIntentFlags(false)
);
// we have to switch account here // we have to switch account here
Intent eventResultIntent = new Intent(context, MainActivity.class); Intent eventResultIntent = new Intent(context, MainActivity.class);
@ -324,13 +325,16 @@ public class NotificationHelper {
eventStackBuilder.addParentStack(MainActivity.class); eventStackBuilder.addParentStack(MainActivity.class);
eventStackBuilder.addNextIntent(eventResultIntent); eventStackBuilder.addNextIntent(eventResultIntent);
PendingIntent eventResultPendingIntent = eventStackBuilder.getPendingIntent((int) account.getId(), PendingIntent eventResultPendingIntent = eventStackBuilder.getPendingIntent(
PendingIntent.FLAG_UPDATE_CURRENT); (int) account.getId(),
pendingIntentFlags(false));
Intent deleteIntent = new Intent(context, NotificationClearBroadcastReceiver.class); Intent deleteIntent = new Intent(context, NotificationClearBroadcastReceiver.class);
deleteIntent.putExtra(ACCOUNT_ID, account.getId()); deleteIntent.putExtra(ACCOUNT_ID, account.getId());
PendingIntent deletePendingIntent = PendingIntent.getBroadcast(context, summary ? (int) account.getId() : notificationId, deleteIntent, PendingIntent deletePendingIntent = PendingIntent.getBroadcast(
PendingIntent.FLAG_UPDATE_CURRENT); context, summary ? (int) account.getId() : notificationId,
deleteIntent,
pendingIntentFlags(false));
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, getChannelId(account, body)) NotificationCompat.Builder builder = new NotificationCompat.Builder(context, getChannelId(account, body))
.setSmallIcon(R.drawable.ic_notify) .setSmallIcon(R.drawable.ic_notify)
@ -349,11 +353,11 @@ public class NotificationHelper {
private static PendingIntent getStatusReplyIntent(String action, Context context, Notification body, AccountEntity account) { private static PendingIntent getStatusReplyIntent(String action, Context context, Notification body, AccountEntity account) {
Intent replyIntent = new Intent(context, SendStatusBroadcastReceiver.class) Intent replyIntent = new Intent(context, SendStatusBroadcastReceiver.class)
.setAction(action) .setAction(action)
.putExtra(KEY_SENDER_ACCOUNT_ID, account.getId()) .putExtra(KEY_SENDER_ACCOUNT_ID, account.getId())
.putExtra(KEY_SENDER_ACCOUNT_IDENTIFIER, account.getIdentifier()) .putExtra(KEY_SENDER_ACCOUNT_IDENTIFIER, account.getIdentifier())
.putExtra(KEY_SENDER_ACCOUNT_FULL_NAME, account.getFullName()) .putExtra(KEY_SENDER_ACCOUNT_FULL_NAME, account.getFullName())
.putExtra(KEY_NOTIFICATION_ID, notificationId); .putExtra(KEY_NOTIFICATION_ID, notificationId);
if(action == CHAT_REPLY_ACTION) { if(action == CHAT_REPLY_ACTION) {
replyIntent.putExtra(KEY_CHAT_ID, body.getChatMessage().getChatId()); replyIntent.putExtra(KEY_CHAT_ID, body.getChatMessage().getChatId());
@ -369,7 +373,7 @@ public class NotificationHelper {
Status.Mention[] mentions = actionableStatus.getMentions(); Status.Mention[] mentions = actionableStatus.getMentions();
List<String> mentionedUsernames = new ArrayList<>(); List<String> mentionedUsernames = new ArrayList<>();
mentionedUsernames.add(actionableStatus.getAccount().getUsername()); mentionedUsernames.add(actionableStatus.getAccount().getUsername());
for (Status.Mention mention : mentions) { for(Status.Mention mention : mentions) {
mentionedUsernames.add(mention.getUsername()); mentionedUsernames.add(mention.getUsername());
} }
mentionedUsernames.removeAll(Collections.singleton(account.getUsername())); mentionedUsernames.removeAll(Collections.singleton(account.getUsername()));
@ -386,12 +390,11 @@ public class NotificationHelper {
return PendingIntent.getBroadcast(context.getApplicationContext(), return PendingIntent.getBroadcast(context.getApplicationContext(),
notificationId, notificationId,
replyIntent, replyIntent,
PendingIntent.FLAG_UPDATE_CURRENT); pendingIntentFlags(true));
} }
public static void createNotificationChannelsForAccount(@NonNull AccountEntity account, @NonNull Context context) { public static void createNotificationChannelsForAccount(@NonNull AccountEntity account, @NonNull Context context) {
if (NOTIFICATION_USE_CHANNELS) { if(NOTIFICATION_USE_CHANNELS) {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
String[] channelIds = new String[]{ String[] channelIds = new String[]{
@ -406,6 +409,7 @@ public class NotificationHelper {
CHANNEL_SUBSCRIPTIONS + account.getIdentifier(), CHANNEL_SUBSCRIPTIONS + account.getIdentifier(),
CHANNEL_MOVE + account.getIdentifier() CHANNEL_MOVE + account.getIdentifier()
}; };
int[] channelNames = { int[] channelNames = {
R.string.notification_mention_name, R.string.notification_mention_name,
R.string.notification_follow_name, R.string.notification_follow_name,
@ -418,6 +422,7 @@ public class NotificationHelper {
R.string.notification_subscription_name, R.string.notification_subscription_name,
R.string.notification_move_name R.string.notification_move_name
}; };
int[] channelDescriptions = { int[] channelDescriptions = {
R.string.notification_mention_descriptions, R.string.notification_mention_descriptions,
R.string.notification_follow_description, R.string.notification_follow_description,
@ -438,7 +443,7 @@ public class NotificationHelper {
//noinspection ConstantConditions //noinspection ConstantConditions
notificationManager.createNotificationChannelGroup(channelGroup); notificationManager.createNotificationChannelGroup(channelGroup);
for (int i = 0; i < channelIds.length; i++) { for(int i = 0; i < channelIds.length; i++) {
String id = channelIds[i]; String id = channelIds[i];
String name = context.getString(channelNames[i]); String name = context.getString(channelNames[i]);
String description = context.getString(channelDescriptions[i]); String description = context.getString(channelDescriptions[i]);
@ -455,24 +460,20 @@ public class NotificationHelper {
} }
notificationManager.createNotificationChannels(channels); notificationManager.createNotificationChannels(channels);
} }
} }
public static void deleteNotificationChannelsForAccount(@NonNull AccountEntity account, @NonNull Context context) { public static void deleteNotificationChannelsForAccount(@NonNull AccountEntity account, @NonNull Context context) {
if (NOTIFICATION_USE_CHANNELS) { if(NOTIFICATION_USE_CHANNELS) {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
//noinspection ConstantConditions //noinspection ConstantConditions
notificationManager.deleteNotificationChannelGroup(account.getIdentifier()); notificationManager.deleteNotificationChannelGroup(account.getIdentifier());
} }
} }
public static void deleteLegacyNotificationChannels(@NonNull Context context, @NonNull AccountManager accountManager) { public static void deleteLegacyNotificationChannels(@NonNull Context context, @NonNull AccountManager accountManager) {
if (NOTIFICATION_USE_CHANNELS) { if(NOTIFICATION_USE_CHANNELS) {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// used until Tusky 1.4 // used until Tusky 1.4
@ -483,36 +484,33 @@ public class NotificationHelper {
notificationManager.deleteNotificationChannel(CHANNEL_FOLLOW); notificationManager.deleteNotificationChannel(CHANNEL_FOLLOW);
// used until Tusky 1.7 // used until Tusky 1.7
for(AccountEntity account: accountManager.getAllAccountsOrderedByActive()) { for(AccountEntity account : accountManager.getAllAccountsOrderedByActive()) {
notificationManager.deleteNotificationChannel(CHANNEL_FAVOURITE+" "+account.getIdentifier()); notificationManager.deleteNotificationChannel(CHANNEL_FAVOURITE + " " + account.getIdentifier());
} }
} }
} }
public static boolean areNotificationsEnabled(@NonNull Context context, @NonNull AccountManager accountManager) { public static boolean areNotificationsEnabled(@NonNull Context context, @NonNull AccountManager accountManager) {
if (NOTIFICATION_USE_CHANNELS) { if(NOTIFICATION_USE_CHANNELS) {
// on Android >= O, notifications are enabled, if at least one channel is enabled // on Android >= O, notifications are enabled, if at least one channel is enabled
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
//noinspection ConstantConditions //noinspection ConstantConditions
if (notificationManager.areNotificationsEnabled()) { if(notificationManager.areNotificationsEnabled()) {
for (NotificationChannel channel : notificationManager.getNotificationChannels()) { for(NotificationChannel channel : notificationManager.getNotificationChannels()) {
if (channel.getImportance() > NotificationManager.IMPORTANCE_NONE) { if(channel.getImportance() > NotificationManager.IMPORTANCE_NONE) {
Log.d(TAG, "NotificationsEnabled"); Timber.d("NotificationsEnabled");
return true; return true;
} }
} }
} }
Log.d(TAG, "NotificationsDisabled"); Timber.d("NotificationsDisabled");
return false; return false;
} else { } else {
// on Android < O, notifications are enabled, if at least one account has notification enabled // on Android < O, notifications are enabled, if at least one account has notification enabled
return accountManager.areNotificationsEnabled(); return accountManager.areNotificationsEnabled();
} }
} }
public static void enablePullNotifications(Context context) { public static void enablePullNotifications(Context context) {
@ -530,26 +528,26 @@ public class NotificationHelper {
workManager.enqueue(workRequest); workManager.enqueue(workRequest);
Log.d(TAG, "enabled notification checks with "+ PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS + "ms interval"); Timber.d("enabled notification checks with ${PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS} ms interval");
} }
public static void disablePullNotifications(Context context) { public static void disablePullNotifications(Context context) {
WorkManager.getInstance(context).cancelAllWorkByTag(NOTIFICATION_PULL_TAG); WorkManager.getInstance(context).cancelAllWorkByTag(NOTIFICATION_PULL_TAG);
Log.d(TAG, "disabled notification checks"); Timber.d("Disabled notification checks");
} }
public static void clearNotificationsForActiveAccount(@NonNull Context context, @NonNull AccountManager accountManager) { public static void clearNotificationsForActiveAccount(@NonNull Context context, @NonNull AccountManager accountManager) {
AccountEntity account = accountManager.getActiveAccount(); AccountEntity account = accountManager.getActiveAccount();
if (account != null && !account.getActiveNotifications().equals("[]")) { if(account != null && !account.getActiveNotifications().equals("[]")) {
Single.fromCallable(() -> { Single.fromCallable(() -> {
account.setActiveNotifications("[]"); account.setActiveNotifications("[]");
accountManager.saveAccount(account); accountManager.saveAccount(account);
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
//noinspection ConstantConditions //noinspection ConstantConditions
notificationManager.cancel((int) account.getId()); notificationManager.cancel((int) account.getId());
return true; return true;
}) })
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.subscribe(); .subscribe();
} }
@ -557,8 +555,7 @@ public class NotificationHelper {
private static boolean filterNotification(AccountEntity account, Notification notification, private static boolean filterNotification(AccountEntity account, Notification notification,
Context context) { Context context) {
if(NOTIFICATION_USE_CHANNELS) {
if (NOTIFICATION_USE_CHANNELS) {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
String channelId = getChannelId(account, notification); String channelId = getChannelId(account, notification);
@ -571,7 +568,7 @@ public class NotificationHelper {
return channel.getImportance() > NotificationManager.IMPORTANCE_NONE; return channel.getImportance() > NotificationManager.IMPORTANCE_NONE;
} }
switch (notification.getType()) { switch(notification.getType()) {
case MENTION: case MENTION:
return account.getNotificationsMentioned(); return account.getNotificationsMentioned();
case STATUS: case STATUS:
@ -599,7 +596,7 @@ public class NotificationHelper {
@Nullable @Nullable
private static String getChannelId(AccountEntity account, Notification notification) { private static String getChannelId(AccountEntity account, Notification notification) {
switch (notification.getType()) { switch(notification.getType()) {
case MENTION: case MENTION:
return CHANNEL_MENTION + account.getIdentifier(); return CHANNEL_MENTION + account.getIdentifier();
case STATUS: case STATUS:
@ -623,25 +620,24 @@ public class NotificationHelper {
default: default:
return null; return null;
} }
} }
private static void setupPreferences(AccountEntity account, private static void setupPreferences(
NotificationCompat.Builder builder) { AccountEntity account,
NotificationCompat.Builder builder) {
if (NOTIFICATION_USE_CHANNELS) { if(NOTIFICATION_USE_CHANNELS) {
return; //do nothing on Android O or newer, the system uses the channel settings anyway return; //do nothing on Android O or newer, the system uses the channel settings anyway
} }
if (account.getNotificationSound()) { if(account.getNotificationSound()) {
builder.setSound(Settings.System.DEFAULT_NOTIFICATION_URI); builder.setSound(Settings.System.DEFAULT_NOTIFICATION_URI);
} }
if (account.getNotificationVibration()) { if(account.getNotificationVibration()) {
builder.setVibrate(new long[]{500, 500}); builder.setVibrate(new long[]{500, 500});
} }
if (account.getNotificationLight()) { if(account.getNotificationLight()) {
builder.setLights(0xFF2B90D9, 300, 1000); builder.setLights(0xFF2B90D9, 300, 1000);
} }
} }
@ -652,19 +648,19 @@ public class NotificationHelper {
@Nullable @Nullable
private static String joinNames(Context context, JSONArray array) throws JSONException { private static String joinNames(Context context, JSONArray array) throws JSONException {
if (array.length() > 3) { if(array.length() > 3) {
int length = array.length(); int length = array.length();
return String.format(context.getString(R.string.notification_summary_large), return String.format(context.getString(R.string.notification_summary_large),
wrapItemAt(array, length - 1), wrapItemAt(array, length - 1),
wrapItemAt(array, length - 2), wrapItemAt(array, length - 2),
wrapItemAt(array, length - 3), wrapItemAt(array, length - 3),
length - 3); length - 3);
} else if (array.length() == 3) { } else if(array.length() == 3) {
return String.format(context.getString(R.string.notification_summary_medium), return String.format(context.getString(R.string.notification_summary_medium),
wrapItemAt(array, 2), wrapItemAt(array, 2),
wrapItemAt(array, 1), wrapItemAt(array, 1),
wrapItemAt(array, 0)); wrapItemAt(array, 0));
} else if (array.length() == 2) { } else if(array.length() == 2) {
return String.format(context.getString(R.string.notification_summary_small), return String.format(context.getString(R.string.notification_summary_small),
wrapItemAt(array, 1), wrapItemAt(array, 1),
wrapItemAt(array, 0)); wrapItemAt(array, 0));
@ -676,7 +672,7 @@ public class NotificationHelper {
@Nullable @Nullable
private static String titleForType(Context context, Notification notification, AccountEntity account) { private static String titleForType(Context context, Notification notification, AccountEntity account) {
String accountName = StringUtils.unicodeWrap(notification.getAccount().getName()); String accountName = StringUtils.unicodeWrap(notification.getAccount().getName());
switch (notification.getType()) { switch(notification.getType()) {
case MENTION: case MENTION:
return String.format(context.getString(R.string.notification_mention_format), return String.format(context.getString(R.string.notification_mention_format),
accountName); accountName);
@ -711,11 +707,12 @@ public class NotificationHelper {
return String.format(context.getString(R.string.notification_move_format), accountName); return String.format(context.getString(R.string.notification_move_format), accountName);
} }
} }
return null; return null;
} }
private static String bodyForType(Notification notification, Context context) { private static String bodyForType(Notification notification, Context context) {
switch (notification.getType()) { switch(notification.getType()) {
case MOVE: case MOVE:
return "@" + notification.getTarget().getUsername(); return "@" + notification.getTarget().getUsername();
case FOLLOW: case FOLLOW:
@ -726,19 +723,19 @@ public class NotificationHelper {
case REBLOG: case REBLOG:
case EMOJI_REACTION: case EMOJI_REACTION:
case STATUS: case STATUS:
if (!TextUtils.isEmpty(notification.getStatus().getSpoilerText())) { if(!TextUtils.isEmpty(notification.getStatus().getSpoilerText())) {
return notification.getStatus().getSpoilerText(); return notification.getStatus().getSpoilerText();
} else { } else {
return notification.getStatus().getContent().toString(); return notification.getStatus().getContent().toString();
} }
case POLL: case POLL:
if (!TextUtils.isEmpty(notification.getStatus().getSpoilerText())) { if(!TextUtils.isEmpty(notification.getStatus().getSpoilerText())) {
return notification.getStatus().getSpoilerText(); return notification.getStatus().getSpoilerText();
} else { } else {
StringBuilder builder = new StringBuilder(notification.getStatus().getContent()); StringBuilder builder = new StringBuilder(notification.getStatus().getContent());
builder.append('\n'); builder.append('\n');
Poll poll = notification.getStatus().getPoll(); Poll poll = notification.getStatus().getPoll();
for(PollOption option: poll.getOptions()) { for(PollOption option : poll.getOptions()) {
builder.append(buildDescription(option.getTitle(), builder.append(buildDescription(option.getTitle(),
PollViewDataKt.calculatePercent(option.getVotesCount(), poll.getVotersCount(), poll.getVotesCount()), PollViewDataKt.calculatePercent(option.getVotesCount(), poll.getVotersCount(), poll.getVotesCount()),
context)); context));
@ -747,7 +744,7 @@ public class NotificationHelper {
return builder.toString(); return builder.toString();
} }
case CHAT_MESSAGE: case CHAT_MESSAGE:
if (!TextUtils.isEmpty(notification.getChatMessage().getContent())) { if(!TextUtils.isEmpty(notification.getChatMessage().getContent())) {
return notification.getChatMessage().getContent().toString(); return notification.getChatMessage().getContent().toString();
} else if(notification.getChatMessage().getAttachment() != null) { } else if(notification.getChatMessage().getAttachment() != null) {
return context.getString(notification.getChatMessage().getAttachment().describeAttachmentType()); return context.getString(notification.getChatMessage().getAttachment().describeAttachmentType());
@ -760,4 +757,10 @@ public class NotificationHelper {
return null; return null;
} }
public static int pendingIntentFlags(boolean mutable) {
return (PendingIntent.FLAG_UPDATE_CURRENT
| (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ?
(mutable ? PendingIntent.FLAG_MUTABLE : PendingIntent.FLAG_IMMUTABLE) : 0)
);
}
} }

View file

@ -1,3 +1,23 @@
/*
* Husky -- A Pleroma client for Android
*
* Copyright (C) 2022 The Husky Developers
* Copyright (C) 2020 Alibek Omarov
*
* 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.
*
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.keylesspalace.tusky.service package com.keylesspalace.tusky.service
import android.app.NotificationChannel import android.app.NotificationChannel
@ -222,15 +242,15 @@ class StreamingService : Service(), Injectable {
return object : WebSocketListener() { return object : WebSocketListener() {
override fun onOpen(webSocket: WebSocket, response: Response) { override fun onOpen(webSocket: WebSocket, response: Response) {
Timber.d("Stream connected to: $tag") Timber.d("Stream connected to: $tag. Response[$response]")
} }
override fun onClosed(webSocket: WebSocket, code: Int, reason: String) { override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
Timber.d("Stream closed for: $tag") Timber.d("Stream closed for: $tag. Reason[$reason]")
} }
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
Timber.e("Stream failed for $tag", t) Timber.e("Stream failed for $tag: $t. Response[$response]")
} }
override fun onMessage(webSocket: WebSocket, text: String) { override fun onMessage(webSocket: WebSocket, text: String) {