From ed0092a8bc9685830c8ce87347b8eae13558e9be Mon Sep 17 00:00:00 2001 From: reuk Date: Thu, 21 Nov 2024 22:06:42 +0000 Subject: [PATCH] PushNotifications: Assert instead of crashing if Android notification icon cannot be located --- .../native/juce_PushNotifications_android.cpp | 92 +++++++++++++------ 1 file changed, 64 insertions(+), 28 deletions(-) diff --git a/modules/juce_gui_extra/native/juce_PushNotifications_android.cpp b/modules/juce_gui_extra/native/juce_PushNotifications_android.cpp index e824c4e296..fcbefabd1d 100644 --- a/modules/juce_gui_extra/native/juce_PushNotifications_android.cpp +++ b/modules/juce_gui_extra/native/juce_PushNotifications_android.cpp @@ -276,7 +276,7 @@ bool PushNotifications::Notification::isValid() const noexcept //============================================================================== struct PushNotifications::Pimpl { - Pimpl (PushNotifications& p) + explicit Pimpl (PushNotifications& p) : owner (p) {} @@ -303,16 +303,18 @@ struct PushNotifications::Pimpl auto* env = getEnv(); - auto notificationManager = getNotificationManager(); - - if (notificationManager.get() != nullptr) + if (auto notificationManager = getNotificationManager()) { - auto notification = juceNotificationToJavaNotification (n); + if (auto notification = juceNotificationToJavaNotification (n)) + { + auto tag = javaString (n.identifier); + const int id = 0; - auto tag = javaString (n.identifier); - const int id = 0; - - env->CallVoidMethod (notificationManager.get(), NotificationManagerBase.notify, tag.get(), id, notification.get()); + env->CallVoidMethod (notificationManager.get(), + NotificationManagerBase.notify, + tag.get(), + id, notification.get()); + } } } @@ -607,11 +609,12 @@ struct PushNotifications::Pimpl auto notificationBuilder = createNotificationBuilder (n); - setupRequiredFields (n, notificationBuilder); - setupOptionalFields (n, notificationBuilder); + notificationBuilder = setupRequiredFields (n, notificationBuilder); + notificationBuilder = setupOptionalFields (n, notificationBuilder); + notificationBuilder = setupActions (n, notificationBuilder); - if (n.actions.size() > 0) - setupActions (n, notificationBuilder); + if (notificationBuilder == nullptr) + return notificationBuilder; return LocalRef (env->CallObjectMethod (notificationBuilder, NotificationBuilderApi16.build)); } @@ -648,8 +651,11 @@ struct PushNotifications::Pimpl return LocalRef (env->NewObject (builderClass, builderConstructor, context.get())); } - static void setupRequiredFields (const Notification& n, LocalRef& notificationBuilder) + static LocalRef setupRequiredFields (const Notification& n, LocalRef notificationBuilder) { + if (notificationBuilder == nullptr) + return notificationBuilder; + auto* env = getEnv(); LocalRef context (getMainActivity()); @@ -676,8 +682,16 @@ struct PushNotifications::Pimpl env->CallObjectMethod (notificationBuilder, NotificationBuilderBase.setContentIntent, notifyPendingIntent.get()); auto resources = LocalRef (env->CallObjectMethod (context.get(), AndroidContext.getResources)); - const int iconId = env->CallIntMethod (resources, AndroidResources.getIdentifier, javaString (n.icon).get(), - javaString ("raw").get(), packageNameString.get()); + const auto iconId = env->CallIntMethod (resources, AndroidResources.getIdentifier, javaString (n.icon).get(), + javaString ("raw").get(), packageNameString.get()); + + if (iconId == 0) + { + // If you hit this, the notification icon could not be located, and the notification + // will not be sent. + jassertfalse; + return {}; + } env->CallObjectMethod (notificationBuilder, NotificationBuilderBase.setSmallIcon, iconId); @@ -688,12 +702,17 @@ struct PushNotifications::Pimpl auto publicNotificationBuilder = createNotificationBuilder (n); - setupRequiredFields (*n.publicVersion, publicNotificationBuilder); - setupOptionalFields (*n.publicVersion, publicNotificationBuilder); + publicNotificationBuilder = setupRequiredFields (*n.publicVersion, publicNotificationBuilder); + publicNotificationBuilder = setupOptionalFields (*n.publicVersion, publicNotificationBuilder); + + if (publicNotificationBuilder == nullptr) + return {}; auto publicVersion = LocalRef (env->CallObjectMethod (publicNotificationBuilder, NotificationBuilderApi16.build)); env->CallObjectMethod (notificationBuilder, NotificationBuilderApi21.setPublicVersion, publicVersion.get()); } + + return notificationBuilder; } static LocalRef juceNotificationToBundle (const Notification& n) @@ -753,8 +772,11 @@ struct PushNotifications::Pimpl return bundle; } - static void setupOptionalFields (const Notification& n, LocalRef& notificationBuilder) + static LocalRef setupOptionalFields (const Notification n, LocalRef& notificationBuilder) { + if (notificationBuilder == nullptr) + return notificationBuilder; + auto* env = getEnv(); if (n.subtitle.isNotEmpty()) @@ -871,12 +893,15 @@ struct PushNotifications::Pimpl env->CallObjectMethod (notificationBuilder, NotificationBuilderApi26.setTimeoutAfter, (jlong) n.timeoutAfterMs); } - setupNotificationDeletedCallback (n, notificationBuilder); + return setupNotificationDeletedCallback (n, notificationBuilder); } - static void setupNotificationDeletedCallback (const Notification& n, - LocalRef& notificationBuilder) + static LocalRef setupNotificationDeletedCallback (const Notification& n, + LocalRef notificationBuilder) { + if (notificationBuilder == nullptr) + return notificationBuilder; + auto* env = getEnv(); LocalRef context (getMainActivity()); @@ -898,16 +923,19 @@ struct PushNotifications::Pimpl 0)); env->CallObjectMethod (notificationBuilder, NotificationBuilderBase.setDeleteIntent, deletePendingIntent.get()); + + return notificationBuilder; } - static void setupActions (const Notification& n, LocalRef& notificationBuilder) + static LocalRef setupActions (const Notification& n, LocalRef notificationBuilder) { + if (notificationBuilder == nullptr || n.actions.isEmpty()) + return notificationBuilder; + auto* env = getEnv(); LocalRef context (getMainActivity()); - int actionIndex = 0; - - for (const auto& action : n.actions) + for (const auto [actionIndex, action] : enumerate (n.actions)) { auto activityClass = LocalRef (env->CallObjectMethod (context.get(), JavaObject.getClass)); auto notifyIntent = LocalRef (env->NewObject (AndroidIntent, AndroidIntent.constructorWithContextAndClass, context.get(), activityClass.get())); @@ -938,6 +966,14 @@ struct PushNotifications::Pimpl iconId = env->CallIntMethod (resources, AndroidResources.getIdentifier, javaString (n.icon).get(), javaString ("raw").get(), packageNameString.get()); + if (iconId == 0) + { + // If this is hit, the notification icon could not be located, so the notification + // cannot be displayed. + jassertfalse; + return {}; + } + auto actionBuilder = LocalRef (env->NewObject (NotificationActionBuilder, NotificationActionBuilder.constructor, iconId, @@ -982,9 +1018,9 @@ struct PushNotifications::Pimpl env->CallObjectMethod (notificationBuilder, NotificationBuilderApi20.addAction, env->CallObjectMethod (actionBuilder, NotificationActionBuilder.build)); - - ++actionIndex; } + + return notificationBuilder; } static LocalRef juceUrlToAndroidUri (const URL& url)