X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=src%2Fusr%2Flib%2Fhildon-desktop%2FCallNotify.py;h=6f81c18aba30f382f52aafb2e299ca6af99adc77;hb=77c080ef748f67f229486ffdf9c5736823409686;hp=4fda0abcedd63b0030367df00ae03341adff2b2a;hpb=44187736acfee84c0b291e11b1d07717e852a389;p=callnotify diff --git a/src/usr/lib/hildon-desktop/CallNotify.py b/src/usr/lib/hildon-desktop/CallNotify.py old mode 100755 new mode 100644 index 4fda0ab..6f81c18 --- a/src/usr/lib/hildon-desktop/CallNotify.py +++ b/src/usr/lib/hildon-desktop/CallNotify.py @@ -1,4 +1,4 @@ -import gtk +import gtk, gst import gobject import hildon, hildondesktop import sqlite3 @@ -8,195 +8,160 @@ import osso 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.Debug = False self.configDir = "/home/user/.config/CallNotify/" self.configFile = "conf.txt" - self.readConfigurationFile() - self.msgType = "" + self.configSoundFile = "sound.txt" + self.Debug = WriteLog + self.dbg("debugging started") + 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.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() + if self.Debug: + hildon.hildon_play_system_sound(self.soundFile) 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') - a.close() - - - def readConfigurationFile(self): - 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]) - f.close() - - 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) + 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 766" + self.configDir+self.configSoundFile) - def vibrateActivate(self, widget, data=None): - self.dbg('vibrateActivate started') - self.vibration = widget.get_active() #not(self.vibrate) + 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() + + # 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: + self.soundCall = line.rstrip() + line = f.readline() + if line: + self.soundSMS = line.rstrip() + line = f.readline() + if line: + self.soundBoth = line.rstrip() + line = f.readline() + if line: + self.volume = float(line.rstrip()) + f.close() + except: + os.remove(self.configDir+self.configFile) + os.remove(self.configDir+self.configSoundFile) + self.checkForConfigFile() - def playSound(self): + def playSound(self): self.dbg('playSound started') if self.sound: - hildon.hildon_play_system_sound(self.soundFile) - #pygame.time.delay(1000) + # Create the player_name sink + if self.msgType == "Call": + self.dbg('play soundCall:' + self.soundCall) + Playbin2().play(self.soundCall, self.volume) + elif self.msgType == "SMS": + 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: 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) @@ -207,27 +172,14 @@ class CallNotify(hildondesktop.StatusMenuItem): 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): + 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" 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)) @@ -235,108 +187,85 @@ 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): + 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) + DBusGMainLoop(set_as_default=True) + bus = dbus.SessionBus() - self.mainLoop = gobject.MainLoop() - self.mainLoop.run() + 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(60000, 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] - def show(self): + #if isSms: + #self.dbg('get missed SMSs: ' + str(missed)) + #else: + #self.dbg('get missed Calls: ' + str(missed)) + + return missed + + def show(self): self.dbg('show started') # blink the icon every 1 second if not(self.stop): @@ -346,8 +275,8 @@ class CallNotify(hildondesktop.StatusMenuItem): 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 @@ -358,22 +287,20 @@ class CallNotify(hildondesktop.StatusMenuItem): 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) @@ -383,3 +310,13 @@ class CallNotify(hildondesktop.StatusMenuItem): 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() +