Imported Upstream version 0.1.2
[callnotify] / src / usr / lib / hildon-desktop / CallNotify.py
old mode 100644 (file)
new mode 100755 (executable)
index d05e5d6..4552a8b
 import gtk
 import gobject
-import hildondesktop
+import hildon, hildondesktop
 import sqlite3
 import time
 import dbus
+import osso
+import atexit, os, datetime
 from dbus.mainloop.glib import DBusGMainLoop
 
 
 class CallNotify(hildondesktop.StatusMenuItem):
     def __init__(self):
                hildondesktop.StatusMenuItem.__init__(self)
-               
-               self.path = "/home/user/.rtcom-eventlogger/el.db"
-               
-               # Prevent multiple timers to refresh the status icon
-               self.stop = False
-               
-               # Load images
-               self.loadImages()
+               # Set members
+               self.configDir = "/home/user/.config/CallNotify/"
+               self.configFile = "conf.txt"
+               self.Debug = False
+               self.dbg("debugging started")
+               self.readConfigurationFile()
                self.msgType = ""               
                self.toShow = True
+               self.stop = False
+               self.path = "/home/user/.rtcom-eventlogger/el-v1.db"
                self.missed = self.getMissedCallsCount(False)
                self.missedSMS = self.getMissedCallsCount(True)
                self.missedLastCall = self.missed
                self.missedLastSMS = self.missedSMS
-               gobject.timeout_add(5000, self.handleMissedCall) 
+               self.mainLoop = None    
+               self.soundFile = "/usr/share/CallNotify/missed.wav"
+               self.dbg('constructor')
                
+               # Load images
+               self.loadImages()
+                       
+               # Register to handle screen off/on events
+               osso_c = osso.Context("osso_test_device_on", "0.0.1", False)
+               device = osso.DeviceState(osso_c)
+               #device.set_display_event_cb(self.state_cb)
+               
+               # Check missed calls notification
+               self.tmr_main = gobject.timeout_add(5000, self.handleMissedCall) 
+               self.tmrset = True      
                # add d-bus listener for removing notification after viewing missed call
                # Doing timeout_add with return False instead of explicitly raising a thread
                gobject.timeout_add(500, self.startDbusListeners)
