3 from __future__ import with_statement
13 import dialcentral.util.qt_compat as qt_compat
14 QtCore = qt_compat.QtCore
15 import dialcentral.util.linux as linux_utils
18 _FREMANTLE_ALARM = "Fremantle"
19 _DIABLO_ALARM = "Diablo"
25 ALARM_TYPE = _FREMANTLE_ALARM
26 except (ImportError, OSError):
28 import osso.alarmd as alarmd
29 ALARM_TYPE = _DIABLO_ALARM
30 except (ImportError, OSError):
31 ALARM_TYPE = _NO_ALARM
34 _moduleLogger = logging.getLogger(__name__)
37 def _get_start_time(recurrence):
38 now = datetime.datetime.now()
39 startTimeMinute = now.minute + max(recurrence, 5) # being safe
40 startTimeHour = now.hour + int(startTimeMinute / 60)
41 startTimeMinute = startTimeMinute % 59
42 now.replace(minute=startTimeMinute)
43 timestamp = int(time.mktime(now.timetuple()))
47 def _create_recurrence_mask(recurrence, base):
49 >>> bin(_create_recurrence_mask(60, 60))
51 >>> bin(_create_recurrence_mask(30, 60))
52 '0b1000000000000000000000000000001'
53 >>> bin(_create_recurrence_mask(2, 60))
54 '0b10101010101010101010101010101010101010101010101010101010101'
55 >>> bin(_create_recurrence_mask(1, 60))
56 '0b111111111111111111111111111111111111111111111111111111111111'
59 for i in xrange(base / recurrence):
60 mask |= 1 << (recurrence * i)
64 def _unpack_minutes(recurrence):
66 >>> _unpack_minutes(0)
68 >>> _unpack_minutes(1)
70 >>> _unpack_minutes(59)
72 >>> _unpack_minutes(60)
74 >>> _unpack_minutes(129)
76 >>> _unpack_minutes(5 * 60 * 24 + 3 * 60 + 2)
78 >>> _unpack_minutes(12 * 60 * 24 + 3 * 60 + 2)
82 minutesInDay = 24 * minutesInAnHour
83 minutesInAWeek = minutesInDay * 7
85 days = recurrence / minutesInDay
87 recurrence -= days * minutesInDay
88 hours = recurrence / minutesInAnHour
89 recurrence -= hours * minutesInAnHour
90 mins = recurrence % minutesInAnHour
92 assert recurrence == 0, "Recurrence %d" % recurrence
93 return daysOfWeek, hours, mins
96 class _FremantleAlarmHandler(object):
100 _TITLE = "Dialcentral Notifications"
101 _LAUNCHER = "python %s" % os.path.abspath(os.path.join(os.path.dirname(__file__), "alarm_notify.py"))
106 self._alarmCookie = self._INVALID_COOKIE
107 self._launcher = self._LAUNCHER
110 def alarmCookie(self):
111 return self._alarmCookie
113 def load_settings(self, config, sectionName):
115 self._recurrence = config.getint(sectionName, "recurrence")
116 self._alarmCookie = config.getint(sectionName, "alarmCookie")
117 launcher = config.get(sectionName, "notifier")
119 self._launcher = launcher
120 except ConfigParser.NoOptionError:
122 except ConfigParser.NoSectionError:
125 def save_settings(self, config, sectionName):
127 config.set(sectionName, "recurrence", str(self._recurrence))
128 config.set(sectionName, "alarmCookie", str(self._alarmCookie))
129 launcher = self._launcher if self._launcher != self._LAUNCHER else ""
130 config.set(sectionName, "notifier", launcher)
131 except ConfigParser.NoOptionError:
133 except ConfigParser.NoSectionError:
136 def apply_settings(self, enabled, recurrence):
137 if recurrence != self._recurrence or enabled != self.isEnabled:
141 self._set_alarm(recurrence)
142 self._recurrence = int(recurrence)
145 def recurrence(self):
146 return self._recurrence
150 return self._alarmCookie != self._INVALID_COOKIE
152 def _set_alarm(self, recurrenceMins):
153 assert 1 <= recurrenceMins, "Notifications set to occur too frequently: %d" % recurrenceMins
154 alarmTime = _get_start_time(recurrenceMins)
156 event = alarm.Event()
157 event.appid = self._TITLE
158 event.alarm_time = alarmTime
159 event.recurrences_left = self._REPEAT_FOREVER
161 action = event.add_actions(1)[0]
162 action.flags |= alarm.ACTION_TYPE_EXEC | alarm.ACTION_WHEN_TRIGGERED
163 action.command = self._launcher
165 recurrence = event.add_recurrences(1)[0]
166 recurrence.mask_min |= _create_recurrence_mask(recurrenceMins, 60)
167 recurrence.mask_hour |= alarm.RECUR_HOUR_DONTCARE
168 recurrence.mask_mday |= alarm.RECUR_MDAY_DONTCARE
169 recurrence.mask_wday |= alarm.RECUR_WDAY_DONTCARE
170 recurrence.mask_mon |= alarm.RECUR_MON_DONTCARE
171 recurrence.special |= alarm.RECUR_SPECIAL_NONE
173 assert event.is_sane()
174 self._alarmCookie = alarm.add_event(event)
176 def _clear_alarm(self):
177 if self._alarmCookie == self._INVALID_COOKIE:
179 alarm.delete_event(self._alarmCookie)
180 self._alarmCookie = self._INVALID_COOKIE
183 class _DiabloAlarmHandler(object):
186 _TITLE = "Dialcentral Notifications"
187 _LAUNCHER = "python %s" % os.path.abspath(os.path.join(os.path.dirname(__file__), "alarm_notify.py"))
193 bus = dbus.SystemBus()
194 self._alarmdDBus = bus.get_object("com.nokia.alarmd", "/com/nokia/alarmd");
195 self._alarmCookie = self._INVALID_COOKIE
196 self._launcher = self._LAUNCHER
199 def alarmCookie(self):
200 return self._alarmCookie
202 def load_settings(self, config, sectionName):
204 self._recurrence = config.getint(sectionName, "recurrence")
205 self._alarmCookie = config.getint(sectionName, "alarmCookie")
206 launcher = config.get(sectionName, "notifier")
208 self._launcher = launcher
209 except ConfigParser.NoOptionError:
211 except ConfigParser.NoSectionError:
214 def save_settings(self, config, sectionName):
215 config.set(sectionName, "recurrence", str(self._recurrence))
216 config.set(sectionName, "alarmCookie", str(self._alarmCookie))
217 launcher = self._launcher if self._launcher != self._LAUNCHER else ""
218 config.set(sectionName, "notifier", launcher)
220 def apply_settings(self, enabled, recurrence):
221 if recurrence != self._recurrence or enabled != self.isEnabled:
225 self._set_alarm(recurrence)
226 self._recurrence = int(recurrence)
229 def recurrence(self):
230 return self._recurrence
234 return self._alarmCookie != self._INVALID_COOKIE
236 def _set_alarm(self, recurrence):
237 assert 1 <= recurrence, "Notifications set to occur too frequently: %d" % recurrence
238 alarmTime = _get_start_time(recurrence)
240 #Setup the alarm arguments so that they can be passed to the D-Bus add_event method
242 alarmd.ALARM_EVENT_NO_DIALOG |
243 alarmd.ALARM_EVENT_NO_SNOOZE |
244 alarmd.ALARM_EVENT_CONNECTED
247 action.extend(['flags', _DEFAULT_FLAGS])
248 action.extend(['title', self._TITLE])
249 action.extend(['path', self._launcher])
253 [alarmTime, int(27)],
254 signature=dbus.Signature('v')
256 ]) #int(27) used in place of alarm_index
259 event.extend([dbus.ObjectPath('/AlarmdEventRecurring'), dbus.UInt32(4)])
260 event.extend(['action', dbus.ObjectPath('/AlarmdActionExec')]) #use AlarmdActionExec instead of AlarmdActionDbus
261 event.append(dbus.UInt32(len(action) / 2))
263 event.extend(['time', dbus.Int64(alarmTime)])
264 event.extend(['recurr_interval', dbus.UInt32(recurrence)])
265 event.extend(['recurr_count', dbus.Int32(self._REPEAT_FOREVER)])
267 self._alarmCookie = self._alarmdDBus.add_event(*event);
269 def _clear_alarm(self):
270 if self._alarmCookie == self._INVALID_COOKIE:
272 deleteResult = self._alarmdDBus.del_event(dbus.Int32(self._alarmCookie))
273 self._alarmCookie = self._INVALID_COOKIE
274 assert deleteResult != -1, "Deleting of alarm event failed"
277 class _ApplicationAlarmHandler(object):
280 _MIN_TO_MS_FACTORY = 1000 * 60
283 self._timer = QtCore.QTimer()
284 self._timer.setSingleShot(False)
285 self._timer.setInterval(5 * self._MIN_TO_MS_FACTORY)
288 def alarmCookie(self):
291 def load_settings(self, config, sectionName):
293 self._timer.setInterval(config.getint(sectionName, "recurrence") * self._MIN_TO_MS_FACTORY)
294 except ConfigParser.NoOptionError:
296 except ConfigParser.NoSectionError:
300 def save_settings(self, config, sectionName):
301 config.set(sectionName, "recurrence", str(self.recurrence))
303 def apply_settings(self, enabled, recurrence):
304 self._timer.setInterval(recurrence * self._MIN_TO_MS_FACTORY)
311 def notifySignal(self):
312 return self._timer.timeout
315 def recurrence(self):
316 return int(self._timer.interval() / self._MIN_TO_MS_FACTORY)
320 return self._timer.isActive()
323 class _NoneAlarmHandler(object):
326 self._enabled = False
330 def alarmCookie(self):
333 def load_settings(self, config, sectionName):
335 self._recurrence = config.getint(sectionName, "recurrence")
337 except ConfigParser.NoOptionError:
339 except ConfigParser.NoSectionError:
342 def save_settings(self, config, sectionName):
343 config.set(sectionName, "recurrence", str(self.recurrence))
345 def apply_settings(self, enabled, recurrence):
346 self._enabled = enabled
349 def recurrence(self):
350 return self._recurrence
357 _BACKGROUND_ALARM_FACTORY = {
358 _FREMANTLE_ALARM: _FremantleAlarmHandler,
359 _DIABLO_ALARM: _DiabloAlarmHandler,
364 class AlarmHandler(object):
366 ALARM_NONE = "No Alert"
367 ALARM_BACKGROUND = "Background Alert"
368 ALARM_APPLICATION = "Application Alert"
369 ALARM_TYPES = [ALARM_NONE, ALARM_BACKGROUND, ALARM_APPLICATION]
372 ALARM_NONE: _NoneAlarmHandler,
373 ALARM_BACKGROUND: _BACKGROUND_ALARM_FACTORY,
374 ALARM_APPLICATION: _ApplicationAlarmHandler,
378 self._alarms = {self.ALARM_NONE: _NoneAlarmHandler()}
379 self._currentAlarmType = self.ALARM_NONE
381 def load_settings(self, config, sectionName):
383 self._currentAlarmType = config.get(sectionName, "alarm")
384 except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
385 _moduleLogger.exception("Falling back to old style")
386 self._currentAlarmType = self.ALARM_BACKGROUND
387 if self._currentAlarmType not in self.ALARM_TYPES:
388 self._currentAlarmType = self.ALARM_NONE
390 self._init_alarm(self._currentAlarmType)
391 if self._currentAlarmType in self._alarms:
392 self._alarms[self._currentAlarmType].load_settings(config, sectionName)
393 if not self._alarms[self._currentAlarmType].isEnabled:
394 _moduleLogger.info("Config file lied, not actually enabled")
395 self._currentAlarmType = self.ALARM_NONE
397 _moduleLogger.info("Background alerts not supported")
398 self._currentAlarmType = self.ALARM_NONE
400 def save_settings(self, config, sectionName):
401 config.set(sectionName, "alarm", self._currentAlarmType)
402 self._alarms[self._currentAlarmType].save_settings(config, sectionName)
404 def apply_settings(self, t, recurrence):
406 newHandler = self._alarms[t]
407 oldHandler = self._alarms[self._currentAlarmType]
408 if newHandler != oldHandler:
409 oldHandler.apply_settings(False, 0)
410 newHandler.apply_settings(True, recurrence)
411 self._currentAlarmType = t
415 return self._currentAlarmType
418 def backgroundNotificationsSupported(self):
419 return self.ALARM_FACTORY[self.ALARM_BACKGROUND] is not None
422 def applicationNotifySignal(self):
423 self._init_alarm(self.ALARM_APPLICATION)
424 return self._alarms[self.ALARM_APPLICATION].notifySignal
427 def recurrence(self):
428 return self._alarms[self._currentAlarmType].recurrence
432 return self._currentAlarmType != self.ALARM_NONE
435 def alarmCookie(self):
436 return self._alarms[self._currentAlarmType].alarmCookie
438 def _init_alarm(self, t):
439 if t not in self._alarms and self.ALARM_FACTORY[t] is not None:
440 self._alarms[t] = self.ALARM_FACTORY[t]()
444 logFormat = '(%(relativeCreated)5d) %(levelname)-5s %(threadName)s.%(name)s.%(funcName)s: %(message)s'
445 logging.basicConfig(level=logging.DEBUG, format=logFormat)
446 from dialcentral import constants
452 parser = optparse.OptionParser()
453 parser.add_option("-x", "--display", action="store_true", dest="display", help="Display data")
454 parser.add_option("-e", "--enable", action="store_true", dest="enabled", help="Whether the alarm should be enabled or not", default=False)
455 parser.add_option("-d", "--disable", action="store_false", dest="enabled", help="Whether the alarm should be enabled or not", default=False)
456 parser.add_option("-r", "--recurrence", action="store", type="int", dest="recurrence", help="How often the alarm occurs", default=5)
457 (commandOptions, commandArgs) = parser.parse_args()
459 settingsPath = linux_utils.get_resource_path("config", constants.__app_name__, "settings.ini")
461 alarmHandler = AlarmHandler()
462 config = ConfigParser.SafeConfigParser()
463 config.read(settingsPath)
464 alarmHandler.load_settings(config, "alarm")
466 if commandOptions.display:
467 print "Alarm (%s) is %s for every %d minutes" % (
468 alarmHandler.alarmCookie,
469 "enabled" if alarmHandler.isEnabled else "disabled",
470 alarmHandler.recurrence,
473 isEnabled = commandOptions.enabled
474 recurrence = commandOptions.recurrence
476 if alarmHandler.backgroundNotificationsSupported:
477 enableType = AlarmHandler.ALARM_BACKGROUND
479 enableType = AlarmHandler.ALARM_APPLICATION
480 alarmHandler.apply_settings(enableType if isEnabled else AlarmHandler.ALARM_NONE, recurrence)
482 alarmHandler.save_settings(config, "alarm")
483 with open(settingsPath, "wb") as configFile:
484 config.write(configFile)
487 if __name__ == "__main__":