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:
parent
6d10eb536f
commit
269ebbb525
11 changed files with 308 additions and 149 deletions
|
|
@ -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