+               #atexit.register(self.cleanup)
+               
+               # add GUI buttons
+               # self.addGUI()
+               self.dbg('constructor end')
+       
+    def addGUI(self):
+         # add GUI buttons                                              
+                label = gtk.Label("Call Notify")                               
+                button = gtk.Button()                                          
+                button.add(label)                                              
+                button.connect("clicked", self.openSettingsDialog)             
+                self.add(button)                                               
+                self.show_all()    
+               self.dbg('addGUI end')
+
+    def checkForConfigFile(self):
+               self.dbg('checkForConfigFile started')
+               os.umask(0)
+               if not os.path.exists(self.configDir):
+                       os.mkdir(self.configDir)
+               if not os.path.exists(self.configDir+self.configFile):
+                       a = open(self.configDir+self.configFile,'w+')
+                       a.write('y;y;y;5.0\n')
+                       a.close()
+               # set proper permissions
+               os.system("chmod 766 " + self.configDir)
+               os.system("chmod 766" + self.configDir+self.configFile)
+
+                
+    def readConfigurationFile(self):
+               try:
+                       self.dbg('readConfigurationFile started')
+                       self.checkForConfigFile()
+                       f = open(self.configDir+self.configFile, 'r')
+                       raw_set = f.readline().rsplit(';')
+                       self.visual = raw_set[0] in ('y')
+                       self.sound = raw_set[1] in ('y')
+                       self.vibration = raw_set[2] in ('y')
+                       self.interval = float(raw_set[3].replace(',','.'))
+                       f.close()
+               except:
+                       os.remove(self.configDir+self.configFile)
+                       self.checkForConfigFile()
+       
+    def saveConfigurationFile(self):
+               self.dbg('saveConfigurationFile started')
+               f = open(self.configDir+self.configFile, "w")
+               conf = ''
+               if self.visual:
+                       conf += 'y;'
+               else:
+                       conf += 'n;'
+
+               if self.sound:
+                       conf += 'y;'
+               else:
+                       conf +='n;'
+       
+               if self.vibration:
+                       conf += 'y;'
+               else:
+                       conf += 'n;'
+
+               conf += str(self.interval)
+       
+               f.write(conf)
+               f.close()
+
+    def openSettingsDialog(self, widget, data=None):
+               self.dbg('openSettingsDialog started')
+               self.dialog = gtk.Dialog(title="Call Notify Settings")               
+                self.dialog.set_size_request(800,300)
+               #self.dialog.connect("response", self.dialogClosed)  
+               self.readConfigurationFile()            
+               # Visual
+                               
+                b2 = gtk.CheckButton(label="Visual Notification On")           
+                b2.connect("clicked", self.notificationActivate)               
+               b2.set_active(self.visual)
+                self.dialog.vbox.add(b2)                    
+                               
+                               # Sound
+                               
+                b3 = gtk.CheckButton(label="Sound Notification On")            
+                b3.connect("clicked", self.soundActivate)                      
+               b3.set_active(self.sound) 
+                self.dialog.vbox.add(b3)  
+                               
+                               # Vibration
+                               
+               b4 = gtk.CheckButton(label="Vibrate Notification On")            
+                b4.connect("clicked", self.vibrateActivate)                      
+               b4.set_active(self.vibration)
+                self.dialog.vbox.add(b4)  
+                               
+                               # Slider
+                               
+               Adj = gtk.Adjustment(self.interval, lower=0, upper=60, step_incr=5, page_incr=5)
+               Adj.connect("value_changed", self.intervalChanged)
+               Adj.set_value(self.interval)
+                               
+               Slider = gtk.HScale(adjustment=Adj)
+               self.dialog.vbox.add(Slider)
+                               
+                               # Manual reset
+                               
+               b5 = gtk.Button(label="Manually reset notification")           
+                b5.connect("clicked", self.resetNotification)                  
+               self.dialog.vbox.add(b5)
+               
+                               # Save Button
+               
+               bSave = gtk.Button(label="Save")
+               bSave.connect("clicked", self.saveSettings)
+               self.dialog.action_area.add(bSave)
+                               
+                               # Cancel Button
+                               
+               bCancel = gtk.Button(label="Cancel")
+               bCancel.connect("clicked", self.cancelDialog)
+               self.dialog.vbox.add(bCancel)
+               
+               self.dialog.show_all()
+
+    def intervalChanged(self, adj):
+               self.dbg('intervalChanged started')
+               self.interval = adj.value
+
+    def saveSettings(self, widget, data=None):
+               self.dbg('saveSettings started')
+               self.saveConfigurationFile()
+       
+    def dialogClosed(self, dialog, response_id):
+               self.dbg('dialogClosed started')
+       
+    def cancelDialog(self, widget, data=None):
+               self.dbg('cancelDialog started')
+               self.dialog.destroy()
+       
+    def resetNotification(self, widget, data=None):
+               self.dbg('resetNotification started')
+               self.stop_notification(self)
+
+    def soundActivate(self, widget, data=None):
+               self.dbg('soundActivate started')
+               self.sound = widget.get_active() #not(self.sound)
+       
+    def notificationActivate(self,widget, data=None):
+               self.dbg('notificationActivate started')
+               self.visual = widget.get_active() #not(self.visual)
+
+    def vibrateActivate(self, widget, data=None):
+               self.dbg('vibrateActivate started')
+               self.vibration = widget.get_active() #not(self.vibrate)
+
+       
+    def playSound(self):
+               self.dbg('playSound started')
+               if self.sound:
+                       hildon.hildon_play_system_sound(self.soundFile)
+                       #pygame.time.delay(1000)
+               if self.vibration:
+                       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\'"
+                       bb = str(bb)
+                       b = os.popen(bb)
+                       b.close()
+                       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\'" 
+                       b = os.popen(bb)
+                       b.close()
+               return True
+               
+       
+    def cleanup(self):
+               self.dbg('cleanup started')
+               gobject.source_remove(self.tmr_main)                  
+               gobject.source_remove(self.tmr_ptr)     
+               gobject.source_remove(self.tmr_ptr2)
+               
+               self.mainLoop.quit()
 
     def loadImages(self):
