-import gtk
+import gtk, gst
import gobject
import hildon, hildondesktop
import sqlite3
import atexit, os, datetime
from dbus.mainloop.glib import DBusGMainLoop
+WriteLog = False
+
+class Playbin2:
+ def __init__(self):
+ self.idle = True # not playing at the moment
+ self.configDir = "/home/user/.config/CallNotify/"
+ self.Debug = WriteLog
+ # create a playbin2 pipe
+ self.player = gst.element_factory_make("playbin2", "player")
+ # connect a signal handler to it's bus
+ bus = self.player.get_bus()
+ bus.add_signal_watch()
+ bus.connect("message", self.on_message)
+
+ def on_message(self, bus, message):
+ t = message.type
+ if t == gst.MESSAGE_EOS:
+ self.player.set_state(gst.STATE_NULL)
+ self.idle = True
+ self.dbg('Playbin2: EOS: STATE_NULL')
+ elif t == gst.MESSAGE_ERROR:
+ #err, debug = message.parse_error()
+ #print >> sys.stderr, "Error: {0} {1}".format(err, debug)
+ self.player.set_state(gst.STATE_NULL)
+ self.idle = True
+ self.dbg('Playbin2: ERROR: STATE_NULL')
+ return self.idle
+
+ def play(self, file, volume):
+ # abort previous play if still busy
+ if not self.idle:
+ #print >> sys.stderr, 'audio truncated'
+ self.player.set_state(gst.STATE_NULL)
+ self.player.set_property("uri", "file://" + file)
+ if volume > 0.0:
+ self.player.set_property("volume", min(volume, 1.0))
+ self.dbg('Volume:' + str(self.player.get_property("volume")))
+ self.player.set_state(gst.STATE_PLAYING)
+ self.idle = False # now playing
+
+ 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()
class CallNotify(hildondesktop.StatusMenuItem):
- def __init__(self):
+ def __init__(self):
hildondesktop.StatusMenuItem.__init__(self)
# Set members
self.configDir = "/home/user/.config/CallNotify/"
self.configFile = "conf.txt"
- self.Debug = False
+ self.configSoundFile = "sound.txt"
+ self.Debug = WriteLog
self.dbg("debugging started")
- self.readConfigurationFile()
- self.msgType = ""
+ self.msgType = ""
self.toShow = True
self.stop = False
- self.path = "/home/user/.rtcom-eventlogger/el.db"
- self.missed = self.getMissedCallsCount(False)
- self.missedSMS = self.getMissedCallsCount(True)
- self.missedLastCall = self.missed
- self.missedLastSMS = self.missedSMS
- self.mainLoop = None
+ self.path = "/home/user/.config/hildon-desktop/notifications.db"
+ self.mainLoop = None
self.soundFile = "/usr/share/CallNotify/missed.wav"
+ self.soundCall = self.soundFile
+ self.soundSMS = self.soundFile
+ self.soundBoth = self.soundFile
+ self.volume = 0.5
+ self.visual = True
+ self.sound = True
+ self.vibration = True
+ self.interval = float(5.0)
+ self.readConfigurationFile()
+
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):
+
+ def checkForConfigFile(self):
self.dbg('checkForConfigFile started')
os.umask(0)
if not os.path.exists(self.configDir):
- os.mkdir(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()
+ a = open(self.configDir+self.configFile,'w+')
+ a.write('y;y;y;5.0\n')
+ a.close()
+ if not os.path.exists(self.configDir+self.configSoundFile):
+ a = open(self.configDir+self.configSoundFile,'w+')
+ a.write('\n')
+ a.close()
# set proper permissions
- os.system("chmod 766 " + self.configDir)
- os.system("chmod 766" + self.configDir+self.configFile)
+ os.system("chmod 755 " + self.configDir)
+ os.system("chmod 644 " + self.configDir+self.configFile)
+ os.system("chmod 644 " + self.configDir+self.configSoundFile)
+
-
- def readConfigurationFile(self):
+ def readConfigurationFile(self):
try:
self.dbg('readConfigurationFile started')
self.checkForConfigFile()
self.sound = raw_set[1] in ('y')
self.vibration = raw_set[2] in ('y')
self.interval = float(raw_set[3].replace(',','.'))
+ self.dbg('visual='+str(self.visual)+' sound='+str(self.sound)+' vibration='+str(self.vibration)+' interval='+str(self.interval))
+ f.close()
+
+ # read sound config file
+ f = open(self.configDir+self.configSoundFile, 'r')
+ line = f.readline()
+ # check if specific missed call, SMS or common sound was defined in config file
+ if line.strip():
+ self.soundCall = line.strip()
+ self.dbg('soundCall changed to: '+self.soundCall)
+ line = f.readline()
+ if line.strip():
+ self.soundSMS = line.rstrip()
+ self.dbg('soundSMS changed to: '+self.soundSMS)
+ line = f.readline()
+ if line.strip():
+ self.soundBoth = line.strip()
+ self.dbg('soundBoth changed to: '+self.soundBoth)
+ line = f.readline()
+ if line.strip():
+ self.volume = float(line.strip())
+ self.dbg('volume changed to: '+self.volume)
f.close()
except:
os.remove(self.configDir+self.configFile)
+ os.remove(self.configDir+self.configSoundFile)
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):
+ 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()
+ profiled = dbus.Interface(dbus.SessionBus().get_object("com.nokia.profiled", "/com/nokia/profiled"), "com.nokia.profiled")
+ mce = dbus.Interface(dbus.SystemBus().get_object("com.nokia.mce", "/com/nokia/mce/request"), "com.nokia.mce.request")
+ if self.sound and profiled.get_value("", "ringing.alert.type") != "silent":
+ # Create the player_name sink
+ if self.msgType == "Call" and profiled.get_value("", "ringing.alert.volume") != "0":
+ self.dbg('play soundCall:' + self.soundCall)
+ Playbin2().play(self.soundCall, self.volume)
+ elif self.msgType == "SMS" and profiled.get_value("", "sms.alert.volume") != "0":
+ self.dbg('play soundSMS:' + self.soundSMS)
+ Playbin2().play(self.soundSMS, self.volume)
+ elif self.msgType == "Both":
+ self.dbg('play soundBoth:' + self.soundBoth)
+ Playbin2().play(self.soundBoth, self.volume)
+ else:
+ Playbin2().play(self.soundFile, self.volume)
+
+ if self.vibration and profiled.get_value("", "vibrating.alert.enabled") == "On":
+ self.dbg('vibrate:')
+ mce.req_vibrator_pattern_activate("PatternIncomingCall")
+ time.sleep(0.5);
+ mce.req_vibrator_pattern_deactivate("PatternIncomingCall")
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):
+
+ 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 = 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"
+
+ # Load 5 numbers and the "+5"
self.imgList = []
- #self.imgList.append(gtk.gdk.pixbuf_new_from_file_at_size("/home/user/1.png",18,18))
self.imgList.append(gtk.gdk.pixbuf_new_from_file_at_size("/usr/share/CallNotify/1.png",18,18))
self.imgList.append(gtk.gdk.pixbuf_new_from_file_at_size("/usr/share/CallNotify/2.png",18,18))
self.imgList.append(gtk.gdk.pixbuf_new_from_file_at_size("/usr/share/CallNotify/3.png",18,18))
self.imgList.append(gtk.gdk.pixbuf_new_from_file_at_size("/usr/share/CallNotify/4.png",18,18))
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):
+ 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, "MessageReceived", None, None, None)
- bus.add_signal_receiver(self.smsRead, "NotificationClosed", "org.freedesktop.Notifications", None, "/org/freedesktop/Notifications")
- bus.add_signal_receiver(self.smsRead2, "PendingMessagesRemoved", None, None, None)
-
- self.mainLoop = gobject.MainLoop()
- self.mainLoop.run()
+ DBusGMainLoop(set_as_default=True)
+ bus = dbus.SessionBus()
+
+ bus.add_signal_receiver(self.notificationClosed, "NotificationClosed", "org.freedesktop.Notifications", None, "/org/freedesktop/Notifications")
+ bus.add_signal_receiver(self.pendingMessagesRemoved, "PendingMessagesRemoved", None, None, None)
+ bus.add_signal_receiver(self.newEvent, "NewEvent", None, None, None)
+
+ self.mainLoop = gobject.MainLoop()
+ self.mainLoop.run()
return False
-
- 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.dbg('smsRead started')
+
+ def newEvent(self, a, b, c, d, e, f):
+ self.dbg('newEvent started')
+ # On NewEvent the notifications.db is not immediately filled, thus check the event after one minute waiting
+ self.tmr_main = gobject.timeout_add(20000, self.handleMissed)
+ return True
+
+ def notificationClosed(self, a):
+ self.dbg('notificationClosed started')
self.stop_notification(a)
-
- def handleMissedCall(self):
- self.dbg('handleMissedCall started')
- if self.missedLastCall != self.getMissedCallsCount(False):
- if self.msgType == "SMS":
- self.msgType = "Both"
- else:
- self.msgType = "Call"
+
+ def pendingMessagesRemoved(self, a):
+ self.dbg('pendingMessagesRemoved started')
+ self.stop_notification(self)
+
+ def handleMissed(self):
+ missedCall = self.getMissedCallsCount(False)
+ missedSMS = self.getMissedCallsCount(True)
+ self.dbg('Missed CALL: ' + str(missedCall))
+ self.dbg('Missed SMS: ' + str(missedSMS))
+
+ if missedCall and missedSMS:
+ self.msgType = "Both"
+ self.dbg('***********handleMissed BOTH started***********: ' + str(missedCall) + str(missedSMS))
+ elif missedCall and not missedSMS:
+ self.msgType = "Call"
+ self.dbg('***********handleMissed CALL started***********: ' + str(missedCall))
+ elif missedSMS and not missedCall:
+ self.msgType = "SMS"
+ self.dbg('***********handleMissed SMS started***********: ' + str(missedSMS))
+
+ if missedCall or missedSMS:
self.show()
- self.missedLastCall = self.getMissedCallsCount(False)
- return True
-
- def stop_notification(self, a):
+
+ # Execute the function only once on NewEvent
+ return False
+
+ def stop_notification(self, a):
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)
+ gobject.source_remove(self.tmr_main)
except:
pass
-
- def theLoop(self):
- self.dbg('theLoop started')
- missedCalls = self.getMissedCallsCount(False)
- if self.missedLastCall != missedCalls:
- self.show()
- self.missedLastCall = missedCalls
- return True
-
- def getMissedCallsCount(self, isSms):
- self.dbg('getMissedCallsCount started. agrs: ' + str(isSms))
- eType = 3
- if isSms:
- eType=7
+ def getMissedCallsCount(self, isSms):
conn = sqlite3.connect(self.path)
cur = conn.cursor()
- cur.execute("select count(id) from Events where event_type_id = " + str(eType))
- return cur.fetchone()[0]
+ if isSms:
+ cur.execute("select count(id) from notifications where icon_name='general_sms'")
+ else:
+ cur.execute("select count(id) from notifications where icon_name='general_missed'")
+ missed = cur.fetchone()[0]
+
+ #if isSms:
+ #self.dbg('get missed SMSs: ' + str(missed))
+ #else:
+ #self.dbg('get missed Calls: ' + str(missed))
- def show(self):
+ return missed
+
+ def show(self):
self.dbg('show started')
# blink the icon every 1 second
if not(self.stop):
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')
+
+ def blinkIcon(self):
+ # self.dbg('blinkIcon started')
if self.toShow:
self.toShow = False
img = self.callPicture
else:
img = self.smsPicture
isSMS = False
- counter = self.missed
if self.msgType == "SMS":
- counter = self.missedSMS
isSMS = True
- index = self.getMissedCallsCount(isSMS) - counter - 1
+ index = self.getMissedCallsCount(isSMS) - 1
if index >= 5:
index = 5
- if index < 0:
- 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):
+
+ 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
# gobject.type_register(hd_plugin_type)
# obj = gobject.new(hd_plugin_type, plugin_id="plugid_id")
# obj.show_all()
-# gtk.main()
+# gtk.main()