@@ -46,8 +46,8 @@ class UnknownApple1Service(Service):
46
46
uuid = VendorUUID ("9fa480e0-4967-4542-9390-d343dc5d04ae" )
47
47
48
48
class _NotificationAttribute :
49
- def __init__ (self , id , * , max_length = False ):
50
- self ._id = id
49
+ def __init__ (self , attribute_id , * , max_length = False ):
50
+ self ._id = attribute_id
51
51
self ._max_length = max_length
52
52
53
53
def __get__ (self , notification , cls ):
@@ -72,18 +72,56 @@ def __get__(self, notification, cls):
72
72
return value
73
73
74
74
class Notification :
75
+ """One notification that appears in the iOS notification center."""
76
+ # pylint: disable=too-many-instance-attributes
77
+
75
78
app_id = _NotificationAttribute (0 )
79
+ """String id of the app that generated the notification. It is not the name of the app. For
80
+ example, Slack is "com.tinyspeck.chatlyio" and Twitter is "com.atebits.Tweetie2"."""
81
+
76
82
title = _NotificationAttribute (1 , max_length = True )
83
+ """Title of the notification. Varies per app."""
84
+
77
85
subtitle = _NotificationAttribute (2 , max_length = True )
86
+ """Subtitle of the notification. Varies per app."""
87
+
78
88
message = _NotificationAttribute (3 , max_length = True )
89
+ """Message body of the notification. Varies per app."""
90
+
79
91
message_size = _NotificationAttribute (4 )
92
+ """Total length of the message string."""
93
+
80
94
_raw_date = _NotificationAttribute (5 )
81
95
positive_action_label = _NotificationAttribute (6 )
96
+ """Human readable label of the positive action."""
97
+
82
98
negative_action_label = _NotificationAttribute (7 )
99
+ """Human readable label of the negative action."""
100
+
101
+ def __init__ (self , notification_id , event_flags , category_id , category_count , * , control_point ,
102
+ data_source ):
103
+ self .id = notification_id # pylint: disable=invalid-name
104
+ """Integer id of the notification."""
83
105
84
- def __init__ (self , id , event_flags , category_id , category_count , * , control_point , data_source ):
85
- self .id = id
86
106
self .removed = False
107
+ """True when the notification has been cleared on the iOS device."""
108
+
109
+
110
+ self .silent = False
111
+ self .important = False
112
+ self .preexisting = False
113
+ """True if the notification existed before we connected to the iOS device."""
114
+
115
+ self .positive_action = False
116
+ """True if the notification has a positive action to respond with. For example, this could
117
+ be answering a phone call."""
118
+
119
+ self .negative_action = False
120
+ """True if the notification has a negative action to respond with. For example, this could
121
+ be declining a phone call."""
122
+
123
+ self .category_count = 0
124
+ """Number of other notifications with the same category."""
87
125
88
126
self .update (event_flags , category_id , category_count )
89
127
@@ -93,8 +131,11 @@ def __init__(self, id, event_flags, category_id, category_count, *, control_poin
93
131
self .data_source = data_source
94
132
95
133
def update (self , event_flags , category_id , category_count ):
134
+ """Update the notification and clear the attribute cache."""
96
135
self .category_id = category_id
97
136
137
+ self .category_count = category_count
138
+
98
139
self .silent = (event_flags & (1 << 0 )) != 0
99
140
self .important = (event_flags & (1 << 1 )) != 0
100
141
self .preexisting = (event_flags & (1 << 2 )) != 0
@@ -103,17 +144,8 @@ def update(self, event_flags, category_id, category_count):
103
144
104
145
self ._attribute_cache = {}
105
146
106
- @property
107
- def app (self ):
108
- self .control_point .write (struct .pack ("<BIB" , 0 , self .id , 0 ))
109
- while self .data_source .in_waiting == 0 :
110
- pass
111
- print (self .data_source .in_waiting )
112
- print (self .data_source .read ())
113
- return ""
114
-
115
-
116
147
def __str__ (self ):
148
+ # pylint: disable=too-many-branches
117
149
flags = []
118
150
category = None
119
151
if self .category_id == 0 :
@@ -151,48 +183,62 @@ def __str__(self):
151
183
flags .append ("positive_action" )
152
184
if self .negative_action :
153
185
flags .append ("negative_action" )
154
- return category + " " + " " .join (flags ) + " " + self .app_id + " " + str (self .title ) + " " + str (self .subtitle ) + " " + str (self .message ) + " " # + self.date
186
+ return (category + " " +
187
+ " " .join (flags ) + " " +
188
+ self .app_id + " " +
189
+ str (self .title ) + " " +
190
+ str (self .subtitle ) + " " +
191
+ str (self .message ))
155
192
156
193
class AppleNotificationService (Service ):
157
194
"""Notification service."""
158
195
uuid = VendorUUID ("7905F431-B5CE-4E99-A40F-4B1E122D00D0" )
159
196
160
197
control_point = StreamIn (uuid = VendorUUID ("69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9" ))
161
- data_source = StreamOut (uuid = VendorUUID ("22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB" ), buffer_size = 1024 )
162
- notification_source = StreamOut (uuid = VendorUUID ("9FBF120D-6301-42D9-8C58-25E699A21DBD" ), buffer_size = 8 * 100 )
198
+ data_source = StreamOut (uuid = VendorUUID ("22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB" ),
199
+ buffer_size = 1024 )
200
+ notification_source = StreamOut (uuid = VendorUUID ("9FBF120D-6301-42D9-8C58-25E699A21DBD" ),
201
+ buffer_size = 8 * 100 )
163
202
164
203
def __init__ (self , service = None ):
165
204
super ().__init__ (service = service )
166
205
self ._active_notifications = {}
167
206
168
207
def _update (self ):
169
- while self .notification_source .in_waiting > 7 :
170
- buffer = self .notification_source .read (8 )
171
- event_id , event_flags , category_id , category_count , id = struct .unpack ("<BBBBI" , buffer )
208
+ # Pylint is incorrectly inferring the type of self.notification_source so disable no-member.
209
+ while self .notification_source .in_waiting > 7 : # pylint: disable=no-member
210
+ buffer = self .notification_source .read (8 ) # pylint: disable=no-member
211
+ event_id , event_flags , category_id , category_count , nid = struct .unpack ("<BBBBI" ,
212
+ buffer )
172
213
if event_id == 0 :
173
- self ._active_notifications [id ] = Notification (id , event_flags , category_id ,
174
- category_count , control_point = self .control_point , data_source = self .data_source )
175
- yield self ._active_notifications [id ]
214
+ self ._active_notifications [nid ] = Notification (nid , event_flags , category_id ,
215
+ category_count ,
216
+ control_point = self .control_point ,
217
+ data_source = self .data_source )
218
+ yield self ._active_notifications [nid ]
176
219
elif event_id == 1 :
177
- self ._active_notifications [id ].update (event_flags , category_id , category_count )
220
+ self ._active_notifications [nid ].update (event_flags , category_id , category_count )
178
221
yield None
179
222
elif event_id == 2 :
180
- self ._active_notifications [id ].removed = True
181
- del self ._active_notifications [id ]
223
+ self ._active_notifications [nid ].removed = True
224
+ del self ._active_notifications [nid ]
182
225
yield None
183
- #print(event_id, event_flags, category_id, category_count)
184
-
185
226
186
227
def wait_for_new_notifications (self , timeout = None ):
228
+ """Waits for new notifications and yields them. Returns on timeout, update, disconnect or
229
+ clear."""
187
230
start_time = time .monotonic ()
188
231
while timeout is None or timeout > time .monotonic () - start_time :
189
- new_notification = next (self ._update ())
232
+ try :
233
+ new_notification = next (self ._update ())
234
+ except StopIteration :
235
+ return
190
236
if new_notification :
191
237
yield new_notification
192
- return
193
238
194
239
@property
195
240
def active_notifications (self ):
241
+ """A dictionary of active notifications keyed by id."""
196
242
for _ in self ._update ():
197
243
pass
198
244
return self ._active_notifications
0 commit comments