9 from PyQt4 import QtCore
13 _FREMANTLE_ALARM = "Fremantle"
14 _DIABLO_ALARM = "Diablo"
20 ALARM_TYPE = _FREMANTLE_ALARM
21 except (ImportError, OSError):
23 import osso.alarmd as alarmd
24 ALARM_TYPE = _DIABLO_ALARM
25 except (ImportError, OSError):
26 ALARM_TYPE = _NO_ALARM
29 _moduleLogger = logging.getLogger(__name__)
32 def _get_start_time(recurrence):
33 now = datetime.datetime.now()
34 startTimeMinute = now.minute + max(recurrence, 5) # being safe
35 startTimeHour = now.hour + int(startTimeMinute / 60)
36 startTimeMinute = startTimeMinute % 59
37 now.replace(minute=startTimeMinute)
38 timestamp = int(time.mktime(now.timetuple()))
42 def _create_recurrence_mask(recurrence, base):
44 >>> bin(_create_recurrence_mask(60, 60))
46 >>> bin(_create_recurrence_mask(30, 60))
47 '0b1000000000000000000000000000001'
48 >>> bin(_create_recurrence_mask(2, 60))
49 '0b10101010101010101010101010101010101010101010101010101010101'
50 >>> bin(_create_recurrence_mask(1, 60))
51 '0b111111111111111111111111111111111111111111111111111111111111'
54 for i in xrange(base / recurrence):
55 mask |= 1 << (recurrence * i)
59 def _unpack_minutes(recurrence):
61 >>> _unpack_minutes(0)
63 >>> _unpack_minutes(1)
65 >>> _unpack_minutes(59)
67 >>> _unpack_minutes(60)
69 >>> _unpack_minutes(129)
71 >>> _unpack_minutes(5 * 60 * 24 + 3 * 60 + 2)
73 >>> _unpack_minutes(12 * 60 * 24 + 3 * 60 + 2)
77 minutesInDay = 24 * minutesInAnHour
78 minutesInAWeek = minutesInDay * 7
80 days = recurrence / minutesInDay
82 recurrence -= days * minutesInDay
83 hours = recurrence / minutesInAnHour
84 recurrence -= hours * minutesInAnHour
85 mins = recurrence % minutesInAnHour
87 assert recurrence == 0, "Recurrence %d" % recurrence
88 return daysOfWeek, hours, mins
91 class _FremantleAlarmHandler(object):
95 _TITLE = "Dialcentral Notifications"
96 _LAUNCHER = os.path.abspath(os.path.join(os.path.dirname(__file__), "alarm_notify.py"))
101 self._alarmCookie = self._INVALID_COOKIE
102 self._launcher = self._LAUNCHER
104 def load_settings(self, config, sectionName):
106 self._recurrence = config.getint(sectionName, "recurrence")
107 self._alarmCookie = config.getint(sectionName, "alarmCookie")
108 launcher = config.get(sectionName, "notifier")
110 self._launcher = launcher
111 except ConfigParser.NoOptionError:
113 except ConfigParser.NoSectionError:
116 def save_settings(self, config, sectionName):
118 config.set(sectionName, "recurrence", str(self._recurrence))
119 config.set(sectionName, "alarmCookie", str(self._alarmCookie))
120 launcher = self._launcher if self._launcher != self._LAUNCHER else ""
121 config.set(sectionName, "notifier", launcher)
122 except ConfigParser.NoOptionError:
124 except ConfigParser.NoSectionError:
127 def apply_settings(self, enabled, recurrence):
128 if recurrence != self._recurrence or enabled != self.isEnabled:
132 self._set_alarm(recurrence)
133 self._recurrence = int(recurrence)
136 def recurrence(self):
137 return self._recurrence
141 return self._alarmCookie != self._INVALID_COOKIE
143 def _set_alarm(self, recurrenceMins):
144 assert 1 <= recurrenceMins, "Notifications set to occur too frequently: %d" % recurrenceMins
145 alarmTime = _get_start_time(recurrenceMins)
147 event = alarm.Event()
148 event.appid = self._TITLE
149 event.alarm_time = alarmTime
150 event.recurrences_left = self._REPEAT_FOREVER
152 action = event.add_actions(1)[0]
153 action.flags |= alarm.ACTION_TYPE_EXEC | alarm.ACTION_WHEN_TRIGGERED
154 action.command = self._launcher
156 recurrence = event.add_recurrences(1)[0]
157 recurrence.mask_min |= _create_recurrence_mask(recurrenceMins, 60)
158 recurrence.mask_hour |= alarm.RECUR_HOUR_DONTCARE
159 recurrence.mask_mday |= alarm.RECUR_MDAY_DONTCARE
160 recurrence.mask_wday |= alarm.RECUR_WDAY_DONTCARE
161 recurrence.mask_mon |= alarm.RECUR_MON_DONTCARE
162 recurrence.special |= alarm.RECUR_SPECIAL_NONE
164 assert event.is_sane()
165 self._alarmCookie = alarm.add_event(event)
167 def _clear_alarm(self):
168 if self._alarmCookie == self._INVALID_COOKIE:
170 alarm.delete_event(self._alarmCookie)
171 self._alarmCookie = self._INVALID_COOKIE
174 class _DiabloAlarmHandler(object):
177 _TITLE = "Dialcentral Notifications"
178 _LAUNCHER = os.path.abspath(os.path.join(os.path.dirname(__file__), "alarm_notify.py"))
184 bus = dbus.SystemBus()
185 self._alarmdDBus = bus.get_object("com.nokia.alarmd", "/com/nokia/alarmd");
186 self._alarmCookie = self._INVALID_COOKIE
187 self._launcher = self._LAUNCHER
189 def load_settings(self, config, sectionName):
191 self._recurrence = config.getint(sectionName, "recurrence")
192 self._alarmCookie = config.getint(sectionName, "alarmCookie")
193 launcher = config.get(sectionName, "notifier")
195 self._launcher = launcher
196 except ConfigParser.NoOptionError:
198 except ConfigParser.NoSectionError:
201 def save_settings(self, config, sectionName):
202 config.set(sectionName, "recurrence", str(self._recurrence))
203 config.set(sectionName, "alarmCookie", str(self._alarmCookie))
204 launcher = self._launcher if self._launcher != self._LAUNCHER else ""
205 config.set(sectionName, "notifier", launcher)
207 def apply_settings(self, enabled, recurrence):
208 if recurrence != self._recurrence or enabled != self.isEnabled:
212 self._set_alarm(recurrence)
213 self._recurrence = int(recurrence)
216 def recurrence(self):
217 return self._recurrence
221 return self._alarmCookie != self._INVALID_COOKIE
223 def _set_alarm(self, recurrence):
224 assert 1 <= recurrence, "Notifications set to occur too frequently: %d" % recurrence
225 alarmTime = _get_start_time(recurrence)
227 #Setup the alarm arguments so that they can be passed to the D-Bus add_event method
229 alarmd.ALARM_EVENT_NO_DIALOG |
230 alarmd.ALARM_EVENT_NO_SNOOZE |
231 alarmd.ALARM_EVENT_CONNECTED
234 action.extend(['flags', _DEFAULT_FLAGS])
235 action.extend(['title', self._TITLE])
236 action.extend(['path', self._launcher])
240 [alarmTime, int(27)],
241 signature=dbus.Signature('v')
243 ]) #int(27) used in place of alarm_index
246 event.extend([dbus.ObjectPath('/AlarmdEventRecurring'), dbus.UInt32(4)])
247 event.extend(['action', dbus.ObjectPath('/AlarmdActionExec')]) #use AlarmdActionExec instead of AlarmdActionDbus
248 event.append(dbus.UInt32(len(action) / 2))
250 event.extend(['time', dbus.Int64(alarmTime)])
251 event.extend(['recurr_interval', dbus.UInt32(recurrence)])
252 event.extend(['recurr_count', dbus.Int32(self._REPEAT_FOREVER)])
254 self._alarmCookie = self._alarmdDBus.add_event(*event);
256 def _clear_alarm(self):
257 if self._alarmCookie == self._INVALID_COOKIE:
259 deleteResult = self._alarmdDBus.del_event(dbus.Int32(self._alarmCookie))
260 self._alarmCookie = self._INVALID_COOKIE
261 assert deleteResult != -1, "Deleting of alarm event failed"
264 class _ApplicationAlarmHandler(object):
267 _MIN_TO_MS_FACTORY = 1000 * 60
270 self._timer = QtCore.QTimer()
271 self._timer.setSingleShot(False)
272 self._timer.setInterval(5 * self._MIN_TO_MS_FACTORY)
274 def load_settings(self, config, sectionName):
276 self._timer.setInterval(config.getint(sectionName, "recurrence") * self._MIN_TO_MS_FACTORY)
277 except ConfigParser.NoOptionError:
279 except ConfigParser.NoSectionError:
283 def save_settings(self, config, sectionName):
284 config.set(sectionName, "recurrence", str(self.recurrence))
286 def apply_settings(self, enabled, recurrence):
287 self._timer.setInterval(recurrence * self._MIN_TO_MS_FACTORY)
294 def notifySignal(self):
295 return self._timer.timeout
298 def recurrence(self):
299 return int(self._timer.interval() / self._MIN_TO_MS_FACTORY)
303 return self._timer.isActive()
306 class _NoneAlarmHandler(object):
309 self._enabled = False
312 def load_settings(self, config, sectionName):
314 self._recurrence = config.getint(sectionName, "recurrence")
315 except ConfigParser.NoOptionError:
317 except ConfigParser.NoSectionError:
320 def save_settings(self, config, sectionName):
321 config.set(sectionName, "recurrence", str(self.recurrence))
323 def apply_settings(self, enabled, recurrence):
324 self._enabled = enabled
327 def recurrence(self):
328 return self._recurrence
335 _BACKGROUND_ALARM_FACTORY = {
336 _FREMANTLE_ALARM: _FremantleAlarmHandler,
337 _DIABLO_ALARM: _DiabloAlarmHandler,
342 class AlarmHandler(object):
344 ALARM_NONE = "No Alert"
345 ALARM_BACKGROUND = "Background Alert"
346 ALARM_APPLICATION = "Application Alert"
347 ALARM_TYPES = [ALARM_NONE, ALARM_BACKGROUND, ALARM_APPLICATION]
350 ALARM_NONE: _NoneAlarmHandler,
351 ALARM_BACKGROUND: _BACKGROUND_ALARM_FACTORY,
352 ALARM_APPLICATION: _ApplicationAlarmHandler,
356 self._alarms = {self.ALARM_NONE: _NoneAlarmHandler()}
357 self._currentAlarmType = self.ALARM_NONE
359 def load_settings(self, config, sectionName):
361 self._currentAlarmType = config.get(sectionName, "alarm")
362 except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
363 _moduleLogger.exception("Falling back to old style")
364 self._currentAlarmType = self.ALARM_BACKGROUND
365 if self._currentAlarmType not in self.ALARM_TYPES:
366 self._currentAlarmType = self.ALARM_NONE
368 self._init_alarm(self._currentAlarmType)
369 if self._currentAlarmType in self._alarms:
370 self._alarms[self._currentAlarmType].load_settings(config, sectionName)
371 if not self._alarms[self._currentAlarmType].isEnabled:
372 _moduleLogger.info("Config file lied, not actually enabled")
373 self._currentAlarmType = self.ALARM_NONE
375 _moduleLogger.info("Background alerts not supported")
376 self._currentAlarmType = self.ALARM_NONE
378 def save_settings(self, config, sectionName):
379 config.set(sectionName, "alarm", self._currentAlarmType)
380 self._alarms[self._currentAlarmType].save_settings(config, sectionName)
382 def apply_settings(self, t, recurrence):
384 newHandler = self._alarms[t]
385 oldHandler = self._alarms[self._currentAlarmType]
386 if newHandler != oldHandler:
387 oldHandler.apply_settings(False, 0)
388 newHandler.apply_settings(True, recurrence)
389 self._currentAlarmType = t
393 return self._currentAlarmType
396 def backgroundNotificationsSupported(self):
397 return self.ALARM_FACTORY[self.ALARM_BACKGROUND] is not None
400 def applicationNotifySignal(self):
401 self._init_alarm(self.ALARM_APPLICATION)
402 return self._alarms[self.ALARM_APPLICATION].notifySignal
405 def recurrence(self):
406 return self._alarms[self._currentAlarmType].recurrence
410 return self._currentAlarmType != self.ALARM_NONE
412 def _init_alarm(self, t):
413 if t not in self._alarms and self.ALARM_FACTORY[t] is not None:
414 self._alarms[t] = self.ALARM_FACTORY[t]()
418 logFormat = '(%(relativeCreated)5d) %(levelname)-5s %(threadName)s.%(name)s.%(funcName)s: %(message)s'
419 logging.basicConfig(level=logging.DEBUG, format=logFormat)
426 parser = optparse.OptionParser()
427 parser.add_option("-x", "--display", action="store_true", dest="display", help="Display data")
428 parser.add_option("-e", "--enable", action="store_true", dest="enabled", help="Whether the alarm should be enabled or not", default=False)
429 parser.add_option("-d", "--disable", action="store_false", dest="enabled", help="Whether the alarm should be enabled or not", default=False)
430 parser.add_option("-r", "--recurrence", action="store", type="int", dest="recurrence", help="How often the alarm occurs", default=5)
431 (commandOptions, commandArgs) = parser.parse_args()
433 alarmHandler = AlarmHandler()
434 config = ConfigParser.SafeConfigParser()
435 config.read(constants._user_settings_)
436 alarmHandler.load_settings(config, "alarm")
438 if commandOptions.display:
439 print "Alarm (%s) is %s for every %d minutes" % (
440 alarmHandler._alarmCookie,
441 "enabled" if alarmHandler.isEnabled else "disabled",
442 alarmHandler.recurrence,
445 isEnabled = commandOptions.enabled
446 recurrence = commandOptions.recurrence
447 alarmHandler.apply_settings(isEnabled, recurrence)
449 alarmHandler.save_settings(config, "alarm")
450 configFile = open(constants._user_settings_, "wb")
452 config.write(configFile)
457 if __name__ == "__main__":