1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Accessibility: Add AccessibilityHandler::postSystemNotification() function for posting an OS-specific accessible notification

This commit is contained in:
reuk 2024-11-21 21:26:55 +00:00
parent 6d10eb536f
commit 269ebbb525
No known key found for this signature in database
11 changed files with 308 additions and 149 deletions

View file

@ -35,8 +35,6 @@
namespace juce namespace juce
{ {
AccessibilityHandler* AccessibilityHandler::currentlyFocusedHandler = nullptr;
class NativeChildHandler class NativeChildHandler
{ {
public: public:
@ -403,10 +401,24 @@ void AccessibilityHandler::setNativeChildForComponent (Component& component, voi
NativeChildHandler::getInstance().setNativeChild (component, nativeChild); NativeChildHandler::getInstance().setNativeChild (component, nativeChild);
} }
#if JUCE_MODULE_AVAILABLE_juce_gui_extra
void privatePostSystemNotification (const String&, const String&);
#endif
void AccessibilityHandler::postSystemNotification ([[maybe_unused]] const String& notificationTitle,
[[maybe_unused]] const String& notificationBody)
{
#if JUCE_MODULE_AVAILABLE_juce_gui_extra
if (areAnyAccessibilityClientsActive())
privatePostSystemNotification (notificationTitle, notificationBody);
#endif
}
#if ! JUCE_NATIVE_ACCESSIBILITY_INCLUDED #if ! JUCE_NATIVE_ACCESSIBILITY_INCLUDED
void AccessibilityHandler::notifyAccessibilityEvent (AccessibilityEvent) const {} void AccessibilityHandler::notifyAccessibilityEvent (AccessibilityEvent) const {}
void AccessibilityHandler::postAnnouncement (const String&, AnnouncementPriority) {} void AccessibilityHandler::postAnnouncement (const String&, AnnouncementPriority) {}
AccessibilityNativeHandle* AccessibilityHandler::getNativeImplementation() const { return nullptr; } AccessibilityNativeHandle* AccessibilityHandler::getNativeImplementation() const { return nullptr; }
bool AccessibilityHandler::areAnyAccessibilityClientsActive() { return false; }
#endif #endif
} // namespace juce } // namespace juce

View file

@ -295,6 +295,30 @@ public:
*/ */
static void postAnnouncement (const String& announcementString, AnnouncementPriority priority); static void postAnnouncement (const String& announcementString, AnnouncementPriority priority);
/** Posts a local system notification.
In order for this to do anything, the following conditions must be met.
- At build time:
- The juce_gui_extra module must be included in the project.
- Push notifications must be enabled by setting the preprocessor definition
JUCE_PUSH_NOTIFICATIONS=1
- At run time:
- An accessibility client (narrator, voiceover etc.) must be active.
Additionally, on Android, an icon is required for notifications.
This must be specified by adding the path to the icon file called
"accessibilitynotificationicon" in the "Extra Android Raw Resources" setting
in the Projucer.
This will use the push notification client on macOS, iOS and Android.
On Windows this will create a system tray icon to post the notification.
@param notificationTitle the title of the notification
@param notificationBody the main body text of the notification
*/
static void postSystemNotification (const String& notificationTitle,
const String& notificationBody);
//============================================================================== //==============================================================================
/** @internal */ /** @internal */
AccessibilityNativeHandle* getNativeImplementation() const; AccessibilityNativeHandle* getNativeImplementation() const;
@ -329,8 +353,9 @@ private:
void grabFocusInternal (bool); void grabFocusInternal (bool);
void giveAwayFocusInternal() const; void giveAwayFocusInternal() const;
void takeFocus(); void takeFocus();
static bool areAnyAccessibilityClientsActive();
static AccessibilityHandler* currentlyFocusedHandler; static inline AccessibilityHandler* currentlyFocusedHandler = nullptr;
//============================================================================== //==============================================================================
Component& component; Component& component;

View file

@ -1055,4 +1055,9 @@ void AccessibilityHandler::postAnnouncement (const String& announcementString,
javaString (announcementString).get()); javaString (announcementString).get());
} }
bool AccessibilityHandler::areAnyAccessibilityClientsActive()
{
return AccessibilityNativeHandle::areAnyAccessibilityClientsActive();
}
} // namespace juce } // namespace juce

