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-v1.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 #self.dbg('self.missedLastCall: ' + self.missedLastCall)
305 #self.dbg('self.getMissedCallsCount(False): ' + self.getMissedCallsCount(False))
306 if self.missedLastCall != self.getMissedCallsCount(False):
307 if self.msgType == "SMS":
308 self.msgType = "Both"
310 self.msgType = "Call"
312 self.missedLastCall = self.getMissedCallsCount(False)
315 def stop_notification(self, a):
316 self.dbg('stop_notification started')
318 self.set_status_area_icon(None)
319 # Reset the notification (get recent missed call count)
320 self.missed = self.getMissedCallsCount(False)
321 self.missedSMS = self.getMissedCallsCount(True)
322 self.missedLastCall = self.missed
323 self.missedLastSMS = self.missedSMS
326 gobject.source_remove(self.tmr_ptr)
327 gobject.source_remove(self.tmr_ptr2)
333 self.dbg('theLoop started')
334 missedCalls = self.getMissedCallsCount(False)
335 if self.missedLastCall != missedCalls:
337 self.missedLastCall = missedCalls
340 def getMissedCallsCount(self, isSms):
341 self.dbg('getMissedCallsCount started. agrs: ' + str(isSms))
342 conn = sqlite3.connect(self.path)
345 #Nokia changed the event number from 7 to 11 and also combined the incomming and outgoing sms's
346 cur.execute("select count(id) from Events where event_type_id = 11 and outgoing = 0")
348 #Nokia changed the event from 3 to 2
349 cur.execute("select count(id) from Events where event_type_id = 2")
350 return cur.fetchone()[0]
353 self.dbg('show started')
354 # blink the icon every 1 second
356 self.readConfigurationFile()
359 self.tmr_ptr = gobject.timeout_add(1000, self.blinkIcon)
360 self.tmr_ptr2 = gobject.timeout_add(int(self.interval*1000*60), self.playSound)
363 self.dbg('blinkIcon started')
366 img = self.callPicture
367 if self.msgType == "SMS":
368 img = self.smsPicture
369 self.set_status_area_icon(img)
372 img = self.smsPicture
374 counter = self.missed
375 if self.msgType == "SMS":
376 counter = self.missedSMS
378 index = self.getMissedCallsCount(isSMS) - counter - 1
383 if self.msgType != "Both":
384 img = self.imgList[index]
386 self.set_status_area_icon(img)
391 f = open(self.configDir+'log.txt', 'a')
392 f.write(str(datetime.datetime.now()) + ': '+ txt)
397 hd_plugin_type = CallNotify
400 # Uncomment from "if __name__..." to "gtk.main()" if running from CLI as:
401 # "run-standalone.sh python CallNotify.py"
403 if __name__=="__main__":
404 gobject.type_register(hd_plugin_type)
405 obj = gobject.new(hd_plugin_type, plugin_id="plugid_id")