From 376653cb3fd10403a1a2cbb0dbba6ddfa67c60e2 Mon Sep 17 00:00:00 2001 From: sim Date: Tue, 14 Jan 2025 16:00:54 +0100 Subject: [PATCH 1/6] Update UnifiedPush lib --- mastodon/build.gradle | 2 +- .../UnifiedPushNotificationReceiver.java | 15 +++++++++----- .../api/session/AccountSessionManager.java | 8 ++++---- .../SettingsNotificationsFragment.java | 20 +++++++++---------- settings.gradle | 13 ++++++------ 5 files changed, 31 insertions(+), 27 deletions(-) diff --git a/mastodon/build.gradle b/mastodon/build.gradle index 89dd342077..ac1d53c620 100644 --- a/mastodon/build.gradle +++ b/mastodon/build.gradle @@ -164,7 +164,7 @@ dependencies { implementation 'com.github.bottom-software-foundation:bottom-java:2.1.0' annotationProcessor 'org.parceler:parceler:1.1.12' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3' - implementation 'com.github.UnifiedPush:android-connector:2.1.1' + implementation 'org.unifiedpush.android:connector:3.0.2' androidTestImplementation 'androidx.test:core:1.5.0' androidTestImplementation 'androidx.test.ext:junit:1.1.5' diff --git a/mastodon/src/main/java/org/joinmastodon/android/UnifiedPushNotificationReceiver.java b/mastodon/src/main/java/org/joinmastodon/android/UnifiedPushNotificationReceiver.java index 4760fd1112..dd648d7ea3 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/UnifiedPushNotificationReceiver.java +++ b/mastodon/src/main/java/org/joinmastodon/android/UnifiedPushNotificationReceiver.java @@ -9,10 +9,14 @@ import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.model.Notification; import org.joinmastodon.android.model.PaginatedResponse; +import org.unifiedpush.android.connector.FailedReason; import org.unifiedpush.android.connector.MessagingReceiver; +import org.unifiedpush.android.connector.data.PushEndpoint; +import org.unifiedpush.android.connector.data.PushMessage; import java.util.List; +import kotlin.text.Charsets; import me.grishka.appkit.api.Callback; import me.grishka.appkit.api.ErrorResponse; @@ -24,16 +28,16 @@ public UnifiedPushNotificationReceiver() { } @Override - public void onNewEndpoint(@NotNull Context context, @NotNull String endpoint, @NotNull String instance) { + public void onNewEndpoint(@NotNull Context context, @NotNull PushEndpoint endpoint, @NotNull String instance) { // Called when a new endpoint be used for sending push messages - Log.d(TAG, "onNewEndpoint: New Endpoint " + endpoint + " for "+ instance); + Log.d(TAG, "onNewEndpoint: New Endpoint " + endpoint.getUrl() + " for "+ instance); AccountSession account = AccountSessionManager.getInstance().tryGetAccount(instance); if (account != null) - account.getPushSubscriptionManager().registerAccountForPush(null, endpoint); + account.getPushSubscriptionManager().registerAccountForPush(null, endpoint.getUrl()); } @Override - public void onRegistrationFailed(@NotNull Context context, @NotNull String instance) { + public void onRegistrationFailed(@NotNull Context context, @NotNull FailedReason reason, @NotNull String instance) { // called when the registration is not possible, eg. no network Log.d(TAG, "onRegistrationFailed: " + instance); //re-register for gcm @@ -53,7 +57,8 @@ public void onUnregistered(@NotNull Context context, @NotNull String instance) { } @Override - public void onMessage(@NotNull Context context, @NotNull byte[] message, @NotNull String instance) { + public void onMessage(@NotNull Context context, @NotNull PushMessage message, @NotNull String instance) { + Log.d(TAG, "New message for " + instance); // Called when a new message is received. The message contains the full POST body of the push message AccountSession account = AccountSessionManager.getInstance().tryGetAccount(instance); diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java index 58252c51a6..62a6dd9db6 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java @@ -127,12 +127,12 @@ public void addAccount(Instance instance, Token token, Account self, Application MastodonAPIController.runInBackground(()->writeInstanceInfoFile(wrapper, instance.uri)); updateMoreInstanceInfo(instance, instance.uri); - if (!UnifiedPush.getDistributor(context).isEmpty()) { - UnifiedPush.registerApp( + if (UnifiedPush.getAckDistributor(context) != null) { + UnifiedPush.register( context, session.getID(), - new ArrayList<>(), - context.getPackageName() + null, + null ); } else if(PushSubscriptionManager.arePushNotificationsAvailable()){ session.getPushSubscriptionManager().registerAccountForPush(null); diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsNotificationsFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsNotificationsFragment.java index 60804ecccc..c6c2997b55 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsNotificationsFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsNotificationsFragment.java @@ -72,7 +72,7 @@ public void onCreate(Bundle savedInstanceState){ lp=AccountSessionManager.get(accountID).getLocalPreferences(); getPushSubscription(); - useUnifiedPush=!UnifiedPush.getDistributor(getContext()).isEmpty(); + useUnifiedPush=UnifiedPush.getAckDistributor(getContext()) != null; onDataLoaded(List.of( pauseItem=new CheckableListItem<>(getString(R.string.pause_all_notifications), getPauseItemSubtitle(), CheckableListItem.Style.SWITCH, false, R.drawable.ic_fluent_alert_snooze_24_regular, i->onPauseNotificationsClick(false)), @@ -94,7 +94,7 @@ public void onCreate(Bundle savedInstanceState){ )); //only enable when distributors, who can receive notifications, are available - unifiedPushItem.isEnabled=!UnifiedPush.getDistributors(getContext(), new ArrayList<>()).isEmpty(); + unifiedPushItem.isEnabled=!UnifiedPush.getDistributors(getContext()).isEmpty(); if (!unifiedPushItem.isEnabled) { unifiedPushItem.subtitleRes=R.string.sk_settings_unifiedpush_no_distributor_body; } @@ -316,12 +316,12 @@ private void updateBanner(){ bannerText.setText(R.string.notifications_disabled_in_system); bannerButton.setText(R.string.open_system_notification_settings); bannerButton.setOnClickListener(v->openSystemNotificationSettings()); - }else if(BuildConfig.BUILD_TYPE.equals("fdroidRelease") && UnifiedPush.getDistributor(getContext()).isEmpty()){ + }else if(BuildConfig.BUILD_TYPE.equals("fdroidRelease") && UnifiedPush.getAckDistributor(getContext()) != null){ bannerAdapter.setVisible(true); bannerIcon.setImageResource(R.drawable.ic_fluent_warning_24_filled); bannerTitle.setVisibility(View.VISIBLE); bannerTitle.setText(R.string.mo_settings_unifiedpush_warning); - if(UnifiedPush.getDistributors(getContext(), new ArrayList<>()).isEmpty()) { + if(UnifiedPush.getDistributors(getContext()).isEmpty()) { bannerText.setText(R.string.mo_settings_unifiedpush_warning_no_distributors); bannerButton.setText(R.string.info); bannerButton.setOnClickListener(v->UiUtils.launchWebBrowser(getContext(), "https://unifiedpush.org/")); @@ -342,14 +342,14 @@ private void updateBanner(){ } private void onUnifiedPushClick(){ - if(UnifiedPush.getDistributor(getContext()).isEmpty()){ - List distributors = UnifiedPush.getDistributors(getContext(), new ArrayList<>()); + if(UnifiedPush.getAckDistributor(getContext()) == null){ + List distributors = UnifiedPush.getDistributors(getContext()); showUnifiedPushRegisterDialog(distributors); return; } for (AccountSession accountSession : AccountSessionManager.getInstance().getLoggedInAccounts()) { - UnifiedPush.unregisterApp( + UnifiedPush.unregister( getContext(), accountSession.getID() ); @@ -367,11 +367,11 @@ private void showUnifiedPushRegisterDialog(List distributors){ String userDistrib = distributors.get(which); UnifiedPush.saveDistributor(getContext(), userDistrib); for (AccountSession accountSession : AccountSessionManager.getInstance().getLoggedInAccounts()){ - UnifiedPush.registerApp( + UnifiedPush.register( getContext(), accountSession.getID(), - new ArrayList<>(), - getContext().getPackageName() + null, + null ); } unifiedPushItem.toggle(); diff --git a/settings.gradle b/settings.gradle index a4a0c62018..09a0c536e6 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,12 +2,6 @@ pluginManagement { repositories { google() mavenCentral() - maven { - url "https://www.jitpack.io" - content { - includeModule 'com.github.UnifiedPush', 'android-connector' - } - } mavenLocal() } } @@ -17,7 +11,12 @@ dependencyResolutionManagement { google() mavenCentral() mavenLocal() - maven { url 'https://jitpack.io' } + maven { + url 'https://jitpack.io' + content { + includeModule 'com.github.bottom-software-foundation', 'bottom-java' + } + } } } rootProject.name = "Moshidon" From 00e90e5f21a53a8ab2122548d327d55f41068c15 Mon Sep 17 00:00:00 2001 From: sim Date: Tue, 14 Jan 2025 16:04:27 +0100 Subject: [PATCH 2/6] Use standard webpush when available --- .../android/PushNotificationReceiver.java | 2 +- .../UnifiedPushNotificationReceiver.java | 48 +++++++++++++++---- .../android/api/PushSubscriptionManager.java | 13 +++-- .../RegisterForPushNotifications.java | 2 + 4 files changed, 52 insertions(+), 13 deletions(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/PushNotificationReceiver.java b/mastodon/src/main/java/org/joinmastodon/android/PushNotificationReceiver.java index b26ba5fa76..49e402f4d7 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/PushNotificationReceiver.java +++ b/mastodon/src/main/java/org/joinmastodon/android/PushNotificationReceiver.java @@ -163,7 +163,7 @@ public void notifyUnifiedPush(Context context, AccountSession account, org.joinm PushNotificationReceiver.this.notify(context, PushNotification.fromNotification(context, account, notification), account.getID(), notification); } - private void notify(Context context, PushNotification pn, String accountID, org.joinmastodon.android.model.Notification notification){ + void notify(Context context, PushNotification pn, String accountID, org.joinmastodon.android.model.Notification notification){ NotificationManager nm=context.getSystemService(NotificationManager.class); AccountSession session=AccountSessionManager.get(accountID); Account self=session.self; diff --git a/mastodon/src/main/java/org/joinmastodon/android/UnifiedPushNotificationReceiver.java b/mastodon/src/main/java/org/joinmastodon/android/UnifiedPushNotificationReceiver.java index dd648d7ea3..7e2b452ed6 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/UnifiedPushNotificationReceiver.java +++ b/mastodon/src/main/java/org/joinmastodon/android/UnifiedPushNotificationReceiver.java @@ -5,16 +5,20 @@ import org.jetbrains.annotations.NotNull; import org.joinmastodon.android.api.MastodonAPIController; +import org.joinmastodon.android.api.requests.notifications.GetNotificationByID; import org.joinmastodon.android.api.session.AccountSession; import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.model.Notification; import org.joinmastodon.android.model.PaginatedResponse; +import org.joinmastodon.android.model.PushNotification; import org.unifiedpush.android.connector.FailedReason; import org.unifiedpush.android.connector.MessagingReceiver; +import org.unifiedpush.android.connector.data.PublicKeySet; import org.unifiedpush.android.connector.data.PushEndpoint; import org.unifiedpush.android.connector.data.PushMessage; import java.util.List; +import java.util.function.Function; import kotlin.text.Charsets; import me.grishka.appkit.api.Callback; @@ -32,8 +36,15 @@ public void onNewEndpoint(@NotNull Context context, @NotNull PushEndpoint endpoi // Called when a new endpoint be used for sending push messages Log.d(TAG, "onNewEndpoint: New Endpoint " + endpoint.getUrl() + " for "+ instance); AccountSession account = AccountSessionManager.getInstance().tryGetAccount(instance); - if (account != null) - account.getPushSubscriptionManager().registerAccountForPush(null, endpoint.getUrl()); + if (account != null) { + PublicKeySet ks = endpoint.getPubKeySet(); + if (ks != null){ + account.getPushSubscriptionManager().registerAccountForPush(null, endpoint.getUrl(), ks.getPubKey(), ks.getAuth()); + } else { + // ks should never be null on new endpoint + account.getPushSubscriptionManager().registerAccountForPush(null, endpoint.getUrl()); + } + } } @Override @@ -65,19 +76,38 @@ public void onMessage(@NotNull Context context, @NotNull PushMessage message, @N if (account == null) return; - //this is stupid - // Mastodon stores the info to decrypt the message in the HTTP headers, which are not accessible in UnifiedPush, - // thus it is not possible to decrypt them. SO we need to re-request them from the server and transform them later on - // The official uses fcm and moves the headers to extra data, see - // https://github.com/mastodon/webpush-fcm-relay/blob/cac95b28d5364b0204f629283141ac3fb749e0c5/webpush-fcm-relay.go#L116 - // https://github.com/tuskyapp/Tusky/pull/2303#issue-1112080540 + if (message.getDecrypted()) { + // If the mastodon server supports the standard webpush, we can directly use the content + Log.d(TAG, "Push message correctly decrypted"); + PushNotification pn = MastodonAPIController.gson.fromJson(new String(message.getContent(), Charsets.UTF_8), PushNotification.class); + new GetNotificationByID(pn.notificationId) + .setCallback(new Callback<>(){ + @Override + public void onSuccess(org.joinmastodon.android.model.Notification result){ + MastodonAPIController.runInBackground(()->new PushNotificationReceiver().notify(context, pn, instance, result)); + } + + @Override + public void onError(ErrorResponse error){ + MastodonAPIController.runInBackground(()-> new PushNotificationReceiver().notify(context, pn, instance, null)); + } + }) + .exec(instance); + } else { + // else, we have to sync with the server + Log.d(TAG, "Server doesn't support standard webpush, fetching one notification"); + fetchOneNotification(context, account, (notif) -> () -> new PushNotificationReceiver().notifyUnifiedPush(context, account, notif)); + } + } + + private void fetchOneNotification(@NotNull Context context, @NotNull AccountSession account, @NotNull Function callback) { account.getCacheController().getNotifications(null, 1, false, false, true, new Callback<>(){ @Override public void onSuccess(PaginatedResponse> result){ result.items .stream() .findFirst() - .ifPresent(value->MastodonAPIController.runInBackground(()->new PushNotificationReceiver().notifyUnifiedPush(context, account, value))); + .ifPresent(value->MastodonAPIController.runInBackground(callback.apply(value))); } @Override diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/PushSubscriptionManager.java b/mastodon/src/main/java/org/joinmastodon/android/api/PushSubscriptionManager.java index 046c555316..0e757910b5 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/PushSubscriptionManager.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/PushSubscriptionManager.java @@ -169,9 +169,16 @@ public void registerAccountForPush(PushSubscription subscription, String endpoin if (endpoint.startsWith("https://app.joinmastodon.org/relay-to/fcm/")) newEndpoint += pushAccountID; - new RegisterForPushNotifications(newEndpoint, - encodedPublicKey, - encodedAuthKey, + registerAccountForPush(subscription, newEndpoint, encodedPublicKey, encodedAuthKey); + }); + } + + public void registerAccountForPush(PushSubscription subscription, String endpoint, String p256dh, String auth){ + MastodonAPIController.runInBackground(()->{ + Log.d(TAG, "registerAccountForPush: started for "+accountID); + new RegisterForPushNotifications(endpoint, + p256dh, + auth, subscription==null ? PushSubscription.Alerts.ofAll() : subscription.alerts, subscription==null ? PushSubscription.Policy.ALL : subscription.policy) .setCallback(new Callback<>(){ diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/requests/notifications/RegisterForPushNotifications.java b/mastodon/src/main/java/org/joinmastodon/android/api/requests/notifications/RegisterForPushNotifications.java index fb6cabcd97..18bd028848 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/requests/notifications/RegisterForPushNotifications.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/requests/notifications/RegisterForPushNotifications.java @@ -27,6 +27,8 @@ private static class Keys{ private static class Subscription{ public String endpoint; + // Use standard push notifications if available + public Boolean standard = true; public Keys keys=new Keys(); } From 66824aadb9ff924c753bebc5c3b8059c8208037a Mon Sep 17 00:00:00 2001 From: sim Date: Tue, 14 Jan 2025 16:13:31 +0100 Subject: [PATCH 3/6] Use standard webpush for UnifiedPush only --- .../android/UnifiedPushNotificationReceiver.java | 2 +- .../android/api/PushSubscriptionManager.java | 12 ++++++++---- .../notifications/RegisterForPushNotifications.java | 5 +++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/UnifiedPushNotificationReceiver.java b/mastodon/src/main/java/org/joinmastodon/android/UnifiedPushNotificationReceiver.java index 7e2b452ed6..dcad18895b 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/UnifiedPushNotificationReceiver.java +++ b/mastodon/src/main/java/org/joinmastodon/android/UnifiedPushNotificationReceiver.java @@ -39,7 +39,7 @@ public void onNewEndpoint(@NotNull Context context, @NotNull PushEndpoint endpoi if (account != null) { PublicKeySet ks = endpoint.getPubKeySet(); if (ks != null){ - account.getPushSubscriptionManager().registerAccountForPush(null, endpoint.getUrl(), ks.getPubKey(), ks.getAuth()); + account.getPushSubscriptionManager().registerAccountForPush(null, true, endpoint.getUrl(), ks.getPubKey(), ks.getAuth()); } else { // ks should never be null on new endpoint account.getPushSubscriptionManager().registerAccountForPush(null, endpoint.getUrl()); diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/PushSubscriptionManager.java b/mastodon/src/main/java/org/joinmastodon/android/api/PushSubscriptionManager.java index 0e757910b5..d913f6f723 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/PushSubscriptionManager.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/PushSubscriptionManager.java @@ -166,17 +166,21 @@ public void registerAccountForPush(PushSubscription subscription, String endpoin //work-around for adding the randomAccountId String newEndpoint = endpoint; - if (endpoint.startsWith("https://app.joinmastodon.org/relay-to/fcm/")) - newEndpoint += pushAccountID; + Boolean standard = true; + if (endpoint.startsWith("https://app.joinmastodon.org/relay-to/fcm/")){ + newEndpoint+=pushAccountID; + standard = false; + } - registerAccountForPush(subscription, newEndpoint, encodedPublicKey, encodedAuthKey); + registerAccountForPush(subscription, standard, newEndpoint, encodedPublicKey, encodedAuthKey); }); } - public void registerAccountForPush(PushSubscription subscription, String endpoint, String p256dh, String auth){ + public void registerAccountForPush(PushSubscription subscription, Boolean standard, String endpoint, String p256dh, String auth){ MastodonAPIController.runInBackground(()->{ Log.d(TAG, "registerAccountForPush: started for "+accountID); new RegisterForPushNotifications(endpoint, + standard, p256dh, auth, subscription==null ? PushSubscription.Alerts.ofAll() : subscription.alerts, diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/requests/notifications/RegisterForPushNotifications.java b/mastodon/src/main/java/org/joinmastodon/android/api/requests/notifications/RegisterForPushNotifications.java index 18bd028848..ae29298eb8 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/requests/notifications/RegisterForPushNotifications.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/requests/notifications/RegisterForPushNotifications.java @@ -4,10 +4,11 @@ import org.joinmastodon.android.model.PushSubscription; public class RegisterForPushNotifications extends MastodonAPIRequest{ - public RegisterForPushNotifications(String endpoint, String encryptionKey, String authKey, PushSubscription.Alerts alerts, PushSubscription.Policy policy){ + public RegisterForPushNotifications(String endpoint, Boolean standard, String encryptionKey, String authKey, PushSubscription.Alerts alerts, PushSubscription.Policy policy){ super(HttpMethod.POST, "/push/subscription", PushSubscription.class); Request r=new Request(); r.subscription.endpoint=endpoint; + r.subscription.standard = standard; r.data.alerts=alerts; r.policy=policy; r.subscription.keys.p256dh=encryptionKey; @@ -28,7 +29,7 @@ private static class Keys{ private static class Subscription{ public String endpoint; // Use standard push notifications if available - public Boolean standard = true; + public Boolean standard; public Keys keys=new Keys(); } From cc4558458c81881638a1cfd03f900d90a15c2ed0 Mon Sep 17 00:00:00 2001 From: sim Date: Tue, 14 Jan 2025 16:53:00 +0100 Subject: [PATCH 4/6] Add Helper for some UnifiedPush functions --- .../api/session/AccountSessionManager.java | 3 +- .../SettingsNotificationsFragment.java | 35 +++++-------- .../android/utils/UnifiedPushHelper.java | 51 +++++++++++++++++++ 3 files changed, 65 insertions(+), 24 deletions(-) create mode 100644 mastodon/src/main/java/org/joinmastodon/android/utils/UnifiedPushHelper.java diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java index 62a6dd9db6..e37e2b698c 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java @@ -34,6 +34,7 @@ import org.joinmastodon.android.model.LegacyFilter; import org.joinmastodon.android.model.Instance; import org.joinmastodon.android.model.Token; +import org.joinmastodon.android.utils.UnifiedPushHelper; import org.unifiedpush.android.connector.UnifiedPush; import java.io.File; @@ -127,7 +128,7 @@ public void addAccount(Instance instance, Token token, Account self, Application MastodonAPIController.runInBackground(()->writeInstanceInfoFile(wrapper, instance.uri)); updateMoreInstanceInfo(instance, instance.uri); - if (UnifiedPush.getAckDistributor(context) != null) { + if (UnifiedPushHelper.isUnifiedPushEnabled(context)) { UnifiedPush.register( context, session.getID(), diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsNotificationsFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsNotificationsFragment.java index c6c2997b55..ac22670c62 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsNotificationsFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsNotificationsFragment.java @@ -26,6 +26,7 @@ import org.joinmastodon.android.ui.M3AlertDialogBuilder; import org.joinmastodon.android.ui.utils.HideableSingleViewRecyclerAdapter; import org.joinmastodon.android.ui.utils.UiUtils; +import org.joinmastodon.android.utils.UnifiedPushHelper; import org.unifiedpush.android.connector.UnifiedPush; import java.time.Instant; @@ -57,6 +58,7 @@ public class SettingsNotificationsFragment extends BaseSettingsFragment{ // MEGALODON private boolean useUnifiedPush = false; + private boolean hasAnyUnifiedPushDistrib = false; private CheckableListItem uniformIconItem, deleteItem, onlyLatestItem, unifiedPushItem; private CheckableListItem postsItem, updateItem; @@ -72,7 +74,8 @@ public void onCreate(Bundle savedInstanceState){ lp=AccountSessionManager.get(accountID).getLocalPreferences(); getPushSubscription(); - useUnifiedPush=UnifiedPush.getAckDistributor(getContext()) != null; + useUnifiedPush=UnifiedPushHelper.isUnifiedPushEnabled(getContext()); + hasAnyUnifiedPushDistrib=UnifiedPushHelper.hasAnyDistributorInstalled(getContext()); onDataLoaded(List.of( pauseItem=new CheckableListItem<>(getString(R.string.pause_all_notifications), getPauseItemSubtitle(), CheckableListItem.Style.SWITCH, false, R.drawable.ic_fluent_alert_snooze_24_regular, i->onPauseNotificationsClick(false)), @@ -94,7 +97,7 @@ public void onCreate(Bundle savedInstanceState){ )); //only enable when distributors, who can receive notifications, are available - unifiedPushItem.isEnabled=!UnifiedPush.getDistributors(getContext()).isEmpty(); + unifiedPushItem.isEnabled=hasAnyUnifiedPushDistrib; if (!unifiedPushItem.isEnabled) { unifiedPushItem.subtitleRes=R.string.sk_settings_unifiedpush_no_distributor_body; } @@ -316,12 +319,12 @@ private void updateBanner(){ bannerText.setText(R.string.notifications_disabled_in_system); bannerButton.setText(R.string.open_system_notification_settings); bannerButton.setOnClickListener(v->openSystemNotificationSettings()); - }else if(BuildConfig.BUILD_TYPE.equals("fdroidRelease") && UnifiedPush.getAckDistributor(getContext()) != null){ + }else if(BuildConfig.BUILD_TYPE.equals("fdroidRelease") && useUnifiedPush){ bannerAdapter.setVisible(true); bannerIcon.setImageResource(R.drawable.ic_fluent_warning_24_filled); bannerTitle.setVisibility(View.VISIBLE); bannerTitle.setText(R.string.mo_settings_unifiedpush_warning); - if(UnifiedPush.getDistributors(getContext()).isEmpty()) { + if(!hasAnyUnifiedPushDistrib) { bannerText.setText(R.string.mo_settings_unifiedpush_warning_no_distributors); bannerButton.setText(R.string.info); bannerButton.setOnClickListener(v->UiUtils.launchWebBrowser(getContext(), "https://unifiedpush.org/")); @@ -342,23 +345,15 @@ private void updateBanner(){ } private void onUnifiedPushClick(){ - if(UnifiedPush.getAckDistributor(getContext()) == null){ + if(!useUnifiedPush){ List distributors = UnifiedPush.getDistributors(getContext()); showUnifiedPushRegisterDialog(distributors); return; } - - for (AccountSession accountSession : AccountSessionManager.getInstance().getLoggedInAccounts()) { - UnifiedPush.unregister( - getContext(), - accountSession.getID() - ); - - //re-register to fcm - accountSession.getPushSubscriptionManager().registerAccountForPush(getPushSubscription()); - } + UnifiedPushHelper.unregisterAllAccounts(getContext()); unifiedPushItem.toggle(); rebindItem(unifiedPushItem); + useUnifiedPush = false; } private void showUnifiedPushRegisterDialog(List distributors){ @@ -366,16 +361,10 @@ private void showUnifiedPushRegisterDialog(List distributors){ (dialog, which)->{ String userDistrib = distributors.get(which); UnifiedPush.saveDistributor(getContext(), userDistrib); - for (AccountSession accountSession : AccountSessionManager.getInstance().getLoggedInAccounts()){ - UnifiedPush.register( - getContext(), - accountSession.getID(), - null, - null - ); - } + UnifiedPushHelper.registerAllAccounts(getContext()); unifiedPushItem.toggle(); rebindItem(unifiedPushItem); + useUnifiedPush = true; }).setOnCancelListener(d->rebindItem(unifiedPushItem)).show(); } diff --git a/mastodon/src/main/java/org/joinmastodon/android/utils/UnifiedPushHelper.java b/mastodon/src/main/java/org/joinmastodon/android/utils/UnifiedPushHelper.java new file mode 100644 index 0000000000..aba3ca8640 --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/utils/UnifiedPushHelper.java @@ -0,0 +1,51 @@ +package org.joinmastodon.android.utils; + +import android.content.Context; + +import androidx.annotation.NonNull; + +import org.joinmastodon.android.api.session.AccountSession; +import org.joinmastodon.android.api.session.AccountSessionManager; +import org.unifiedpush.android.connector.UnifiedPush; + +public class UnifiedPushHelper { + + /** + * @param context + * @return `true` if UnifiedPush is used + */ + public static boolean isUnifiedPushEnabled(@NonNull Context context) { + return UnifiedPush.getAckDistributor(context) != null; + } + + /** + * If any distributor is installed on the device + * @param context + * @return `true` if at least one is installed + */ + public static boolean hasAnyDistributorInstalled(@NonNull Context context) { + return !UnifiedPush.getDistributors(context).isEmpty(); + } + + public static void registerAllAccounts(@NonNull Context context) { + for (AccountSession accountSession : AccountSessionManager.getInstance().getLoggedInAccounts()){ + UnifiedPush.register( + context, + accountSession.getID(), + null, + null + ); + } + } + + public static void unregisterAllAccounts(@NonNull Context context) { + for (AccountSession accountSession : AccountSessionManager.getInstance().getLoggedInAccounts()){ + UnifiedPush.unregister( + context, + accountSession.getID() + ); + // use FCM again + accountSession.getPushSubscriptionManager().registerAccountForPush(null); + } + } +} From 7cd756f6b0d4f53bb7d81cf3fa65920a0d36a621 Mon Sep 17 00:00:00 2001 From: sim Date: Tue, 14 Jan 2025 16:53:18 +0100 Subject: [PATCH 5/6] Re-register UnifiedPush when application starts --- .../main/java/org/joinmastodon/android/MastodonApp.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/MastodonApp.java b/mastodon/src/main/java/org/joinmastodon/android/MastodonApp.java index 48cc95cb3e..763067ed75 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/MastodonApp.java +++ b/mastodon/src/main/java/org/joinmastodon/android/MastodonApp.java @@ -6,6 +6,7 @@ import android.webkit.WebView; import org.joinmastodon.android.api.PushSubscriptionManager; +import org.joinmastodon.android.utils.UnifiedPushHelper; import me.grishka.appkit.imageloader.ImageCache; import me.grishka.appkit.utils.NetworkUtils; @@ -27,7 +28,11 @@ public void onCreate(){ ImageCache.setParams(params); NetworkUtils.setUserAgent("MoshidonAndroid/"+BuildConfig.VERSION_NAME); - PushSubscriptionManager.tryRegisterFCM(); + if (UnifiedPushHelper.isUnifiedPushEnabled(this)){ + UnifiedPushHelper.registerAllAccounts(this); + } else { + PushSubscriptionManager.tryRegisterFCM(); + } GlobalUserPreferences.load(); if(BuildConfig.DEBUG){ WebView.setWebContentsDebuggingEnabled(true); From 281e98974967175a23814e9d143b83866488c858 Mon Sep 17 00:00:00 2001 From: sim Date: Tue, 21 Jan 2025 17:58:24 +0100 Subject: [PATCH 6/6] Use server VAPID keys --- .../joinmastodon/android/api/session/AccountSessionManager.java | 2 +- .../java/org/joinmastodon/android/utils/UnifiedPushHelper.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java index e37e2b698c..e09649a62d 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java @@ -133,7 +133,7 @@ public void addAccount(Instance instance, Token token, Account self, Application context, session.getID(), null, - null + session.app.vapidKey.replaceAll("=","") ); } else if(PushSubscriptionManager.arePushNotificationsAvailable()){ session.getPushSubscriptionManager().registerAccountForPush(null); diff --git a/mastodon/src/main/java/org/joinmastodon/android/utils/UnifiedPushHelper.java b/mastodon/src/main/java/org/joinmastodon/android/utils/UnifiedPushHelper.java index aba3ca8640..af78d845e8 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/utils/UnifiedPushHelper.java +++ b/mastodon/src/main/java/org/joinmastodon/android/utils/UnifiedPushHelper.java @@ -33,7 +33,7 @@ public static void registerAllAccounts(@NonNull Context context) { context, accountSession.getID(), null, - null + accountSession.app.vapidKey.replaceAll("=","") ); } }