View file

@ -666,4 +666,9 @@ void AccessibilityHandler::postAnnouncement (const String& announcementString, A
sendAccessibilityEvent (UIAccessibilityAnnouncementNotification, juceStringToNS (announcementString)); sendAccessibilityEvent (UIAccessibilityAnnouncementNotification, juceStringToNS (announcementString));
} }
bool AccessibilityHandler::areAnyAccessibilityClientsActive()
{
return juce::areAnyAccessibilityClientsActive();
}
} // namespace juce } // namespace juce

View file

@ -939,4 +939,9 @@ void AccessibilityHandler::postAnnouncement (const String& announcementString, A
NSAccessibilityPriorityKey: @(nsPriority) }); NSAccessibilityPriorityKey: @(nsPriority) });
} }
bool AccessibilityHandler::areAnyAccessibilityClientsActive()
{
return juce::areAnyAccessibilityClientsActive();
}
} // namespace juce } // namespace juce

View file

@ -39,26 +39,83 @@ namespace juce
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token") JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
static bool isStartingUpOrShuttingDown() //==============================================================================
struct WindowsAccessibility
{ {
if (auto* app = JUCEApplicationBase::getInstance()) WindowsAccessibility() = delete;
if (app->isInitialising())
static long getUiaRootObjectId()
{
return static_cast<long> (UiaRootObjectId);
}
static bool handleWmGetObject (AccessibilityHandler* handler, WPARAM wParam, LPARAM lParam, LRESULT* res)
{
if (isStartingUpOrShuttingDown() || (handler == nullptr || ! isHandlerValid (*handler)))
return false;
if (auto* uiaWrapper = WindowsUIAWrapper::getInstance())
{
ComSmartPtr<IRawElementProviderSimple> provider;
handler->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
if (! uiaWrapper->isProviderDisconnecting (provider))
*res = uiaWrapper->returnRawElementProvider ((HWND) handler->getComponent().getWindowHandle(), wParam, lParam, provider);
return true; return true;
}
if (auto* mm = MessageManager::getInstanceWithoutCreating()) return false;
if (mm->hasStopMessageBeenSent()) }
return true;
return false; static void revokeUIAMapEntriesForWindow (HWND hwnd)
} {
if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
uiaWrapper->returnRawElementProvider (hwnd, 0, 0, nullptr);
}
static bool isHandlerValid (const AccessibilityHandler& handler) static bool isStartingUpOrShuttingDown()
{ {
if (auto* provider = handler.getNativeImplementation()) if (auto* app = JUCEApplicationBase::getInstance())
return provider->isElementValid(); if (app->isInitialising())
return true;
return false; if (auto* mm = MessageManager::getInstanceWithoutCreating())
} if (mm->hasStopMessageBeenSent())
return true;
return false;
}
static bool isHandlerValid (const AccessibilityHandler& handler)
{
if (auto* provider = handler.getNativeImplementation())
return provider->isElementValid();
return false;
}
static bool areAnyAccessibilityClientsActive()
{
const auto areClientsListening = []
{
if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
return uiaWrapper->clientsAreListening() != 0;
return false;
};
const auto isScreenReaderRunning = []
{
BOOL isRunning = FALSE;
SystemParametersInfo (SPI_GETSCREENREADER, 0, (PVOID) &isRunning, 0);
return isRunning != 0;
};
return areClientsListening() || isScreenReaderRunning();
}
};
//============================================================================== //==============================================================================
class AccessibilityHandler::AccessibilityNativeImpl class AccessibilityHandler::AccessibilityNativeImpl
@ -103,31 +160,12 @@ AccessibilityNativeHandle* AccessibilityHandler::getNativeImplementation() const
return nativeImpl->accessibilityElement; return nativeImpl->accessibilityElement;
} }
static bool areAnyAccessibilityClientsActive()
{
const auto areClientsListening = []
{
if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
return uiaWrapper->clientsAreListening() != 0;
return false;
};
const auto isScreenReaderRunning = []
{
BOOL isRunning = FALSE;
SystemParametersInfo (SPI_GETSCREENREADER, 0, (PVOID) &isRunning, 0);
return isRunning != 0;
};
return areClientsListening() || isScreenReaderRunning();
}
template <typename Callback> template <typename Callback>
void getProviderWithCheckedWrapper (const AccessibilityHandler& handler, Callback&& callback) void getProviderWithCheckedWrapper (const AccessibilityHandler& handler, Callback&& callback)
{ {
if (! areAnyAccessibilityClientsActive() || isStartingUpOrShuttingDown() || ! isHandlerValid (handler)) if (! WindowsAccessibility::areAnyAccessibilityClientsActive()
|| WindowsAccessibility::isStartingUpOrShuttingDown()
|| ! WindowsAccessibility::isHandlerValid (handler))
return; return;
if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating()) if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
@ -292,41 +330,11 @@ void AccessibilityHandler::postAnnouncement (const String& announcementString, A
} }
} }
//============================================================================== bool AccessibilityHandler::areAnyAccessibilityClientsActive()
namespace WindowsAccessibility
{ {
static long getUiaRootObjectId() return WindowsAccessibility::areAnyAccessibilityClientsActive();
{
return static_cast<long> (UiaRootObjectId);
}
static bool handleWmGetObject (AccessibilityHandler* handler, WPARAM wParam, LPARAM lParam, LRESULT* res)
{
if (isStartingUpOrShuttingDown() || (handler == nullptr || ! isHandlerValid (*handler)))
return false;
if (auto* uiaWrapper = WindowsUIAWrapper::getInstance())
{
ComSmartPtr<IRawElementProviderSimple> provider;
handler->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
if (! uiaWrapper->isProviderDisconnecting (provider))
*res = uiaWrapper->returnRawElementProvider ((HWND) handler->getComponent().getWindowHandle(), wParam, lParam, provider);
return true;
}
return false;
}
static void revokeUIAMapEntriesForWindow (HWND hwnd)
{
if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
uiaWrapper->returnRawElementProvider (hwnd, 0, 0, nullptr);
}
} }
JUCE_END_IGNORE_WARNINGS_GCC_LIKE JUCE_END_IGNORE_WARNINGS_GCC_LIKE
} // namespace juce } // namespace juce

