9 import util.qt_compat as qt_compat
10 QtCore = qt_compat.QtCore
14 _FREMANTLE_ALARM = "Fremantle"
15 _DIABLO_ALARM = "Diablo"
21 ALARM_TYPE = _FREMANTLE_ALARM
22 except (ImportError, OSError):
24 import osso.alarmd as alarmd
25 ALARM_TYPE = _DIABLO_ALARM
26 except (ImportError, OSError):
27 ALARM_TYPE = _NO_ALARM
30 _moduleLogger = logging.getLogger(__name__)
33 def _get_start_time(recurrence):
34 now = datetime.datetime.now()
35 startTimeMinute = now.minute + max(recurrence, 5) # being safe
36 startTimeHour = now.hour + int(startTimeMinute / 60)
37 startTimeMinute = startTimeMinute % 59
38 now.replace(minute=startTimeMinute)
39 timestamp = int(time.mktime(now.timetuple()))
43 def _create_recurrence_mask(recurrence, base):
45 >>> bin(_create_recurrence_mask(60, 60))
47 >>> bin(_create_recurrence_mask(30, 60))
48 '0b1000000000000000000000000000001'
49 >>> bin(_create_recurrence_mask(2, 60))
50 '0b10101010101010101010101010101010101010101010101010101010101'
51 >>> bin(_create_recurrence_mask(1, 60))
52 '0b111111111111111111111111111111111111111111111111111111111111'
55 for i in xrange(base / recurrence):
56 mask |= 1 << (recurrence * i)
60 def _unpack_minutes(recurrence):
62 >>> _unpack_minutes(0)
64 >>> _unpack_minutes(1)
66 >>> _unpack_minutes(59)
68 >>> _unpack_minutes(60)
70 >>> _unpack_minutes(129)
72 >>> _unpack_minutes(5 * 60 * 24 + 3 * 60 + 2)
74 >>> _unpack_minutes(12 * 60 * 24 + 3 * 60 + 2)
78 minutesInDay = 24 * minutesInAnHour
79 minutesInAWeek = minutesInDay * 7
81 days = recurrence / minutesInDay
83 recurrence -= days * minutesInDay
84 hours = recurrence / minutesInAnHour
85 recurrence -= hours * minutesInAnHour
86 mins = recurrence % minutesInAnHour
88 assert recurrence == 0, "Recurrence %d" % recurrence
89 return daysOfWeek, hours, mins
92 class _FremantleAlarmHandler(object):
96 _TITLE = "Dialcentral Notifications"
97 _LAUNCHER = os.path.abspath(os.path.join(os.path.dirname(__file__), "alarm_notify.py"))
102 self._alarmCookie = self._INVALID_COOKIE
103 self._launcher = self._LAUNCHER
105 def load_settings(self, config, sectionName):
107 self._recurrence = config.getint(sectionName, "recurrence")
108 self._alarmCookie = config.getint(sectionName, "alarmCookie")
109 launcher = config.get(sectionName, "notifier")
111 self._launcher = launcher
112 except ConfigParser.NoOptionError:
114 except ConfigParser.NoSectionError:
117 def save_settings(self, config, sectionName):
119 config.set(sectionName, "recurrence", str(self._recurrence))
120 config.set(sectionName, "alarmCookie", str(self._alarmCookie))
121 launcher = self._launcher if self._launcher != self._LAUNCHER else ""
122 config.set(sectionName, "notifier", launcher)
123 except ConfigParser.NoOptionError:
125 except ConfigParser.NoSectionError:
128 def apply_settings(self, enabled, recurrence):
129 if recurrence != self._recurrence or enabled != self.isEnabled:
133 self._set_alarm(recurrence)
134 self._recurrence = int(recurrence)
137 def recurrence(self):
138 return self._recurrence
142 return self._alarmCookie != self._INVALID_COOKIE
144 def _set_alarm(self, recurrenceMins):
145 assert 1 <= recurrenceMins, "Notifications set to occur too frequently: %d" % recurrenceMins
146 alarmTime = _get_start_time(recurrenceMins)
148 event = alarm.Event()
149 event.appid = self._TITLE
150 event.alarm_time = alarmTime
151 event.recurrences_left = self._REPEAT_FOREVER
153 action = event.add_actions(1)[0]
154 action.flags |= alarm.ACTION_TYPE_EXEC | alarm.ACTION_WHEN_TRIGGERED
155 action.command = self._launcher
157 recurrence = event.add_recurrences(1)[0]
158 recurrence.mask_min |= _create_recurrence_mask(recurrenceMins, 60)
159 recurrence.mask_hour |= alarm.RECUR_HOUR_DONTCARE
160 recurrence.mask_mday |= alarm.RECUR_MDAY_DONTCARE
161 recurrence.mask_wday |= alarm.RECUR_WDAY_DONTCARE
162 recurrence.mask_mon |= alarm.RECUR_MON_DONTCARE
163 recurrence.special |= alarm.RECUR_SPECIAL_NONE
165 assert event.is_sane()
166 self._alarmCookie = alarm.add_event(event)
168 def _clear_alarm(self):
169 if self._alarmCookie == self._INVALID_COOKIE:
171 alarm.delete_event(self._alarmCookie)
172 self._alarmCookie = self._INVALID_COOKIE
175 class _DiabloAlarmHandler(object):
178 _TITLE = "Dialcentral Notifications"
179 _LAUNCHER = os.path.abspath(os.path.join(os.path.dirname(__file__), "alarm_notify.py"))
185 bus = dbus.SystemBus()
186 self._alarmdDBus = bus.get_object("com.nokia.alarmd", "/com/nokia/alarmd");
187 self._alarmCookie = self._INVALID_COOKIE
188 self._launcher = self._LAUNCHER
190 def load_settings(self, config, sectionName):
192 self._recurrence = config.getint(sectionName, "recurrence")
193 self._alarmCookie = config.getint(sectionName, "alarmCookie")
194 launcher = config.get(sectionName, "notifier")
196 self._launcher = launcher
197 except ConfigParser.NoOptionError:
199 except ConfigParser.NoSectionError:
202 def save_settings(self, config, sectionName):
203 config.set(sectionName, "recurrence", str(self._recurrence))
204 config.set(sectionName, "alarmCookie", str(self._alarmCookie))
205 launcher = self._launcher if self._launcher != self._LAUNCHER else ""
206 config.set(sectionName, "notifier", launcher)
208 def apply_settings(self, enabled, recurrence):
209 if recurrence != self._recurrence or enabled != self.isEnabled:
213 self._set_alarm(recurrence)
214 self._recurrence = int(recurrence)
217 def recurrence(self):
218 return self._recurrence
222 return self._alarmCookie != self._INVALID_COOKIE
224 def _set_alarm(self, recurrence):
225 assert 1 <= recurrence, "Notifications set to occur too frequently: %d" % recurrence
226 alarmTime = _get_start_time(recurrence)
228 #Setup the alarm arguments so that they can be passed to the D-Bus add_event method
230 alarmd.ALARM_EVENT_NO_DIALOG |
231 alarmd.ALARM_EVENT_NO_SNOOZE |
232 alarmd.ALARM_EVENT_CONNECTED
235 action.extend(['flags', _DEFAULT_FLAGS])
236 action.extend(['title', self._TITLE])
237 action.extend(['path', self._launcher])
241 [alarmTime, int(27)],
242 signature=dbus.Signature('v')
244 ]) #int(27) used in place of alarm_index
247 event.extend([dbus.ObjectPath('/AlarmdEventRecurring'), dbus.UInt32(4)])
248 event.extend(['action', dbus.ObjectPath('/AlarmdActionExec')]) #use AlarmdActionExec instead of AlarmdActionDbus
249 event.append(dbus.UInt32(len(action) / 2))
251 event.extend(['time', dbus.Int64(alarmTime)])
252 event.extend(['recurr_interval', dbus.UInt32(recurrence)])
253 event.extend(['recurr_count', dbus.Int32(self._REPEAT_FOREVER)])
255 self._alarmCookie = self._alarmdDBus.add_event(*event);
257 def _clear_alarm(self):
258 if self._alarmCookie == self._INVALID_COOKIE:
260 deleteResult = self._alarmdDBus.del_event(dbus.Int32(self._alarmCookie))
261 self._alarmCookie = self._INVALID_COOKIE
262 assert deleteResult != -1, "Deleting of alarm event failed"
265 class _ApplicationAlarmHandler(object):
268 _MIN_TO_MS_FACTORY = 1000 * 60
271 self._timer = QtCore.QTimer()
272 self._timer.setSingleShot(False)
273 self._timer.setInterval(5 * self._MIN_TO_MS_FACTORY)
275 def load_settings(self, config, sectionName):
277 self._timer.setInterval(config.getint(sectionName, "recurrence") * self._MIN_TO_MS_FACTORY)
278 except ConfigParser.NoOptionError:
280 except ConfigParser.NoSectionError:
284 def save_settings(self, config, sectionName):
285 config.set(sectionName, "recurrence", str(self.recurrence))
287 def apply_settings(self, enabled, recurrence):
288 self._timer.setInterval(recurrence * self._MIN_TO_MS_FACTORY)
295 def notifySignal(self):
296 return self._timer.timeout
299 def recurrence(self):
300 return int(self._timer.interval() / self._MIN_TO_MS_FACTORY)
304 return self._timer.isActive()
307 class _NoneAlarmHandler(object):
310 self._enabled = False
313 def load_settings(self, config, sectionName):
315 self._recurrence = config.getint(sectionName, "recurrence")
317 except ConfigParser.NoOptionError:
319 except ConfigParser.NoSectionError:
322 def save_settings(self, config, sectionName):
323 config.set(sectionName, "recurrence", str(self.recurrence))
325 def apply_settings(self, enabled, recurrence):
326 self._enabled = enabled
329 def recurrence(self):
330 return self._recurrence
337 _BACKGROUND_ALARM_FACTORY = {
338 _FREMANTLE_ALARM: _FremantleAlarmHandler,
339 _DIABLO_ALARM: _DiabloAlarmHandler,
344 class AlarmHandler(object):
346 ALARM_NONE = "No Alert"
347 ALARM_BACKGROUND = "Background Alert"
348 ALARM_APPLICATION = "Application Alert"
349 ALARM_TYPES = [ALARM_NONE, ALARM_BACKGROUND, ALARM_APPLICATION]
352 ALARM_NONE: _NoneAlarmHandler,
353 ALARM_BACKGROUND: _BACKGROUND_ALARM_FACTORY,
354 ALARM_APPLICATION: _ApplicationAlarmHandler,
358 self._alarms = {self.ALARM_NONE: _NoneAlarmHandler()}
359 self._currentAlarmType = self.ALARM_NONE
361 def load_settings(self, config, sectionName):
363 self._currentAlarmType = config.get(sectionName, "alarm")
364 except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
365 _moduleLogger.exception("Falling back to old style")
366 self._currentAlarmType = self.ALARM_BACKGROUND
367 if self._currentAlarmType not in self.ALARM_TYPES:
368 self._currentAlarmType = self.ALARM_NONE
370 self._init_alarm(self._currentAlarmType)
371 if self._currentAlarmType in self._alarms:
372 self._alarms[self._currentAlarmType].load_settings(config, sectionName)
373 if not self._alarms[self._currentAlarmType].isEnabled:
374 _moduleLogger.info("Config file lied, not actually enabled")
375 self._currentAlarmType = self.ALARM_NONE
377 _moduleLogger.info("Background alerts not supported")
378 self._currentAlarmType = self.ALARM_NONE
380 def save_settings(self, config, sectionName):
381 config.set(sectionName, "alarm", self._currentAlarmType)
382 self._alarms[self._currentAlarmType].save_settings(config, sectionName)
384 def apply_settings(self, t, recurrence):
386 newHandler = self._alarms[t]
387 oldHandler = self._alarms[self._currentAlarmType]
388 if newHandler != oldHandler:
389 oldHandler.apply_settings(False, 0)
390 newHandler.apply_settings(True, recurrence)
391 self._currentAlarmType = t
395 return self._currentAlarmType
398 def backgroundNotificationsSupported(self):
399 return self.ALARM_FACTORY[self.ALARM_BACKGROUND] is not None
402 def applicationNotifySignal(self):
403 self._init_alarm(self.ALARM_APPLICATION)
404 return self._alarms[self.ALARM_APPLICATION].notifySignal
407 def recurrence(self):
408 return self._alarms[self._currentAlarmType].recurrence
412 return self._currentAlarmType != self.ALARM_NONE
414 def _init_alarm(self, t):
415 if t not in self._alarms and self.ALARM_FACTORY[t] is not None:
416 self._alarms[t] = self.ALARM_FACTORY[t]()
420 logFormat = '(%(relativeCreated)5d) %(levelname)-5s %(threadName)s.%(name)s.%(funcName)s: %(message)s'
421 logging.basicConfig(level=logging.DEBUG, format=logFormat)
428 parser = optparse.OptionParser()
429 parser.add_option("-x", "--display", action="store_true", dest="display", help="Display data")
430 parser.add_option("-e", "--enable", action="store_true", dest="enabled", help="Whether the alarm should be enabled or not", default=False)
431 parser.add_option("-d", "--disable", action="store_false", dest="enabled", help="Whether the alarm should be enabled or not", default=False)
432 parser.add_option("-r", "--recurrence", action="store", type="int", dest="recurrence", help="How often the alarm occurs", default=5)
433 (commandOptions, commandArgs) = parser.parse_args()
435 alarmHandler = AlarmHandler()
436 config = ConfigParser.SafeConfigParser()
437 config.read(constants._user_settings_)
438 alarmHandler.load_settings(config, "alarm")
440 if commandOptions.display:
441 print "Alarm (%s) is %s for every %d minutes" % (
442 alarmHandler._alarmCookie,
443 "enabled" if alarmHandler.isEnabled else "disabled",
444 alarmHandler.recurrence,
447 isEnabled = commandOptions.enabled
448 recurrence = commandOptions.recurrence
449 alarmHandler.apply_settings(isEnabled, recurrence)
451 alarmHandler.save_settings(config, "alarm")
452 configFile = open(constants._user_settings_, "wb")
454 config.write(configFile)
459 if __name__ == "__main__":