Skip to content

Commit

Permalink
Use bulk notification method
Browse files Browse the repository at this point in the history
  • Loading branch information
Lakoja committed Jan 12, 2025
1 parent 5b872a1 commit 0fa77a1
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package com.keylesspalace.tusky.components.systemnotifications

import android.Manifest
import android.app.NotificationManager
import android.content.Context
import android.content.pm.PackageManager
import android.util.Log
import androidx.annotation.WorkerThread
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationManagerCompat
import com.keylesspalace.tusky.appstore.EventHub
import com.keylesspalace.tusky.appstore.NewNotificationsEvent
import com.keylesspalace.tusky.components.systemnotifications.NotificationHelper.filterNotification
Expand All @@ -16,8 +20,6 @@ import com.keylesspalace.tusky.util.HttpHeaderLink
import com.keylesspalace.tusky.util.isLessThan
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.delay

/** Models next/prev links from the "Links" header in an API response */
data class Links(val next: String?, val prev: String?) {
Expand Down Expand Up @@ -52,13 +54,19 @@ class NotificationFetcher @Inject constructor(
private val eventHub: EventHub
) {
suspend fun fetchAndShow() {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
return
}

for (account in accountManager.getAllAccountsOrderedByActive()) {
if (account.notificationsEnabled) {
try {
val notificationManager = context.getSystemService(
Context.NOTIFICATION_SERVICE
) as NotificationManager

val notificationManagerCompat = NotificationManagerCompat.from(context)

// Create sorted list of new notifications
val notifications = fetchNewNotifications(account)
.filter { filterNotification(notificationManager, account, it) }
Expand All @@ -70,37 +78,38 @@ class NotificationFetcher @Inject constructor(
// (and should therefore adhere to the notification config).
eventHub.dispatch(NewNotificationsEvent(account.accountId, notifications))

val notificationsByType: Map<Notification.Type, List<Notification>> = notifications.groupBy { it.type }
val newNotifications = ArrayList<NotificationManagerCompat.NotificationWithIdAndTag>()

val notificationsByType: Map<Notification.Type, List<Notification>> = notifications.groupBy { it.type }
notificationsByType.forEach { notificationsGroup: Map.Entry<Notification.Type, List<Notification>> ->
// NOTE: Enqueue the summary first: Only this way one can avoid running into notification rate limits;
// which also would prohibit the group summary to be shown and thus proper grouping!
NotificationHelper.showSummaryNotification(
context,
notificationManager,
account,
notificationsGroup.key,
notificationsGroup.value
)

notificationsGroup.value.forEach { notification ->
val androidNotification = NotificationHelper.make(
// NOTE Enqueue the summary first: Needed to avoid rate limit problems:
// ie. single notification is enqueued but that later summary one is filtered and thus no grouping
// takes place.
newNotifications.add(
NotificationHelper.makeSummaryNotification(
context,
notificationManager,
notification,
account
account,
notificationsGroup.key,
notificationsGroup.value
)
notificationManager.notify(
notification.id,
account.id.toInt(),
androidNotification
)

notificationsGroup.value.forEach { notification ->
newNotifications.add(
NotificationHelper.make(
context,
notificationManager,
notification,
account
)
)
}

// NOTE this can schedule multiple (summary) notifications in short succession (normally 1-3).
// They can "collapse" to only one audible one if fast enough.
}

// NOTE having multiple summary notifications this here should still collapse them in only one occurrence
notificationManagerCompat.notify(newNotifications)

accountManager.saveAccount(account)
} catch (e: Exception) {
Log.e(TAG, "Error while fetching notifications", e)
Expand Down Expand Up @@ -153,8 +162,6 @@ class NotificationFetcher @Inject constructor(
Log.d(TAG, " localMarkerId: $localMarkerId")
Log.d(TAG, " readingPosition: $readingPosition")

minId = "1405569"

Log.d(TAG, "getting Notifications for ${account.fullName}, min_id: $minId")

// Fetch all outstanding notifications
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.app.RemoteInput;
import androidx.core.app.TaskStackBuilder;
import androidx.work.Constraints;
Expand Down Expand Up @@ -147,7 +148,16 @@ public class NotificationHelper {
* @return the new notification
*/
@NonNull
public static android.app.Notification make(final @NonNull Context context, @NonNull NotificationManager notificationManager, @NonNull Notification body, @NonNull AccountEntity account) {
public static NotificationManagerCompat.NotificationWithIdAndTag make(final @NonNull Context context, @NonNull NotificationManager notificationManager, @NonNull Notification body, @NonNull AccountEntity account) {
return new NotificationManagerCompat.NotificationWithIdAndTag(
body.getId(),
(int)account.getId(),
NotificationHelper.makeBaseNotification(context, notificationManager, body, account)
);
}

@NonNull
public static android.app.Notification makeBaseNotification(final @NonNull Context context, @NonNull NotificationManager notificationManager, @NonNull Notification body, @NonNull AccountEntity account) {
body = body.rewriteToStatusTypeIfNeeded(account.getAccountId());
String mastodonNotificationId = body.getId();
int accountId = (int) account.getId();
Expand Down Expand Up @@ -242,7 +252,7 @@ public static android.app.Notification make(final @NonNull Context context, @Non
}

/**
* Updates the summary notifications for each notification type.
* Creates the summary notifications for a notification type.
* <p>
* Notifications are sent to channels. Within each channel they are grouped and the group has a summary.
* <p>
Expand All @@ -255,13 +265,13 @@ public static android.app.Notification make(final @NonNull Context context, @Non
* @see <a href="https://developer.android.com/develop/ui/views/notifications/group">Create a
* notification group</a>
*/
public static void showSummaryNotification(@NonNull Context context, @NonNull NotificationManager notificationManager, @NonNull AccountEntity account, @NonNull Notification.Type type, @NonNull List<Notification> additionalNotifications) {
public static NotificationManagerCompat.NotificationWithIdAndTag makeSummaryNotification(@NonNull Context context, @NonNull NotificationManager notificationManager, @NonNull AccountEntity account, @NonNull Notification.Type type, @NonNull List<Notification> additionalNotifications) {
int accountId = (int) account.getId();

String typeChannelId = getChannelId(account, type);

if (typeChannelId == null) {
return;
return null;
}

// Create a notification that summarises the other notifications in this group
Expand Down Expand Up @@ -304,7 +314,8 @@ public static void showSummaryNotification(@NonNull Context context, @NonNull No
setSoundVibrationLight(account, summaryBuilder);

String summaryTag = GROUP_SUMMARY_TAG + "." + typeChannelId;
notificationManager.notify(summaryTag, accountId, summaryBuilder.build());

return new NotificationManagerCompat.NotificationWithIdAndTag(summaryTag, accountId, summaryBuilder.build());
}

private static List<StatusBarNotification> getActiveNotifications(StatusBarNotification[] allNotifications, int accountId, String typeChannelId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ class MainActivityTest {
NotificationHelper.createNotificationChannelsForAccount(accountEntity, context)

runInBackground {
val notification = NotificationHelper.make(
val notification = NotificationHelper.makeBaseNotification(
context,
notificationManager,
Notification(
Expand Down

0 comments on commit 0fa77a1

Please sign in to comment.