View file

@ -36,10 +36,50 @@ namespace juce
{ {
//============================================================================== //==============================================================================
#if ! JUCE_ANDROID && ! JUCE_IOS && ! JUCE_MAC #if ! JUCE_PUSH_NOTIFICATIONS_IMPL
struct PushNotifications::Impl
{
explicit Impl (PushNotifications& o) : owner (o) {}
void requestPermissionsWithSettings (const Settings&) const
{
owner.listeners.call ([] (Listener& l) { l.notificationSettingsReceived ({}); });
}
void requestSettingsUsed() const
{
owner.listeners.call ([] (Listener& l) { l.notificationSettingsReceived ({}); });
}
bool areNotificationsEnabled() const { return false; }
void getDeliveredNotifications() const {}
void removeAllDeliveredNotifications() const {}
String getDeviceToken() const { return {}; }
void setupChannels (const Array<ChannelGroup>&, const Array<Channel>&) const {}
void getPendingLocalNotifications() const {}
void removeAllPendingLocalNotifications() const {}
void subscribeToTopic (const String&) const {}
void unsubscribeFromTopic (const String&) const {}
void sendLocalNotification (const Notification&) const {}
void removeDeliveredNotification (const String&) const {}
void removePendingLocalNotification (const String&) const {}
void sendUpstreamMessage (const String&,
const String&,
const String&,
const String&,
int,
const StringPairArray&) const {}
private:
PushNotifications& owner;
};
bool PushNotifications::Notification::isValid() const noexcept { return true; } bool PushNotifications::Notification::isValid() const noexcept { return true; }
#endif #endif
//==============================================================================
PushNotifications::Notification::Notification (const Notification& other) PushNotifications::Notification::Notification (const Notification& other)
: identifier (other.identifier), : identifier (other.identifier),
title (other.title), title (other.title),
@ -82,9 +122,7 @@ PushNotifications::Notification::Notification (const Notification& other)
//============================================================================== //==============================================================================
PushNotifications::PushNotifications() PushNotifications::PushNotifications()
#if JUCE_PUSH_NOTIFICATIONS : pimpl (new Impl (*this))
: pimpl (new Pimpl (*this))
#endif
{ {
} }
@ -93,128 +131,90 @@ PushNotifications::~PushNotifications() { clearSingletonInstance(); }
void PushNotifications::addListener (Listener* l) { listeners.add (l); } void PushNotifications::addListener (Listener* l) { listeners.add (l); }
void PushNotifications::removeListener (Listener* l) { listeners.remove (l); } void PushNotifications::removeListener (Listener* l) { listeners.remove (l); }
void PushNotifications::requestPermissionsWithSettings ([[maybe_unused]] const PushNotifications::Settings& settings) void PushNotifications::requestPermissionsWithSettings (const Settings& settings)
{ {
#if JUCE_PUSH_NOTIFICATIONS && (JUCE_IOS || JUCE_MAC)
pimpl->requestPermissionsWithSettings (settings); pimpl->requestPermissionsWithSettings (settings);
#else
listeners.call ([] (Listener& l) { l.notificationSettingsReceived ({}); });
#endif
} }
void PushNotifications::requestSettingsUsed() void PushNotifications::requestSettingsUsed()
{ {
#if JUCE_PUSH_NOTIFICATIONS && (JUCE_IOS || JUCE_MAC)
pimpl->requestSettingsUsed(); pimpl->requestSettingsUsed();
#else
listeners.call ([] (Listener& l) { l.notificationSettingsReceived ({}); });
#endif
} }
bool PushNotifications::areNotificationsEnabled() const bool PushNotifications::areNotificationsEnabled() const
{ {
#if JUCE_PUSH_NOTIFICATIONS
return pimpl->areNotificationsEnabled(); return pimpl->areNotificationsEnabled();
#else
return false;
#endif
} }
void PushNotifications::getDeliveredNotifications() const void PushNotifications::getDeliveredNotifications() const
{ {
#if JUCE_PUSH_NOTIFICATIONS
pimpl->getDeliveredNotifications(); pimpl->getDeliveredNotifications();
#endif
} }
void PushNotifications::removeAllDeliveredNotifications() void PushNotifications::removeAllDeliveredNotifications()
{ {
#if JUCE_PUSH_NOTIFICATIONS
pimpl->removeAllDeliveredNotifications(); pimpl->removeAllDeliveredNotifications();
#endif
} }
String PushNotifications::getDeviceToken() const String PushNotifications::getDeviceToken() const
{ {
#if JUCE_PUSH_NOTIFICATIONS
return pimpl->getDeviceToken(); return pimpl->getDeviceToken();
#else
return {};
#endif
} }
void PushNotifications::setupChannels ([[maybe_unused]] const Array<ChannelGroup>& groups, [[maybe_unused]] const Array<Channel>& channels) void PushNotifications::setupChannels (const Array<ChannelGroup>& groups,
const Array<Channel>& channels)
{ {
#if JUCE_PUSH_NOTIFICATIONS
pimpl->setupChannels (groups, channels); pimpl->setupChannels (groups, channels);
#endif
} }
void PushNotifications::getPendingLocalNotifications() const void PushNotifications::getPendingLocalNotifications() const
{ {
#if JUCE_PUSH_NOTIFICATIONS
pimpl->getPendingLocalNotifications(); pimpl->getPendingLocalNotifications();
#endif
} }
void PushNotifications::removeAllPendingLocalNotifications() void PushNotifications::removeAllPendingLocalNotifications()
{ {
#if JUCE_PUSH_NOTIFICATIONS
pimpl->removeAllPendingLocalNotifications(); pimpl->removeAllPendingLocalNotifications();
#endif
} }
void PushNotifications::subscribeToTopic ([[maybe_unused]] const String& topic) void PushNotifications::subscribeToTopic (const String& topic)
{ {
#if JUCE_PUSH_NOTIFICATIONS
pimpl->subscribeToTopic (topic); pimpl->subscribeToTopic (topic);
#endif
} }
void PushNotifications::unsubscribeFromTopic ([[maybe_unused]] const String& topic) void PushNotifications::unsubscribeFromTopic (const String& topic)
{ {
#if JUCE_PUSH_NOTIFICATIONS
pimpl->unsubscribeFromTopic (topic); pimpl->unsubscribeFromTopic (topic);
#endif
} }
void PushNotifications::sendLocalNotification (const Notification& n)
void PushNotifications::sendLocalNotification ([[maybe_unused]] const Notification& n)
{ {
#if JUCE_PUSH_NOTIFICATIONS
pimpl->sendLocalNotification (n); pimpl->sendLocalNotification (n);
#endif
} }
void PushNotifications::removeDeliveredNotification ([[maybe_unused]] const String& identifier) void PushNotifications::removeDeliveredNotification (const String& identifier)
{ {
#if JUCE_PUSH_NOTIFICATIONS
pimpl->removeDeliveredNotification (identifier); pimpl->removeDeliveredNotification (identifier);
#endif
} }
void PushNotifications::removePendingLocalNotification ([[maybe_unused]] const String& identifier) void PushNotifications::removePendingLocalNotification (const String& identifier)
{ {
#if JUCE_PUSH_NOTIFICATIONS
pimpl->removePendingLocalNotification (identifier); pimpl->removePendingLocalNotification (identifier);
#endif
} }
void PushNotifications::sendUpstreamMessage ([[maybe_unused]] const String& serverSenderId, void PushNotifications::sendUpstreamMessage (const String& serverSenderId,
[[maybe_unused]] const String& collapseKey, const String& collapseKey,
[[maybe_unused]] const String& messageId, const String& messageId,
[[maybe_unused]] const String& messageType, const String& messageType,
[[maybe_unused]] int timeToLive, int timeToLive,
[[maybe_unused]] const StringPairArray& additionalData) const StringPairArray& additionalData)
{ {
#if JUCE_PUSH_NOTIFICATIONS
pimpl->sendUpstreamMessage (serverSenderId, pimpl->sendUpstreamMessage (serverSenderId,
collapseKey, collapseKey,
messageId, messageId,
messageType, messageType,
timeToLive, timeToLive,
additionalData); additionalData);
#endif
} }
//============================================================================== //==============================================================================
@ -234,4 +234,92 @@ void PushNotifications::Listener::upstreamMessageSent ([[maybe_unused]] const St
void PushNotifications::Listener::upstreamMessageSendingError ([[maybe_unused]] const String& messageId, void PushNotifications::Listener::upstreamMessageSendingError ([[maybe_unused]] const String& messageId,
[[maybe_unused]] const String& error) {} [[maybe_unused]] const String& error) {}
//==============================================================================
void privatePostSystemNotification (const String& notificationTitle, const String& notificationBody);
void privatePostSystemNotification ([[maybe_unused]] const String& notificationTitle,
[[maybe_unused]] const String& notificationBody)
{
#if JUCE_PUSH_NOTIFICATIONS
#if JUCE_ANDROID || JUCE_IOS || JUCE_MAC
auto* notificationsInstance = PushNotifications::getInstance();
if (notificationsInstance == nullptr)
return;
#if JUCE_ANDROID
notificationsInstance->requestPermissionsWithSettings ({});
static auto channels = std::invoke ([]() -> Array<PushNotifications::Channel>
{
PushNotifications::Channel chan;
chan.identifier = "1";
chan.name = "Notifications";
chan.description = "Accessibility notifications";
chan.groupId = "accessibility";
chan.ledColour = Colours::yellow;
chan.canShowBadge = true;
chan.enableLights = true;
chan.enableVibration = true;
chan.soundToPlay = URL ("default_os_sound");
chan.vibrationPattern = { 1000, 1000 };
return { chan };
});
notificationsInstance->setupChannels ({ PushNotifications::ChannelGroup { "accessibility", "accessibility" } },
channels);
#else
static auto settings = std::invoke ([]
{
PushNotifications::Settings s;
s.allowAlert = true;
s.allowBadge = true;
s.allowSound = true;
#if JUCE_IOS
PushNotifications::Settings::Category c;
c.identifier = "Accessibility";
s.categories = { c };
#endif
return s;
});
notificationsInstance->requestPermissionsWithSettings (settings);
#endif
const auto notification = std::invoke ([&notificationTitle, &notificationBody]
{
PushNotifications::Notification n;
n.identifier = String (Random::getSystemRandom().nextInt());
n.title = notificationTitle;
n.body = notificationBody;
#if JUCE_IOS
n.category = "Accessibility";
#elif JUCE_ANDROID
n.channelId = "1";
n.icon = "accessibilitynotificationicon";
#endif
return n;
});
if (notification.isValid())
notificationsInstance->sendLocalNotification (notification);
#else
SystemTrayIconComponent systemTrayIcon;
Image im (Image::ARGB, 128, 128, true);
systemTrayIcon.setIconImage (im, im);
systemTrayIcon.showInfoBubble (notificationTitle, notificationBody);
#endif
#endif
}
} // namespace juce } // namespace juce

View file

@ -403,8 +403,8 @@ public:
*/ */
struct Category struct Category
{ {
juce::String identifier; /**< unique identifier */ String identifier; /**< unique identifier */
juce::Array<Action> actions; /**< optional list of actions within this category */ Array<Action> actions; /**< optional list of actions within this category */
bool sendDismissAction = false; /**< whether dismiss action will be sent to the app */ bool sendDismissAction = false; /**< whether dismiss action will be sent to the app */
}; };
@ -703,12 +703,8 @@ private:
friend struct JuceFirebaseMessagingService; friend struct JuceFirebaseMessagingService;
#endif #endif
#if JUCE_PUSH_NOTIFICATIONS struct Impl;
struct Pimpl; std::unique_ptr<Impl> pimpl;
friend struct Pimpl;
std::unique_ptr<Pimpl> pimpl;
#endif
}; };
} // namespace juce } // namespace juce