+               self.dbg('loadImages started')
                # Load phone image
                #self.pixbuf = gtk.gdk.pixbuf_new_from_file_at_size("/home/user/phone.png",18,18)
                icon_theme = gtk.icon_theme_get_default()
-               self.callPicture = icon_theme.load_icon("general_call", 18, gtk.ICON_LOOKUP_NO_SVG)
+               self.callPicture = gtk.gdk.pixbuf_new_from_file_at_size("/usr/share/CallNotify/call.png",18,18)
+               #icon_theme.load_icon("general_call", 18, gtk.ICON_LOOKUP_NO_SVG)
                self.smsPicture = gtk.gdk.pixbuf_new_from_file_at_size("/usr/share/CallNotify/sms.png",18,18)
                
                # Load 5 numbers and the "+5" 
@@ -47,31 +244,65 @@ class CallNotify(hildondesktop.StatusMenuItem):
                self.imgList.append(gtk.gdk.pixbuf_new_from_file_at_size("/usr/share/CallNotify/5.png",18,18))
                self.imgList.append(gtk.gdk.pixbuf_new_from_file_at_size("/usr/share/CallNotify/more.png",18,18))
                
+       # Screen off event-handler
+    def state_cb(self, state, a):
+               self.dbg('state_cb started')
+               if state == osso.device_state.OSSO_DISPLAY_OFF:
+                       try:
+                               #gobject.source_remove(self.tmr_main)
+                               self.tmrset = False
+                               #gobject.source_remove(self.tmr_ptr)
+                               
+                               #gobject.source_remove(self.tmr_ptr2)
+                       except:
+                               pass
+               elif state == osso.device_state.OSSO_DISPLAY_ON:
+                       if not tmrset:
+                               pass
+                               #self.tmr_main = gobject.timeout_add(5000, self.handleMissedCall)
+                       #self.handleMissedCall()
+               return False
+               
        # Method to define the way to add dbus signal receiver
+
+    def smsRead2(self, a):
+               self.dbg('smsrec started')
+               self.stop_notification(self)
+
     def startDbusListeners(self):
+               self.dbg('startDbusListeners started')
                DBusGMainLoop(set_as_default=True)                             
                 bus = dbus.SessionBus()                                        
                 #bus.add_signal_receiver(self.stop_notification, "NotificationClosed", "org.freedesktop.Notifications", "org.freedesktop.Notifications", "/org/freedesktop/Notifications") 
                #bus.add_signal_receiver(self.handleMissedCall, "Notify", None, None, None)
                #bus.add_signal_receiver(self.handleMissedCall, "MembersChanged", None, None, None)
-               bus.add_signal_receiver(self.smsReceived, "Received", "org.freedesktop.Telepathy.Channel.Type.Text", None, None)
+               bus.add_signal_receiver(self.smsReceived, "MessageReceived", None, None, None)
                bus.add_signal_receiver(self.smsRead, "NotificationClosed", "org.freedesktop.Notifications", None, "/org/freedesktop/Notifications")
-                gobject.MainLoop().run()                                       
+               bus.add_signal_receiver(self.smsRead2, "PendingMessagesRemoved", None, None, None)
+
+                self.mainLoop = gobject.MainLoop()
+               self.mainLoop.run()                                       
                return False
     
-    def smsReceived(self, a, b, c, d, e, f):
-       if self.missedLastSMS == self.getMissedCallsCount(True):
-               if self.msgType == "Call":
-                       self.msgType = "Both"
-               else:
-                       self.msgType = "SMS"
-               self.show()
-       self.missedLastSMS = self.getMissedCallsCount(True)
+    def smsReceived(self, a):
+               self.dbg('snsReceived started')
+               if a[0].has_key('message-type'):
+                       if self.missedLastSMS == self.getMissedCallsCount(True):
+                               if self.msgType == "Call":
+                                       self.msgType = "Both"
+                               else:
+                                       self.msgType = "SMS"
+                               self.show()
+                       self.missedLastSMS = self.getMissedCallsCount(True)
        
     def smsRead(self, a):
-       self.stop_notification(a)
+               self.dbg('smsRead started')
+               self.stop_notification(a)
        
     def handleMissedCall(self):        
