28
28
"""
29
29
30
30
import struct
31
+ import time
31
32
32
33
from . import Service
33
34
from ..uuid import VendorUUID
@@ -44,39 +45,63 @@ class UnknownApple1Service(Service):
44
45
"""Unknown service. Unimplemented."""
45
46
uuid = VendorUUID ("9fa480e0-4967-4542-9390-d343dc5d04ae" )
46
47
48
+ class _NotificationAttribute :
49
+ def __init__ (self , id , * , max_length = False ):
50
+ self ._id = id
51
+ self ._max_length = max_length
52
+
53
+ def __get__ (self , notification , cls ):
54
+ if self ._id in notification ._attribute_cache :
55
+ return notification ._attribute_cache [self ._id ]
56
+
57
+ if self ._max_length :
58
+ command = struct .pack ("<BIBH" , 0 , notification .id , self ._id , 255 )
59
+ else :
60
+ command = struct .pack ("<BIB" , 0 , notification .id , self ._id )
61
+ notification .control_point .write (command )
62
+ while notification .data_source .in_waiting == 0 :
63
+ pass
64
+
65
+ _ , _ = struct .unpack ("<BI" , notification .data_source .read (5 ))
66
+ attribute_id , attribute_length = struct .unpack ("<BH" , notification .data_source .read (3 ))
67
+ if attribute_id != self ._id :
68
+ raise RuntimeError ("Data for other attribute" )
69
+ value = notification .data_source .read (attribute_length )
70
+ value = value .decode ("utf-8" )
71
+ notification ._attribute_cache [self ._id ] = value
72
+ return value
73
+
47
74
class Notification :
75
+ app_id = _NotificationAttribute (0 )
76
+ title = _NotificationAttribute (1 , max_length = True )
77
+ subtitle = _NotificationAttribute (2 , max_length = True )
78
+ message = _NotificationAttribute (3 , max_length = True )
79
+ message_size = _NotificationAttribute (4 )
80
+ _raw_date = _NotificationAttribute (5 )
81
+ positive_action_label = _NotificationAttribute (6 )
82
+ negative_action_label = _NotificationAttribute (7 )
83
+
48
84
def __init__ (self , id , event_flags , category_id , category_count , * , control_point , data_source ):
49
85
self .id = id
50
- self .category_id = category_id
51
86
self .removed = False
52
87
53
- self .silent = (event_flags & (1 << 0 )) != 0
54
- self .important = (event_flags & (1 << 1 )) != 0
55
- self .preexisting = (event_flags & (1 << 2 )) != 0
56
- self .positive_action = (event_flags & (1 << 3 )) != 0
57
- self .negative_action = (event_flags & (1 << 4 )) != 0
88
+ self .update (event_flags , category_id , category_count )
58
89
59
- self .subtitle = None
60
- self .message = None
90
+ self ._attribute_cache = {}
61
91
62
92
self .control_point = control_point
63
93
self .data_source = data_source
64
94
65
95
def update (self , event_flags , category_id , category_count ):
66
- pass
96
+ self . category_id = category_id
67
97
68
- def _fetch_all ( self ):
69
- self .control_point . write ( struct . pack ( "<BIBBHBHBHBBBB" , 0 , self . id , 0 , 1 , 32 , 2 , 32 , 3 , 255 , 4 , 5 , 6 , 7 ))
70
- while self .data_source . in_waiting = = 0 :
71
- pass
72
- _ , _ = struct . unpack ( "<BI" , self . data_source . read ( 5 ))
98
+ self . silent = ( event_flags & ( 1 << 0 )) != 0
99
+ self .important = ( event_flags & ( 1 << 1 )) != 0
100
+ self .preexisting = ( event_flags & ( 1 << 2 )) ! = 0
101
+ self . positive_action = ( event_flags & ( 1 << 3 )) != 0
102
+ self . negative_action = ( event_flags & ( 1 << 4 )) != 0
73
103
74
- for attribute in ["app_id" , "title" , "subtitle" , "message" , "message_size" , "date" , "positive_action_label" , "negative_action_label" ]:
75
- attribute_id , attribute_length = struct .unpack ("<BH" , self .data_source .read (3 ))
76
- if attribute_length == 0 :
77
- continue
78
- value = self .data_source .read (attribute_length ).decode ("utf-8" )
79
- setattr (self , attribute , value )
104
+ self ._attribute_cache = {}
80
105
81
106
@property
82
107
def app (self ):
@@ -89,7 +114,6 @@ def app(self):
89
114
90
115
91
116
def __str__ (self ):
92
- self ._fetch_all ()
93
117
flags = []
94
118
category = None
95
119
if self .category_id == 0 :
@@ -127,7 +151,7 @@ def __str__(self):
127
151
flags .append ("positive_action" )
128
152
if self .negative_action :
129
153
flags .append ("negative_action" )
130
- return category + " " + " " .join (flags ) + " " + self .app_id + " " + self .title + " " + str (self .subtitle ) + " " + str (self .message ) + " " + self .date
154
+ return category + " " + " " .join (flags ) + " " + self .app_id + " " + str ( self .title ) + " " + str (self .subtitle ) + " " + str (self .message ) + " " # + self.date
131
155
132
156
class AppleNotificationService (Service ):
133
157
"""Notification service."""
@@ -141,23 +165,37 @@ def __init__(self, service=None):
141
165
super ().__init__ (service = service )
142
166
self ._active_notifications = {}
143
167
144
- def _update_notifications (self ):
168
+ def _update (self ):
145
169
while self .notification_source .in_waiting > 7 :
146
170
buffer = self .notification_source .read (8 )
147
171
event_id , event_flags , category_id , category_count , id = struct .unpack ("<BBBBI" , buffer )
148
172
if event_id == 0 :
149
173
self ._active_notifications [id ] = Notification (id , event_flags , category_id ,
150
174
category_count , control_point = self .control_point , data_source = self .data_source )
175
+ yield self ._active_notifications [id ]
151
176
elif event_id == 1 :
152
177
self ._active_notifications [id ].update (event_flags , category_id , category_count )
178
+ yield None
153
179
elif event_id == 2 :
154
180
self ._active_notifications [id ].removed = True
155
181
del self ._active_notifications [id ]
182
+ yield None
156
183
#print(event_id, event_flags, category_id, category_count)
157
184
158
- def __iter__ (self ):
159
- self ._update_notifications ()
160
- return iter (self ._active_notifications .values ())
185
+
186
+ def wait_for_new_notifications (self , timeout = None ):
187
+ start_time = time .monotonic ()
188
+ while timeout is None or timeout > time .monotonic () - start_time :
189
+ new_notification = next (self ._update ())
190
+ if new_notification :
191
+ yield new_notification
192
+ return
193
+
194
+ @property
195
+ def active_notifications (self ):
196
+ for _ in self ._update ():
197
+ pass
198
+ return self ._active_notifications
161
199
162
200
class AppleMediaService (Service ):
163
201
"""View and control currently playing media. Unimplemented."""
0 commit comments