mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-09 23:34:20 +00:00
Accessibility: Add AccessibilityHandler::postSystemNotification() function for posting an OS-specific accessible notification
This commit is contained in:
parent
6d10eb536f
commit
269ebbb525
11 changed files with 308 additions and 149 deletions
|
|
@ -35,8 +35,6 @@
|
|||
namespace juce
|
||||
{
|
||||
|
||||
AccessibilityHandler* AccessibilityHandler::currentlyFocusedHandler = nullptr;
|
||||
|
||||
class NativeChildHandler
|
||||
{
|
||||
public:
|
||||
|
|
@ -403,10 +401,24 @@ void AccessibilityHandler::setNativeChildForComponent (Component& component, voi
|
|||
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
|
||||
void AccessibilityHandler::notifyAccessibilityEvent (AccessibilityEvent) const {}
|
||||
void AccessibilityHandler::postAnnouncement (const String&, AnnouncementPriority) {}
|
||||
AccessibilityNativeHandle* AccessibilityHandler::getNativeImplementation() const { return nullptr; }
|
||||
bool AccessibilityHandler::areAnyAccessibilityClientsActive() { return false; }
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -295,6 +295,30 @@ public:
|
|||
*/
|
||||
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 */
|
||||
AccessibilityNativeHandle* getNativeImplementation() const;
|
||||
|
|
@ -329,8 +353,9 @@ private:
|
|||
void grabFocusInternal (bool);
|
||||
void giveAwayFocusInternal() const;
|
||||
void takeFocus();
|
||||
static bool areAnyAccessibilityClientsActive();
|
||||
|
||||
static AccessibilityHandler* currentlyFocusedHandler;
|
||||
static inline AccessibilityHandler* currentlyFocusedHandler = nullptr;
|
||||
|
||||
//==============================================================================
|
||||
Component& component;
|
||||
|
|
|
|||
|
|
@ -1055,4 +1055,9 @@ void AccessibilityHandler::postAnnouncement (const String& announcementString,
|
|||
javaString (announcementString).get());
|
||||
}
|
||||
|
||||
bool AccessibilityHandler::areAnyAccessibilityClientsActive()
|
||||
{
|
||||
return AccessibilityNativeHandle::areAnyAccessibilityClientsActive();
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -666,4 +666,9 @@ void AccessibilityHandler::postAnnouncement (const String& announcementString, A
|
|||
sendAccessibilityEvent (UIAccessibilityAnnouncementNotification, juceStringToNS (announcementString));
|
||||
}
|
||||
|
||||
bool AccessibilityHandler::areAnyAccessibilityClientsActive()
|
||||
{
|
||||
return juce::areAnyAccessibilityClientsActive();
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -939,4 +939,9 @@ void AccessibilityHandler::postAnnouncement (const String& announcementString, A
|
|||
NSAccessibilityPriorityKey: @(nsPriority) });
|
||||
}
|
||||
|
||||
bool AccessibilityHandler::areAnyAccessibilityClientsActive()
|
||||
{
|
||||
return juce::areAnyAccessibilityClientsActive();
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -39,26 +39,83 @@ namespace juce
|
|||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
|
||||
|
||||
static bool isStartingUpOrShuttingDown()
|
||||
//==============================================================================
|
||||
struct WindowsAccessibility
|
||||
{
|
||||
if (auto* app = JUCEApplicationBase::getInstance())
|
||||
if (app->isInitialising())
|
||||
WindowsAccessibility() = delete;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (auto* mm = MessageManager::getInstanceWithoutCreating())
|
||||
if (mm->hasStopMessageBeenSent())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
static void revokeUIAMapEntriesForWindow (HWND hwnd)
|
||||
{
|
||||
if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
|
||||
uiaWrapper->returnRawElementProvider (hwnd, 0, 0, nullptr);
|
||||
}
|
||||
|
||||
static bool isHandlerValid (const AccessibilityHandler& handler)
|
||||
{
|
||||
if (auto* provider = handler.getNativeImplementation())
|
||||
return provider->isElementValid();
|
||||
static bool isStartingUpOrShuttingDown()
|
||||
{
|
||||
if (auto* app = JUCEApplicationBase::getInstance())
|
||||
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
|
||||
|
|
@ -103,31 +160,12 @@ AccessibilityNativeHandle* AccessibilityHandler::getNativeImplementation() const
|
|||
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>
|
||||
void getProviderWithCheckedWrapper (const AccessibilityHandler& handler, Callback&& callback)
|
||||
{
|
||||
if (! areAnyAccessibilityClientsActive() || isStartingUpOrShuttingDown() || ! isHandlerValid (handler))
|
||||
if (! WindowsAccessibility::areAnyAccessibilityClientsActive()
|
||||
|| WindowsAccessibility::isStartingUpOrShuttingDown()
|
||||
|| ! WindowsAccessibility::isHandlerValid (handler))
|
||||
return;
|
||||
|
||||
if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
|
||||
|
|
@ -292,41 +330,11 @@ void AccessibilityHandler::postAnnouncement (const String& announcementString, A
|
|||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
namespace WindowsAccessibility
|
||||
bool AccessibilityHandler::areAnyAccessibilityClientsActive()
|
||||
{
|
||||
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 false;
|
||||
}
|
||||
|
||||
static void revokeUIAMapEntriesForWindow (HWND hwnd)
|
||||
{
|
||||
if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
|
||||
uiaWrapper->returnRawElementProvider (hwnd, 0, 0, nullptr);
|
||||
}
|
||||
return WindowsAccessibility::areAnyAccessibilityClientsActive();
|
||||
}
|
||||
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
PushNotifications::Notification::Notification (const Notification& other)
|
||||
: identifier (other.identifier),
|
||||
title (other.title),
|
||||
|
|
@ -82,9 +122,7 @@ PushNotifications::Notification::Notification (const Notification& other)
|
|||
|
||||
//==============================================================================
|
||||
PushNotifications::PushNotifications()
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
: pimpl (new Pimpl (*this))
|
||||
#endif
|
||||
: pimpl (new Impl (*this))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -93,128 +131,90 @@ PushNotifications::~PushNotifications() { clearSingletonInstance(); }
|
|||
void PushNotifications::addListener (Listener* l) { listeners.add (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);
|
||||
#else
|
||||
listeners.call ([] (Listener& l) { l.notificationSettingsReceived ({}); });
|
||||
#endif
|
||||
}
|
||||
|
||||
void PushNotifications::requestSettingsUsed()
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS && (JUCE_IOS || JUCE_MAC)
|
||||
pimpl->requestSettingsUsed();
|
||||
#else
|
||||
listeners.call ([] (Listener& l) { l.notificationSettingsReceived ({}); });
|
||||
#endif
|
||||
}
|
||||
|
||||
bool PushNotifications::areNotificationsEnabled() const
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
return pimpl->areNotificationsEnabled();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void PushNotifications::getDeliveredNotifications() const
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
pimpl->getDeliveredNotifications();
|
||||
#endif
|
||||
}
|
||||
|
||||
void PushNotifications::removeAllDeliveredNotifications()
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
pimpl->removeAllDeliveredNotifications();
|
||||
#endif
|
||||
}
|
||||
|
||||
String PushNotifications::getDeviceToken() const
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PushNotifications::getPendingLocalNotifications() const
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
pimpl->getPendingLocalNotifications();
|
||||
#endif
|
||||
}
|
||||
|
||||
void PushNotifications::removeAllPendingLocalNotifications()
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
pimpl->removeAllPendingLocalNotifications();
|
||||
#endif
|
||||
}
|
||||
|
||||
void PushNotifications::subscribeToTopic ([[maybe_unused]] const String& topic)
|
||||
void PushNotifications::subscribeToTopic (const String& topic)
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PushNotifications::sendLocalNotification ([[maybe_unused]] const Notification& n)
|
||||
void PushNotifications::sendLocalNotification (const Notification& n)
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PushNotifications::removePendingLocalNotification ([[maybe_unused]] const String& identifier)
|
||||
void PushNotifications::removePendingLocalNotification (const String& identifier)
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
pimpl->removePendingLocalNotification (identifier);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PushNotifications::sendUpstreamMessage ([[maybe_unused]] const String& serverSenderId,
|
||||
[[maybe_unused]] const String& collapseKey,
|
||||
[[maybe_unused]] const String& messageId,
|
||||
[[maybe_unused]] const String& messageType,
|
||||
[[maybe_unused]] int timeToLive,
|
||||
[[maybe_unused]] const StringPairArray& additionalData)
|
||||
void PushNotifications::sendUpstreamMessage (const String& serverSenderId,
|
||||
const String& collapseKey,
|
||||
const String& messageId,
|
||||
const String& messageType,
|
||||
int timeToLive,
|
||||
const StringPairArray& additionalData)
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
pimpl->sendUpstreamMessage (serverSenderId,
|
||||
collapseKey,
|
||||
messageId,
|
||||
messageType,
|
||||
timeToLive,
|
||||
additionalData);
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -234,4 +234,92 @@ void PushNotifications::Listener::upstreamMessageSent ([[maybe_unused]] const St
|
|||
void PushNotifications::Listener::upstreamMessageSendingError ([[maybe_unused]] const String& messageId,
|
||||
[[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 ([¬ificationTitle, ¬ificationBody]
|
||||
{
|
||||
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
|
||||
|
|
|
|||
|
|
@ -403,8 +403,8 @@ public:
|
|||
*/
|
||||
struct Category
|
||||
{
|
||||
juce::String identifier; /**< unique identifier */
|
||||
juce::Array<Action> actions; /**< optional list of actions within this category */
|
||||
String identifier; /**< unique identifier */
|
||||
Array<Action> actions; /**< optional list of actions within this category */
|
||||
bool sendDismissAction = false; /**< whether dismiss action will be sent to the app */
|
||||
};
|
||||
|
||||
|
|
@ -703,12 +703,8 @@ private:
|
|||
friend struct JuceFirebaseMessagingService;
|
||||
#endif
|
||||
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
struct Pimpl;
|
||||
friend struct Pimpl;
|
||||
|
||||
std::unique_ptr<Pimpl> pimpl;
|
||||
#endif
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> pimpl;
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@
|
|||
namespace juce
|
||||
{
|
||||
|
||||
#define JUCE_PUSH_NOTIFICATIONS_IMPL 1
|
||||
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
METHOD (constructor, "<init>", "(Ljava/lang/String;Ljava/lang/CharSequence;I)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)
|
||||
{}
|
||||
|
||||
|
|
@ -306,7 +308,7 @@ struct PushNotifications::Pimpl
|
|||
const auto notifyListeners = []
|
||||
{
|
||||
if (auto* instance = PushNotifications::getInstance())
|
||||
instance->listeners.call ([] (Listener& l) { l.notificationSettingsReceived ({}); });
|
||||
instance->listeners.call ([] (Listener& l) { l.notificationSettingsReceived (makeDefaultSettings()); });
|
||||
};
|
||||
|
||||
if (MessageManager::getInstance()->isThisTheMessageThread())
|
||||
|
|
@ -318,7 +320,7 @@ struct PushNotifications::Pimpl
|
|||
|
||||
void requestSettingsUsed()
|
||||
{
|
||||
owner.listeners.call ([] (Listener& l) { l.notificationSettingsReceived ({}); });
|
||||
owner.listeners.call ([] (Listener& l) { l.notificationSettingsReceived (makeDefaultSettings()); });
|
||||
}
|
||||
|
||||
void sendLocalNotification (const Notification& n)
|
||||
|
|
@ -1573,6 +1575,15 @@ struct PushNotifications::Pimpl
|
|||
&& 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;
|
||||
};
|
||||
|
||||
|
|
@ -1640,14 +1651,14 @@ bool juce_handleNotificationIntent (void* intent)
|
|||
{
|
||||
auto* instance = PushNotifications::getInstanceWithoutCreating();
|
||||
|
||||
if (PushNotifications::Pimpl::isDeleteNotificationIntent ((jobject) intent))
|
||||
if (PushNotifications::Impl::isDeleteNotificationIntent ((jobject) intent))
|
||||
{
|
||||
if (instance)
|
||||
instance->pimpl->notifyListenersAboutLocalNotificationDeleted (LocalRef<jobject> ((jobject) intent));
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (PushNotifications::Pimpl::isLocalNotificationIntent ((jobject) intent))
|
||||
else if (PushNotifications::Impl::isLocalNotificationIntent ((jobject) intent))
|
||||
{
|
||||
if (instance)
|
||||
instance->pimpl->notifyListenersAboutLocalNotification (LocalRef<jobject> ((jobject) intent));
|
||||
|
|
@ -1655,7 +1666,7 @@ bool juce_handleNotificationIntent (void* intent)
|
|||
return true;
|
||||
}
|
||||
#if defined (JUCE_FIREBASE_MESSAGING_SERVICE_CLASSNAME)
|
||||
else if (PushNotifications::Pimpl::isRemoteNotificationIntent ((jobject) intent))
|
||||
else if (PushNotifications::Impl::isRemoteNotificationIntent ((jobject) intent))
|
||||
{
|
||||
if (instance)
|
||||
instance->pimpl->notifyListenersAboutRemoteNotificationFromSystemTray (LocalRef<jobject> ((jobject) intent));
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@
|
|||
namespace juce
|
||||
{
|
||||
|
||||
#define JUCE_PUSH_NOTIFICATIONS_IMPL 1
|
||||
|
||||
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)
|
||||
{
|
||||
Class::setThis (delegate.get(), this);
|
||||
|
|
@ -555,7 +557,7 @@ private:
|
|||
Class()
|
||||
: ObjCClass ("JucePushNotificationsDelegate_")
|
||||
{
|
||||
addIvar<Pimpl*> ("self");
|
||||
addIvar<Impl*> ("self");
|
||||
|
||||
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 void setThis (id self, Pimpl* d) { object_setInstanceVariable (self, "self", d); }
|
||||
static Impl& getThis (id self) { return *getIvar<Impl*> (self, "self"); }
|
||||
static void setThis (id self, Impl* d) { object_setInstanceVariable (self, "self", d); }
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@
|
|||
namespace juce
|
||||
{
|
||||
|
||||
#define JUCE_PUSH_NOTIFICATIONS_IMPL 1
|
||||
|
||||
JUCE_BEGIN_IGNORE_DEPRECATION_WARNINGS
|
||||
|
||||
namespace PushNotificationsDelegateDetailsOsx
|
||||
|
|
@ -343,9 +345,9 @@ private:
|
|||
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)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue