3 import hildon, hildondesktop
8 import atexit, os, datetime
9 from dbus.mainloop.glib import DBusGMainLoop
12 class CallNotify(hildondesktop.StatusMenuItem):
14 hildondesktop.StatusMenuItem.__init__(self)
16 self.configDir = "/home/user/.config/CallNotify/"
17 self.configFile = "conf.txt"
19 self.dbg("debugging started")
20 self.readConfigurationFile()
24 self.path = "/home/user/.rtcom-eventlogger/el.db"
25 self.missed = self.getMissedCallsCount(False)
26 self.missedSMS = self.getMissedCallsCount(True)
27 self.missedLastCall = self.missed
28 self.missedLastSMS = self.missedSMS
30 self.soundFile = "/usr/share/CallNotify/missed.wav"
31 self.dbg('constructor')
36 # Register to handle screen off/on events
37 osso_c = osso.Context("osso_test_device_on", "0.0.1", False)
38 device = osso.DeviceState(osso_c)
39 #device.set_display_event_cb(self.state_cb)
41 # Check missed calls notification
42 self.tmr_main = gobject.timeout_add(5000, self.handleMissedCall)
44 # add d-bus listener for removing notification after viewing missed call
45 # Doing timeout_add with return False instead of explicitly raising a thread
46 gobject.timeout_add(500, self.startDbusListeners)
47 #atexit.register(self.cleanup)
51 self.dbg('constructor end')
55 label = gtk.Label("Call Notify")
58 button.connect("clicked", self.openSettingsDialog)
61 self.dbg('addGUI end')
63 def checkForConfigFile(self):
64 self.dbg('checkForConfigFile started')
66 if not os.path.exists(self.configDir):
67 os.mkdir(self.configDir)
68 if not os.path.exists(self.configDir+self.configFile):
69 a = open(self.configDir+self.configFile,'w+')
70 a.write('y;y;y;5.0\n')
72 # set proper permissions
73 os.system("chmod 766 " + self.configDir)
74 os.system("chmod 766" + self.configDir+self.configFile)
77 def readConfigurationFile(self):
79 self.dbg('readConfigurationFile started')
80 self.checkForConfigFile()
81 f = open(self.configDir+self.configFile, 'r')
82 raw_set = f.readline().rsplit(';')
83 self.visual = raw_set[0] in ('y')
84 self.sound = raw_set[1] in ('y')
85 self.vibration = raw_set[2] in ('y')
86 self.interval = float(raw_set[3].replace(',','.'))
89 os.remove(self.configDir+self.configFile)
90 self.checkForConfigFile()
92 def saveConfigurationFile(self):
93 self.dbg('saveConfigurationFile started')
94 f = open(self.configDir+self.configFile, "w")
111 conf += str(self.interval)
116 def openSettingsDialog(self, widget, data=None):
117 self.dbg('openSettingsDialog started')
118 self.dialog = gtk.Dialog(title="Call Notify Settings")
119 self.dialog.set_size_request(800,300)
120 #self.dialog.connect("response", self.dialogClosed)
121 self.readConfigurationFile()
124 b2 = gtk.CheckButton(label="Visual Notification On")
125 b2.connect("clicked", self.notificationActivate)
126 b2.set_active(self.visual)
127 self.dialog.vbox.add(b2)
131 b3 = gtk.CheckButton(label="Sound Notification On")
132 b3.connect("clicked", self.soundActivate)
133 b3.set_active(self.sound)
134 self.dialog.vbox.add(b3)
138 b4 = gtk.CheckButton(label="Vibrate Notification On")
139 b4.connect("clicked", self.vibrateActivate)
140 b4.set_active(self.vibration)
141 self.dialog.vbox.add(b4)
145 Adj = gtk.Adjustment(self.interval, lower=0, upper=60, step_incr=5, page_incr=5)
146 Adj.connect("value_changed", self.intervalChanged)
147 Adj.set_value(self.interval)
149 Slider = gtk.HScale(adjustment=Adj)
150 self.dialog.vbox.add(Slider)
154 b5 = gtk.Button(label="Manually reset notification")
155 b5.connect("clicked", self.resetNotification)
156 self.dialog.vbox.add(b5)
160 bSave = gtk.Button(label="Save")
161 bSave.connect("clicked", self.saveSettings)
162 self.dialog.action_area.add(bSave)
166 bCancel = gtk.Button(label="Cancel")
167 bCancel.connect("clicked", self.cancelDialog)
168 self.dialog.vbox.add(bCancel)
170 self.dialog.show_all()
172 def intervalChanged(self, adj):
173 self.dbg('intervalChanged started')
174 self.interval = adj.value
176 def saveSettings(self, widget, data=None):
177 self.dbg('saveSettings started')
178 self.saveConfigurationFile()
180 def dialogClosed(self, dialog, response_id):
181 self.dbg('dialogClosed started')
183 def cancelDialog(self, widget, data=None):
184 self.dbg('cancelDialog started')
185 self.dialog.destroy()
187 def resetNotification(self, widget, data=None):
188 self.dbg('resetNotification started')
189 self.stop_notification(self)
191 def soundActivate(self, widget, data=None):
192 self.dbg('soundActivate started')
193 self.sound = widget.get_active() #not(self.sound)
195 def notificationActivate(self,widget, data=None):
196 self.dbg('notificationActivate started')
197 self.visual = widget.get_active() #not(self.visual)
199 def vibrateActivate(self, widget, data=None):
200 self.dbg('vibrateActivate started')
201 self.vibration = widget.get_active() #not(self.vibrate)
205 self.dbg('playSound started')
207 hildon.hildon_play_system_sound(self.soundFile)
208 #pygame.time.delay(1000)
210 bb = 'run-standalone.sh dbus-send --print-reply --system --dest=com.nokia.mce /com/nokia/mce/request com.nokia.mce.request.req_vibrator_pattern_activate string:' + "\'PatternIncomingCall\'"
214 bb = 'run-standalone.sh dbus-send --print-reply --system --dest=com.nokia.mce /com/nokia/mce/request com.nokia.mce.request.req_vibrator_pattern_deactivate string:' + "\'PatternIncomingCall\'"
221 self.dbg('cleanup started')
222 gobject.source_remove(self.tmr_main)
223 gobject.source_remove(self.tmr_ptr)
224 gobject.source_remove(self.tmr_ptr2)
228 def loadImages(self):
229 self.dbg('loadImages started')
231 #self.pixbuf = gtk.gdk.pixbuf_new_from_file_at_size("/home/user/phone.png",18,18)
232 icon_theme = gtk.icon_theme_get_default()
233 self.callPicture = gtk.gdk.pixbuf_new_from_file_at_size("/usr/share/CallNotify/call.png",18,18)
234 #icon_theme.load_icon("general_call", 18, gtk.ICON_LOOKUP_NO_SVG)
235 self.smsPicture = gtk.gdk.pixbuf_new_from_file_at_size("/usr/share/CallNotify/sms.png",18,18)
237 # Load 5 numbers and the "+5"
239 #self.imgList.append(gtk.gdk.pixbuf_new_from_file_at_size("/home/user/1.png",18,18))
240 self.imgList.append(gtk.gdk.pixbuf_new_from_file_at_size("/usr/share/CallNotify/1.png",18,18))
241 self.imgList.append(gtk.gdk.pixbuf_new_from_file_at_size("/usr/share/CallNotify/2.png",18,18))
242 self.imgList.append(gtk.gdk.pixbuf_new_from_file_at_size("/usr/share/CallNotify/3.png",18,18))
243 self.imgList.append(gtk.gdk.pixbuf_new_from_file_at_size("/usr/share/CallNotify/4.png",18,18))
244 self.imgList.append(gtk.gdk.pixbuf_new_from_file_at_size("/usr/share/CallNotify/5.png",18,18))
245 self.imgList.append(gtk.gdk.pixbuf_new_from_file_at_size("/usr/share/CallNotify/more.png",18,18))
247 # Screen off event-handler
248 def state_cb(self, state, a):
249 self.dbg('state_cb started')
250 if state == osso.device_state.OSSO_DISPLAY_OFF:
252 #gobject.source_remove(self.tmr_main)
254 #gobject.source_remove(self.tmr_ptr)
256 #gobject.source_remove(self.tmr_ptr2)
259 elif state == osso.device_state.OSSO_DISPLAY_ON:
262 #self.tmr_main = gobject.timeout_add(5000, self.handleMissedCall)
263 #self.handleMissedCall()
266 # Method to define the way to add dbus signal receiver
268 def smsRead2(self, a):
269 self.dbg('smsrec started')
270 self.stop_notification(self)
272 def startDbusListeners(self):
273 self.dbg('startDbusListeners started')
274 DBusGMainLoop(set_as_default=True)
275 bus = dbus.SessionBus()
276 #bus.add_signal_receiver(self.stop_notification, "NotificationClosed", "org.freedesktop.Notifications", "org.freedesktop.Notifications", "/org/freedesktop/Notifications")
277 #bus.add_signal_receiver(self.handleMissedCall, "Notify", None, None, None)
278 #bus.add_signal_receiver(self.handleMissedCall, "MembersChanged", None, None, None)
279 bus.add_signal_receiver(self.smsReceived, "MessageReceived", None, None, None)
280 bus.add_signal_receiver(self.smsRead, "NotificationClosed", "org.freedesktop.Notifications", None, "/org/freedesktop/Notifications")
281 bus.add_signal_receiver(self.smsRead2, "PendingMessagesRemoved", None, None, None)
283 self.mainLoop = gobject.MainLoop()
287 def smsReceived(self, a):
288 self.dbg('snsReceived started')
289 if a[0].has_key('message-type'):
290 if self.missedLastSMS == self.getMissedCallsCount(True):
291 if self.msgType == "Call":
292 self.msgType = "Both"
296 self.missedLastSMS = self.getMissedCallsCount(True)
298 def smsRead(self, a):
299 self.dbg('smsRead started')
300 self.stop_notification(a)
302 def handleMissedCall(self):
303 self.dbg('handleMissedCall started')
304 if self.missedLastCall != self.getMissedCallsCount(False):
305 if self.msgType == "SMS":
306 self.msgType = "Both"
308 self.msgType = "Call"
310 self.missedLastCall = self.getMissedCallsCount(False)
313 def stop_notification(self, a):
314 self.dbg('stop_notification started')
316 self.set_status_area_icon(None)
317 # Reset the notification (get recent missed call count)
318 self.missed = self.getMissedCallsCount(False)
319 self.missedSMS = self.getMissedCallsCount(True)
320 self.missedLastCall = self.missed
321 self.missedLastSMS = self.missedSMS
324 gobject.source_remove(self.tmr_ptr)
325 gobject.source_remove(self.tmr_ptr2)
331 self.dbg('theLoop started')
332 missedCalls = self.getMissedCallsCount(False)
333 if self.missedLastCall != missedCalls:
335 self.missedLastCall = missedCalls
338 def getMissedCallsCount(self, isSms):
339 self.dbg('getMissedCallsCount started. agrs: ' + str(isSms))
343 conn = sqlite3.connect(self.path)
345 cur.execute("select count(id) from Events where event_type_id = " + str(eType))
346 return cur.fetchone()[0]
349 self.dbg('show started')
350 # blink the icon every 1 second
352 self.readConfigurationFile()
355 self.tmr_ptr = gobject.timeout_add(1000, self.blinkIcon)
356 self.tmr_ptr2 = gobject.timeout_add(int(self.interval*1000*60), self.playSound)
359 self.dbg('blinkIcon started')
362 img = self.callPicture
363 if self.msgType == "SMS":
364 img = self.smsPicture
365 self.set_status_area_icon(img)
368 img = self.smsPicture
370 counter = self.missed
371 if self.msgType == "SMS":
372 counter = self.missedSMS
374 index = self.getMissedCallsCount(isSMS) - counter - 1
379 if self.msgType != "Both":
380 img = self.imgList[index]
382 self.set_status_area_icon(img)
387 f = open(self.configDir+'log.txt', 'a')
388 f.write(str(datetime.datetime.now()) + ': '+ txt)
393 hd_plugin_type = CallNotify
396 # Uncomment from "if __name__..." to "gtk.main()" if running from CLI as:
397 # "run-standalone.sh python CallNotify.py"
399 #if __name__=="__main__":
400 # gobject.type_register(hd_plugin_type)
401 # obj = gobject.new(hd_plugin_type, plugin_id="plugid_id")