+               self.dbg('handleMissedCall started')
+               #self.dbg('self.missedLastCall: ' + self.missedLastCall)
+               #self.dbg('self.getMissedCallsCount(False): ' + self.getMissedCallsCount(False))
                if self.missedLastCall != self.getMissedCallsCount(False):
                        if self.msgType == "SMS":
                                self.msgType = "Both"
@@ -82,18 +313,24 @@ class CallNotify(hildondesktop.StatusMenuItem):
                return True
        
     def stop_notification(self, a):
-               self.set_status_area_icon(None)
-               gobject.source_remove(self.tmr_ptr)
-               self.set_status_area_icon(None)
-               # Reset the notification (get recent missed call count)
-               self.missed = self.getMissedCallsCount(False)
-               self.missedSMS = self.getMissedCallsCount(True)
-               self.missedLastCall = self.missed
-               self.missedLastSMS = self.missedSMS
-               self.stop = False
-               self.msgType = ""
+               self.dbg('stop_notification started')
+               try:
+                       self.set_status_area_icon(None)
+                       # Reset the notification (get recent missed call count)
+                       self.missed = self.getMissedCallsCount(False)
+                       self.missedSMS = self.getMissedCallsCount(True)
+                       self.missedLastCall = self.missed
+                       self.missedLastSMS = self.missedSMS
+                       self.stop = False
+                       self.msgType = ""
+                       gobject.source_remove(self.tmr_ptr)
+                       gobject.source_remove(self.tmr_ptr2)
+               except:
+                       pass
+
 
     def theLoop(self):
+               self.dbg('theLoop started')
                missedCalls = self.getMissedCallsCount(False)
                if self.missedLastCall != missedCalls:
                        self.show()
@@ -101,21 +338,29 @@ class CallNotify(hildondesktop.StatusMenuItem):
                return True
 
     def getMissedCallsCount(self, isSms):
-               eType = 3
-               if isSms:
-                       eType=7
-               conn = sqlite3.connect(self.path)
-               cur = conn.cursor()
-               cur.execute("select count(id) from Events where event_type_id = " + str(eType))
+                self.dbg('getMissedCallsCount started. agrs: ' + str(isSms))
+                conn = sqlite3.connect(self.path)
+                cur = conn.cursor()
+                if isSms:
+                        #Nokia changed the event number from 7 to 11 and also combined the incomming and outgoing sms's
+                        cur.execute("select count(id) from Events where event_type_id = 7 and outgoing = 0")
+                else:
+                        #Nokia changed the event from 3 to 2
+                        cur.execute("select count(id) from Events where event_type_id = 3 and outgoing = 0")
                return cur.fetchone()[0]
 
     def show(self):
+               self.dbg('show started')
                # blink the icon every 1 second
                if not(self.stop):
-                       self.tmr_ptr = gobject.timeout_add(1000, self.blinkIcon)
+                       self.readConfigurationFile()
                        self.stop = True
+                       if self.visual:
+                               self.tmr_ptr = gobject.timeout_add(1000, self.blinkIcon)
+                       self.tmr_ptr2 = gobject.timeout_add(int(self.interval*1000*60), self.playSound)
                        
     def blinkIcon(self):
+               self.dbg('blinkIcon started')
                if self.toShow:
                        self.toShow = False
                        img = self.callPicture
@@ -133,13 +378,31 @@ class CallNotify(hildondesktop.StatusMenuItem):
                        index = self.getMissedCallsCount(isSMS) - counter - 1
                        if index >= 5:
                                index = 5
-                               if index < 0
+                               if index < 0:
                                        index = 0
                        if self.msgType != "Both":
                                img = self.imgList[index]
                        self.toShow = True
                        self.set_status_area_icon(img)
                        return True
+                       
+    def dbg(self, txt):
+                       if self.Debug:
+                               f = open(self.configDir+'log.txt', 'a')
+                               f.write(str(datetime.datetime.now()) + ': '+ txt)
+                               f.write('\n')
+
+                               f.close()
                
 hd_plugin_type = CallNotify
 
+
+# Uncomment from "if __name__..." to "gtk.main()" if running from CLI as:
+# "run-standalone.sh python CallNotify.py"
+
+#if __name__=="__main__":
+#              gobject.type_register(hd_plugin_type)
+#              obj = gobject.new(hd_plugin_type, plugin_id="plugid_id")
+#              obj.show_all()
+#              gtk.main()
+