--- /dev/null
+import os,time
+
+if os.path.exists("/tmp/switch.debug"):
+if True:
+ enable_logging = True
+else:
+ enable_logging = False
+
+if enable_logging and not 'fd' in locals():
+ fd = open('/tmp/switch.log','w+')
+else:
+ fd = None
+
+def debug(*input):
+ if enable_logging:
+ now = str(time.time())
+ print now+str(input)
+ print >>fd,now+str(input)
+ fd.flush()
+
--- /dev/null
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published
+## by the Free Software Foundation; version 2 only.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+import pypackager
+import os
+
+if __name__ == "__main__":
+ try:
+ os.chdir(os.path.dirname(sys.argv[0]))
+ except:
+ pass
+
+ p=pypackager.PyPackager("profile-appointments")
+ p.version='0.0.1'
+ p.buildversion='1'
+ p.display_name='profile-appointments'
+ p.description="widget to switch profile to silent when a meeting is in progress , and switch back to general afterward"
+ p.author="Niv Waizer"
+ p.maintainer="Niv Waizer"
+ p.email="nivwiz@gmail.com"
+ p.depends = "python-hildon (>= 0.9.0-1maemo15), python-hildondesktop (>= 0.1.0-1maemo3), python-gtk2 (>= 2.12.1-6maemo10), python-gobject (>= 2.16), hildon-desktop-python-loader (>= 0.1.0-1maemo3), python-dbus, sudo, python, python-support (>= 0.90.0), python2.5, python-dbus, python-mafw"
+ p.section="user/development"
+ p.arch="all"
+ p.urgency="extra"
+ p.bugtracker='http://unknown'
+ p.distribution="fremantle"
+ p.repository="extras-devel"
+ p.icon='profile-appointments.png'
+ p["/etc/init.d"] = ["switch_backend",]
+ p["/usr/lib/hildon-desktop"] = ["profile-appointments.py",]
+ p["/usr/lib/switchProfByMeeting"] = ["debug.py", "switch_backend.py",]
+ p["/usr/share/icons/hicolor/32x32/hildon"] = ["profile-appointments.png",]
+ p["/etc/sudoers.d"] = ["profile-appointments.sudoers",]
+ p["/usr/share/applications/hildon-status-menu"] = ["profile-appointments.desktop",]
+
+ p.postinstall = """#!/bin/sh
+update-sudoers || true
+
+gtk-update-icon-cache /usr/share/icons/hicolor/
+
+#chmod 755".join(p['/usr/...']
+for file in /etc/init.d/switch_backend /usr/lib/switchProfByMeeting/switch_backend.py ; do
+chmod 755 $file
+done
+for file in /usr/share/applications/hildon-status-menu/profile-appointments.desktop /usr/lib/hildon-desktop/profile-appointments.py ; do
+chmod 644 $file
+chown root:root $file
+done
+#Force applet reloading to get the icon
+ echo "Reloading switchByProfile"
+ TMPFILE=`mktemp /tmp/temp.XXXXXX`
+ mv /usr/share/applications/hildon-status-menu/profile-appointments.desktop $TMPFILE
+ sleep 2
+ mv $TMPFILE /usr/share/applications/hildon-status-menu/profile-appointments.desktop
+ rm -f $TMPFILE
+
+# Automatically added by dh_pysupport
+#if which update-python-modules >/dev/null 2>&1; then
+# update-python-modules openvpn-applet.private
+#fi
+exit 0
+"""
+
+ p.changelog="""First Release
+"""
+
+print p.generate(build_binary=True,build_src=True)
--- /dev/null
+[Desktop Entry]
+Name=switch profile by meeting
+#Comment=Example Status Menu Python plugin
+Type=python
+X-Path=profile-appointments.py
--- /dev/null
+#!/usr/bin/env python
+
+import hildon, gtk
+import hildondesktop
+import commands
+
+class ExampleStatusPlugin(hildondesktop.StatusMenuItem):
+ def __init__(self):
+ hildondesktop.StatusMenuItem.__init__(self)
+
+ self.backend_started = self.status_backend()
+
+ self.button_title_text = "profile-appointments"
+ self.button = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
+ self.button.set_style(hildon.BUTTON_STYLE_PICKER)
+ self.button.set_alignment(0.2,0.5,1,1)
+ image = gtk.image_new_from_icon_name("profile-appointments", gtk.ICON_SIZE_BUTTON)
+ self.button.set_image(image)
+ self.button.set_image_position(gtk.POS_LEFT)
+ self.button.connect("clicked", self.button_clicked_event)
+
+ icon_theme = gtk.icon_theme_get_default()
+ self.pixbuf = icon_theme.load_icon("profile-appointments", 22, gtk.ICON_LOOKUP_NO_SVG)
+
+ self.add(self.button)
+ self.show_all()
+ self.update_button()
+
+ def status_backend(self):
+ """is backend running?"""
+ return commands.getoutput('pgrep switch_backend')
+
+ def button_clicked_event(self,*args):
+ if self.backend_started:
+ self.stop_backend()
+ else:
+ self.start_backend()
+ self.update_button()
+
+ def update_button(self):
+ """Update the start/stop button to reflect current state"""
+ if self.backend_started:
+ self.button.set_text(self.button_title_text,'Stop')
+ self.set_status_area_icon(self.pixbuf)
+ else:
+ self.button.set_text(self.button_title_text,'Start')
+ self.set_status_area_icon(None)
+
+ def start_backend(self):
+ """calls backend start"""
+ (exitstatus, outtext) = commands.getstatusoutput("""/etc/init.d/switch_backend start""")
+ if exitstatus <> 0:
+ print "DEBUG: backend start exit code " + str(status) + ", output: \n"
+ note = hildon.hildon_note_new_information(self.mainwindow, 'profile-appointments failed to start')
+ response = gtk.Dialog.run(note)
+ note.destroy()
+ return
+ self.backend_started = True
+
+ def stop_backend(self):
+ """kills backend"""
+ (exitstatus, outtext) = commands.getstatusoutput("""/etc/init.d/switch_backend stop""")
+ if exitstatus <> 0:
+ print "DEBUG: backend start exit code " + str(status) + ", output: \n"
+ note = hildon.hildon_note_new_information(self.mainwindow, 'profile-appointments failed to start')
+ response = gtk.Dialog.run(note)
+ note.destroy()
+ return
+ self.backend_started = False
+
+hd_plugin_type = ExampleStatusPlugin
--- /dev/null
+user ALL = NOPASSWD: /etc/init.d/switch_backend
--- /dev/null
+Maintainer: Niv Waizer <nivwiz@gmail.com>
+Format: 1.7
+Source: profile-appointments
+Version: 0.0.1-1
+Architecture: all
+Date: Mon, 27 Jun 2011 04:33:49 +0000
+Distribution: fremantle
+Urgency: extra
+Description:
+ widget to switch profile to silent when a meeting is in progress , and switch back to general afterward
+Changes:
+ First Release
+
+Changed-By: Niv Waizer <nivwiz@gmail.com>
+Files:
+ 9da9e14fd9c6b4780bd0a7e9f60fc18a 10792 user/development extras-devel profile-appointments_0.0.1-1.tar.gz
+ 08ab4b189d654976ce09cc3334113ddd 520 user/development extras-devel profile-appointments_0.0.1-1.dsc
+
--- /dev/null
+Source: profile-appointments
+Version: 0.0.1-1
+Maintainer: Niv Waizer <nivwiz@gmail.com>
+Architecture: all
+Format: 1.0
+Build-Depends: python-hildon (>= 0.9.0-1maemo15), python-hildondesktop (>= 0.1.0-1maemo3), python-gtk2 (>= 2.12.1-6maemo10), python-gobject (>= 2.16), hildon-desktop-python-loader (>= 0.1.0-1maemo3), python-dbus, sudo, python, python-support (>= 0.90.0), python2.5, python-dbus, python-mafw
+Standards-Version: 0.0.1-1
+Files:
+ 9da9e14fd9c6b4780bd0a7e9f60fc18a 10792 profile-appointments_0.0.1-1.tar.gz
+
--- /dev/null
+#!/bin/sh
+#
+#set -x
+prefix=/usr/lib/switchProfByMeeting
+PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/bin/X11:$prefix
+#exec_prefix=${prefix}
+#sbindir=${exec_prefix}/sbin
+NAME=switch_backend
+DAEMON=${prefix}/switch_backend.py
+USER=user
+DESC="switch profile by meeting"
+unset USE_UPSTART
+#INITCTL=/sbin/initctl
+ACTION=$1
+test -x $DAEMON || exit 0
+
+kill_deamon()
+{
+ps ax |grep $NAME |grep -v grep|grep -v init|awk '{print $1}'|while read pid
+do kill $pid
+done
+}
+
+case "$ACTION" in
+ start)
+ echo "before"
+ kill_deamon
+ echo "after"
+ echo -n "Starting $DESC: "
+ start-stop-daemon --start --quiet -c $USER \
+ --background --exec "$DAEMON"
+ if test $? == 0
+ then
+ echo "$NAME"
+ fi
+ ;;
+ stop)
+ echo -n "Stopping $DESC: "
+ start-stop-daemon --stop --quiet --oknodo --user $USER \
+ --exec "$DAEMON"
+ if test $? == 0
+ then
+ echo "$NAME"
+ fi
+ kill_deamon
+ ;;
+ reload|restart|force-reload)
+ #
+ # If the "reload" option is implemented, move the "force-reload"
+ # option to the "reload" entry above. If not, "force-reload" is
+ # just the same as "restart".
+ #
+ "$0" stop
+ "$0" start
+ ;;
+ *)
+ N=/etc/init.d/$NAME
+ echo "Usage: $N {start|stop|restart|force-reload}" >&2
+ exit 1
+ ;;
+esac
+
+exit 0
--- /dev/null
+#!/usr/bin/run-standalone.sh python2.5
+
+# Import global modules
+import sys, traceback, gobject, dbus, dbus.mainloop.glib ,os , subprocess
+import time, sqlite3,mafw
+sys.path.insert(0, '/usr/lib/switchProfByMeeting')
+import debug
+debug = debug.debug
+
+sys.path.insert(0, '/home/user')
+dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+class backend:
+ def __init__( self ):
+ #debug( 'init' )
+ self.bus = dbus.SessionBus()
+ self.sleep_duration = 10000
+ self.timeout_id = None
+ self.loop = None
+
+ try:
+ self.profiled_object = self.bus.get_object( 'com.nokia.profiled', '/com/nokia/profiled' )
+ self.calender_object = self.bus.get_object( 'com.nokia.calendar', '/com/nokia/calendar' )
+ self.calender_object.connect_to_signal( 'dbChange', \
+ self.calender_changed, dbus_interface = 'com.nokia.calendar' )
+ self.mafw_object = self.bus.get_object( \
+ 'com.nokia.mafw.renderer.Mafw-Gst-Renderer-Plugin.gstrenderer' \
+ ,'/com/nokia/mafw/renderer/gstrenderer' )
+ except dbus.DBusException:
+ traceback.print_exc()
+ sys.exit(1)
+
+ self.start()
+
+ def set_profile( self, prof ):
+ debug ('in set_profile with '+prof)
+ #save speaker volume as profile change effects it
+ volume_level = self.mafw_object.get_extension_property( 'volume' \
+ , dbus_interface = 'com.nokia.mafw.extension')[1]
+ self.profiled_object.set_profile(prof, dbus_interface='com.nokia.profiled')
+ #restore volume level due to profile change
+ retcode = subprocess.call("dbus-send --type=method_call \
+ --dest=com.nokia.mafw.renderer.Mafw-Gst-Renderer-Plugin.gstrenderer \
+ /com/nokia/mafw/renderer/gstrenderer \
+ com.nokia.mafw.extension.set_extension_property \
+ string:volume variant:uint32:%d"%volume_level, shell=True)
+ if retcode != 0:
+ raise SystemExit('got error code '+str(retcode)+' when setting volume')
+
+ def is_meeting_now( self ):
+ cal_db = sqlite3.connect(os.path.expanduser("~/.calendar/calendardb"))
+ query = "SELECT Summary FROM Components WHERE ComponentType='1' \
+ AND AllDay='0' AND strftime('%s','now') >= DateStart AND \
+ strftime('%s','now') < DateEnd limit 1"
+ ans = cal_db.execute(query).fetchone()
+ debug( 'is_meeting_now returns: '+str(ans) )
+ return ans
+
+ def when_next_meeting( self ):
+ cal_db = sqlite3.connect(os.path.expanduser("~/.calendar/calendardb"))
+ query = "SELECT DateStart FROM Components WHERE ComponentType='1' \
+ and AllDay='0' and strftime('%s','now') < DateStart AND \
+ DateStart < DateEnd ORDER BY DateStart limit 1"
+ #here is the place to make sure the meeting is leagal non zero duration and event
+ ans = cal_db.execute(query).fetchone()
+ if ans != None:
+ next_timeout = ans [0]
+ else:
+ next_timeout = None
+ debug( 'when_next_meeting returns: '+str(next_timeout) )
+ return next_timeout
+
+ def when_end_of_meeting( self ):
+ cal_db = sqlite3.connect(os.path.expanduser("~/.calendar/calendardb"))
+ query = "SELECT DateEnd FROM Components WHERE ComponentType='1' \
+ and AllDay='0' and strftime('%s','now') < DateEnd and \
+ DateStart < DateEnd ORDER BY DateEnd limit 1"
+ #I also need to adress overlapping meetings that the other finishes later
+ next_timeout = cal_db.execute(query).fetchone() [0]
+ debug( 'when_end_of_meeting returns: ' +str(next_timeout) )
+ return next_timeout
+
+ def calc_next_duration( self, next_meeting_time ):
+ if next_meeting_time != None:
+ self.sleep_duration = int ((next_meeting_time - time.time())*1000)
+ else:
+ self.sleep_duration = 5000
+ debug("calc_next_duration returns: "+str(self.sleep_duration))
+
+ def set_timer( self, current_profile ):
+ if current_profile == 'general' :
+ self.calc_next_duration( self.when_next_meeting() )
+ else :
+ self.calc_next_duration( self.when_end_of_meeting() )
+
+ def calender_changed( self, arg1 , arg2 ):
+ debug('calender_changed called with arg1: '+arg1+' arg2: '+arg2 )
+ self.remove_timeout()
+ self.update_profile()
+ self.mainloop()
+ debug ('end of calender_changed')
+
+ def timer_callback( self ):
+ debug('timer_callback timeout_id: '+str(self.timeout_id))
+ self.remove_timeout()
+ self.update_profile()
+ self.mainloop()
+ #commented by merlin 1991 advice self.mainloop()
+ debug('end of timer_callback')
+
+ def remove_timeout( self ):
+ debug ( 'remove timeout called' )
+ if self.timeout_id != None:
+ gobject.source_remove(self.timeout_id)
+ debug( 'removed timeout: '+str(self.timeout_id) )
+
+ def update_profile( self ):
+ debug ( 'begining of update_profile' )
+ if self.is_meeting_now() :
+ self.set_profile( 'silent' )
+ self.set_timer( 'silent' )
+ else:
+ self.set_profile( 'general' )
+ self.set_timer( 'general' )
+
+ def mainloop( self ):
+ debug('going to run loop with sleep_duration: '+str(self.sleep_duration))
+ self.timeout_id = gobject.timeout_add(self.sleep_duration, self.timer_callback )
+ debug( ' new timeou_id is: '+str(self.timeout_id) )
+
+ if self.loop == None :
+ self.loop = gobject.MainLoop()
+ self.loop.run()
+ debug('new loop started')
+ debug ('end of mainloop')
+
+ def start ( self ):
+ ''' update the profile and set a timer loop'''
+ debug( 'starting' )
+ self.update_profile()
+ self.mainloop()
+
+ def stop_mainloop( self ):
+ ''' stop nain loop'''
+ debug( 'stopping main loop' )
+ if self.loop != None and self.loop.is_running():
+ self.loop.quit()
+
+ def status( self ):
+ '''check the status of the switch backend'''
+ if self.loop != None:
+ status = self.loop.is_running()
+ else:
+ status = None
+ debug( 'status is: '+status)
+ return status
+
+if __name__ == "__main__":
+ backend = backend()