View file

@ -35,6 +35,8 @@
namespace juce namespace juce
{ {
#define JUCE_PUSH_NOTIFICATIONS_IMPL 1
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
METHOD (constructor, "<init>", "(Ljava/lang/String;Ljava/lang/CharSequence;I)V") \ METHOD (constructor, "<init>", "(Ljava/lang/String;Ljava/lang/CharSequence;I)V") \
METHOD (enableLights, "enableLights", "(Z)V") \ METHOD (enableLights, "enableLights", "(Z)V") \
@ -274,9 +276,9 @@ bool PushNotifications::Notification::isValid() const noexcept
} }
//============================================================================== //==============================================================================
struct PushNotifications::Pimpl struct PushNotifications::Impl
{ {
explicit Pimpl (PushNotifications& p) explicit Impl (PushNotifications& p)
: owner (p) : owner (p)
{} {}
@ -306,7 +308,7 @@ struct PushNotifications::Pimpl
const auto notifyListeners = [] const auto notifyListeners = []
{ {
if (auto* instance = PushNotifications::getInstance()) if (auto* instance = PushNotifications::getInstance())
instance->listeners.call ([] (Listener& l) { l.notificationSettingsReceived ({}); }); instance->listeners.call ([] (Listener& l) { l.notificationSettingsReceived (makeDefaultSettings()); });
}; };
if (MessageManager::getInstance()->isThisTheMessageThread()) if (MessageManager::getInstance()->isThisTheMessageThread())
@ -318,7 +320,7 @@ struct PushNotifications::Pimpl
void requestSettingsUsed() void requestSettingsUsed()
{ {
owner.listeners.call ([] (Listener& l) { l.notificationSettingsReceived ({}); }); owner.listeners.call ([] (Listener& l) { l.notificationSettingsReceived (makeDefaultSettings()); });
} }
void sendLocalNotification (const Notification& n) void sendLocalNotification (const Notification& n)
@ -1573,6 +1575,15 @@ struct PushNotifications::Pimpl
&& env->CallBooleanMethod (extras, AndroidBundle.containsKey, javaString ("google.message_id").get()); && env->CallBooleanMethod (extras, AndroidBundle.containsKey, javaString ("google.message_id").get());
} }
static Settings makeDefaultSettings()
{
Settings settings;
settings.allowAlert = true;
settings.allowBadge = true;
settings.allowSound = true;
return settings;
}
PushNotifications& owner; PushNotifications& owner;
}; };
@ -1640,14 +1651,14 @@ bool juce_handleNotificationIntent (void* intent)
{ {
auto* instance = PushNotifications::getInstanceWithoutCreating(); auto* instance = PushNotifications::getInstanceWithoutCreating();
if (PushNotifications::Pimpl::isDeleteNotificationIntent ((jobject) intent)) if (PushNotifications::Impl::isDeleteNotificationIntent ((jobject) intent))
{ {
if (instance) if (instance)
instance->pimpl->notifyListenersAboutLocalNotificationDeleted (LocalRef<jobject> ((jobject) intent)); instance->pimpl->notifyListenersAboutLocalNotificationDeleted (LocalRef<jobject> ((jobject) intent));
return true; return true;
} }
else if (PushNotifications::Pimpl::isLocalNotificationIntent ((jobject) intent)) else if (PushNotifications::Impl::isLocalNotificationIntent ((jobject) intent))
{ {
if (instance) if (instance)
instance->pimpl->notifyListenersAboutLocalNotification (LocalRef<jobject> ((jobject) intent)); instance->pimpl->notifyListenersAboutLocalNotification (LocalRef<jobject> ((jobject) intent));
@ -1655,7 +1666,7 @@ bool juce_handleNotificationIntent (void* intent)
return true; return true;
} }
#if defined (JUCE_FIREBASE_MESSAGING_SERVICE_CLASSNAME) #if defined (JUCE_FIREBASE_MESSAGING_SERVICE_CLASSNAME)
else if (PushNotifications::Pimpl::isRemoteNotificationIntent ((jobject) intent)) else if (PushNotifications::Impl::isRemoteNotificationIntent ((jobject) intent))
{ {
if (instance) if (instance)
instance->pimpl->notifyListenersAboutRemoteNotificationFromSystemTray (LocalRef<jobject> ((jobject) intent)); instance->pimpl->notifyListenersAboutRemoteNotificationFromSystemTray (LocalRef<jobject> ((jobject) intent));

View file

@ -35,6 +35,8 @@
namespace juce namespace juce
{ {
#define JUCE_PUSH_NOTIFICATIONS_IMPL 1
struct PushNotificationsDelegateDetails struct PushNotificationsDelegateDetails
{ {
//============================================================================== //==============================================================================
@ -301,9 +303,9 @@ bool PushNotifications::Notification::isValid() const noexcept
} }
//============================================================================== //==============================================================================
struct PushNotifications::Pimpl struct PushNotifications::Impl
{ {
Pimpl (PushNotifications& p) explicit Impl (PushNotifications& p)
: owner (p) : owner (p)
{ {
Class::setThis (delegate.get(), this); Class::setThis (delegate.get(), this);
@ -555,7 +557,7 @@ private:
Class() Class()
: ObjCClass ("JucePushNotificationsDelegate_") : ObjCClass ("JucePushNotificationsDelegate_")
{ {
addIvar<Pimpl*> ("self"); addIvar<Impl*> ("self");
addMethod (@selector (application:didRegisterForRemoteNotificationsWithDeviceToken:), [] (id self, SEL, UIApplication*, NSData* data) addMethod (@selector (application:didRegisterForRemoteNotificationsWithDeviceToken:), [] (id self, SEL, UIApplication*, NSData* data)
{ {
@ -596,8 +598,8 @@ private:
} }
//============================================================================== //==============================================================================
static Pimpl& getThis (id self) { return *getIvar<Pimpl*> (self, "self"); } static Impl& getThis (id self) { return *getIvar<Impl*> (self, "self"); }
static void setThis (id self, Pimpl* d) { object_setInstanceVariable (self, "self", d); } static void setThis (id self, Impl* d) { object_setInstanceVariable (self, "self", d); }
}; };
//============================================================================== //==============================================================================

View file

@ -35,6 +35,8 @@
namespace juce namespace juce
{ {
#define JUCE_PUSH_NOTIFICATIONS_IMPL 1
JUCE_BEGIN_IGNORE_DEPRECATION_WARNINGS JUCE_BEGIN_IGNORE_DEPRECATION_WARNINGS
namespace PushNotificationsDelegateDetailsOsx namespace PushNotificationsDelegateDetailsOsx
@ -343,9 +345,9 @@ private:
bool PushNotifications::Notification::isValid() const noexcept { return true; } bool PushNotifications::Notification::isValid() const noexcept { return true; }
//============================================================================== //==============================================================================
struct PushNotifications::Pimpl : private PushNotificationsDelegate struct PushNotifications::Impl : private PushNotificationsDelegate
{ {
Pimpl (PushNotifications& p) explicit Impl (PushNotifications& p)
: owner (p) : owner (p)
{ {
} }