2 # -*- coding: utf-8 -*-
4 # Copyright (C) 2008,2009
5 # Pietro Montorfano <monto@telefoninux.org>
6 # Marco Trevisan (TreviƱo) <mail@3v1n0.net>
8 # This program is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU General Public License
10 # as published by the Free Software Foundation; either version 3
11 # of the License, or (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
29 TITLE = "SHR Notifier"
31 LOCK_FILE = "/var/lock/shr-notifier"
33 DIALER_ICON = "/usr/share/icons/shr/86x86/apps/openmoko-dialer.png"
34 MESSAGES_ICON = "/usr/share/icons/shr/86x86/apps/openmoko-messages.png"
35 NOTIFY_SOUND = "/usr/share/sounds/purple/alert.wav"
37 MISSED_CALLS_PROGRAM = "/usr/bin/phonelog"
38 #MISSED_CALLS_PROGRAM = "/usr/bin/elmphonelog"
39 MISSED_SMS_PROGRAM = "/usr/bin/phoneui-messages"
41 ATD_PROGRAM = "/usr/sbin/atd"
42 ATSPOOL_DIR = "/var/spool/at"
43 ATD_TRIGGER = "/var/spool/at/trigger"
45 LCD_BACKLIGHT_SYSFILE = "/sys/class/backlight/gta02-bl/bl_power"
46 RESUME_REASON_SYSFILE = "/sys/class/i2c-adapter/i2c-0/0-0073/resume_reason"
47 RTC_TIME_SYSFILE = "/sys/class/rtc/rtc0/since_epoch"
49 SMS_1 = " unread message"
50 SMS_2 = " unread messages"
51 CALL_1 = " missed call"
52 CALL_2 = " missed calls"
54 USAGE_BUSNAME = 'org.freesmartphone.ousaged'
55 USAGE_OBJECTPATH = '/org/freesmartphone/Usage'
56 USAGE_INTERFACE = 'org.freesmartphone.Usage'
58 GSM_BUSNAME = 'org.freesmartphone.ogsmd'
59 GSM_OBJECTPATH = '/org/freesmartphone/GSM/Device'
60 GSM_SIM_INTERFACE = 'org.freesmartphone.GSM.SIM'
61 GSM_CALL_INTERFACE = 'org.freesmartphone.GSM.Call'
63 PREFERENCES_BUSNAME = 'org.freesmartphone.opreferencesd'
64 PREFERENCES_OBJECTPATH = '/org/freesmartphone/Preferences/phone'
65 PREFERENCES_INTERFACE = 'org.freesmartphone.Preferences.Service'
67 DEVICE_BUSNAME = 'org.freesmartphone.odeviced'
68 AUDIO_OBJECTPATH = '/org/freesmartphone/Device/Audio'
69 AUDIO_INTERFACE = 'org.freesmartphone.Device.Audio'
70 VIBRATOR_OBJECTPATH = '/org/freesmartphone/Device/Vibrator/0'
71 VIBRATOR_INTERFACE = 'org.freesmartphone.Device.Vibrator'
72 RTC_OBJECTPATH = '/org/freesmartphone/Device/RTC/0'
73 RTC_INTERFACE = 'org.freesmartphone.Device.RealtimeClock'
76 SECONDS_FOR_NOTIFY = 120
77 MINUTES_FOR_WAKEUP = 15
81 gsm_message_iface = None
99 ATD_NOTIFY_SCRIPT = r'''#!/bin/sh
100 # SHR-notifier check #
101 # File automatically genrated by shr-notifier, don't edit!
105 resume_reason="$(cat %(RESUME_REASON)s)"
106 nextwakeup=$(($(cat %(TIME_FILE)s) + %(INTERVAL)d*60))
108 mv "x$0.$$" "$(dirname "$0")/${nextwakeup}.$(basename "$0" | sed "s/^[0-9]\+[^.]\.//")"
109 echo -e "\n" > %(TRIGGER)s
111 if [ "$resume_reason" = "4000000000" ]; then
112 #echo 1 > %(LCD_BACKLIGHT)s
114 volume="$(expr "$(dbus-send --print-reply --type=method_call --system --dest=%(OPREFERENCESD)s %(PHONE_PATH)s org.freesmartphone.Preferences.Service.GetValue string:"message-volume")" : ".* \(.*\)$")"
116 vibration="$(expr "$(dbus-send --print-reply --type=method_call --system --dest=%(OPREFERENCESD)s %(PHONE_PATH)s org.freesmartphone.Preferences.Service.GetValue string:"ring-vibration")" : ".* \(.*\)$")"
118 if [ -z "$volume" ]; then
122 if [ $volume -gt 0 ]; then
123 dbus-send --type=method_call --print-reply --system --dest=%(ODEVICED)s %(AUDIO_PATH)s org.freesmartphone.Device.Audio.PlaySound string:"%(SOUND)s" int32:0 int32:0
126 if [ "$vibration" = "true" ]; then
127 dbus-send --type=method_call --print-reply --system --dest=%(ODEVICED)s %(VIBRATOR_PATH)s org.freesmartphone.Device.Vibrator.VibratePattern int32:2 int32:150 int32:50 int32:100
130 dbus-send --type=method_call --print-reply --system --dest=%(OUSAGED)s %(USAGE_PATH)s org.freesmartphone.Usage.Suspend || apm -s
132 #echo 0 > %(LCD_BACKLIGHT)s
136 ### ATD Notifier (Notify when the phone is suspended)
137 def atd_trigger_update():
138 if not os.path.exists(ATD_TRIGGER):
141 f = file(ATD_TRIGGER, 'a')
145 def atd_notify_init():
148 if not os.path.exists(ATD_TRIGGER) or not os.path.exists(ATD_PROGRAM):
151 notifytime = rtc_iface.GetCurrentTime() + (MINUTES_FOR_WAKEUP * 60)
153 atfile = os.path.join(ATSPOOL_DIR, '%d.shr-notifier.%d' % (notifytime, os.getpid()))
154 f = file(atfile, 'w')
155 f.write(ATD_NOTIFY_SCRIPT % dict(TIME_FILE=RTC_TIME_SYSFILE, INTERVAL=MINUTES_FOR_WAKEUP,
156 TRIGGER=ATD_TRIGGER, SOUND=NOTIFY_SOUND,
157 LCD_BACKLIGHT=LCD_BACKLIGHT_SYSFILE,
158 RESUME_REASON=RESUME_REASON_SYSFILE,
159 OPREFERENCESD=PREFERENCES_BUSNAME, PHONE_PATH=PREFERENCES_OBJECTPATH,
160 ODEVICED=DEVICE_BUSNAME, AUDIO_PATH=AUDIO_OBJECTPATH,
161 VIBRATOR_PATH=VIBRATOR_OBJECTPATH, OUSAGED=USAGE_BUSNAME,
162 USAGE_PATH=USAGE_OBJECTPATH))
164 os.chmod(atfile, 0755)
168 def atd_notify_stop():
169 if not os.path.exists(ATSPOOL_DIR):
172 atd_notifier_found = False
173 for atspool in os.listdir(ATSPOOL_DIR):
174 if re.match('^[0-9]+[^.]\.shr-notifier\.[0-9]+$', atspool):
175 os.unlink(os.path.join(ATSPOOL_DIR, atspool))
176 atd_notifier_found = True
178 if atd_notifier_found:
181 ### Notify Timer (Vibration and Sound if enabled)
183 if pref_iface.GetValue("message-volume") > 0:
184 audio_iface.PlaySound(NOTIFY_SOUND, 0, 0)
186 if pref_iface.GetValue("ring-vibration"):
187 vibrator_iface.VibratePattern(2, 150, 50, 100)
191 def notify_timer_start():
194 if notify_timer != None:
195 notify_timer.delete()
197 notify_timer = ecore.timer_add(float(SECONDS_FOR_NOTIFY), notify)
199 def notify_timer_stop():
202 if notify_timer != None:
203 notify_timer.delete()
209 for (key, value) in missed_calls.iteritems():
210 lost_call_count += len(value)
212 if (lost_call_count == 1):
213 bt_calls.label_set(str(lost_call_count) + CALL_1)
215 elif (lost_call_count > 1):
216 bt_calls.label_set(str(lost_call_count) + CALL_2)
221 if (missed_sms == 1):
222 bt_sms.label_set(str(missed_sms) + SMS_1)
224 elif (missed_sms > 1):
225 bt_sms.label_set(str(missed_sms) + SMS_2)
230 if ((missed_sms == 0) and ((lost_call_count == 0) or (missed_calls == {}))):
239 ## here's the main function, using args so that it doesn't crash even if new parameters will be added
240 def call_signal_handler(sender = "", *args, **kwargs):
242 call_status = str(args[0])
243 if (args[1].has_key("peer")):
244 caller = str(args[1]["peer"])
247 if (call_status == "INCOMING"):
249 elif ((call_status == "ACTIVE") and (call_active != "")):
251 elif ((call_status == "RELEASE") and (call_active != "")):
252 if (missed_calls.has_key(call_active)):
253 missed_calls[call_active].append(time.time())
255 missed_calls[call_active] = [time.time()]
258 def sms_signal_handler(*args, **kwargs):
263 def sigterm_handler(signum, frame):
268 ## elementary standard signal
269 def destroy(obj = None, event = None, data = ""):
279 def show_missed_calls(*args, **kwargs):
283 os.system(MISSED_CALLS_PROGRAM + " &")
285 def show_missed_sms(*args, **kwargs):
289 os.system(MISSED_SMS_PROGRAM + " &")
291 if __name__ == "__main__":
293 lock = file(LOCK_FILE, 'w')
294 fcntl.lockf(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)
296 print TITLE + " is already running. Kill it!"
299 #signal.signal(signal.SIGTERM, sigterm_handler)
303 while (not initialized):
307 ### setting up the dbus and all the interfaces that we need
308 dbus_loop = e_dbus.DBusEcoreMainLoop()
310 system_bus = dbus.SystemBus(mainloop = dbus_loop)
311 gsm_bus = system_bus.get_object(GSM_BUSNAME, GSM_OBJECTPATH)
312 gsm_call_iface = dbus.Interface(gsm_bus, GSM_CALL_INTERFACE)
313 gsm_sim_iface = dbus.Interface(gsm_bus, GSM_SIM_INTERFACE)
315 pref_bus = system_bus.get_object(PREFERENCES_BUSNAME, PREFERENCES_OBJECTPATH)
316 pref_iface = dbus.Interface(pref_bus, PREFERENCES_INTERFACE)
318 audio_bus = system_bus.get_object(DEVICE_BUSNAME, AUDIO_OBJECTPATH)
319 audio_iface = dbus.Interface(audio_bus, AUDIO_INTERFACE)
321 vibrator_bus = system_bus.get_object(DEVICE_BUSNAME, VIBRATOR_OBJECTPATH)
322 vibrator_iface = dbus.Interface(vibrator_bus, VIBRATOR_INTERFACE)
324 rtc_bus = system_bus.get_object(DEVICE_BUSNAME, RTC_OBJECTPATH)
325 rtc_iface = dbus.Interface(rtc_bus, RTC_INTERFACE)
327 ### Actually we only need to listen for incoming calls
328 gsm_call_iface.connect_to_signal("CallStatus", call_signal_handler)
329 gsm_sim_iface.connect_to_signal("IncomingStoredMessage", sms_signal_handler)
333 time.sleep(SECONDS_FOR_RETRY)
337 ### Now that dbus it's ok lets build the UI
338 win = elementary.Window(TITLE, elementary.ELM_WIN_BASIC)
340 win.callback_destroy_add(destroy)
342 bg = elementary.Background(win)
343 win.resize_object_add(bg)
344 bg.size_hint_weight_set(0.0, 0.0)
345 bg.size_hint_align_set(-1.0, -1.0)
348 box_main = elementary.Box(win)
349 box_main.size_hint_weight_set(0.0, 0.0)
350 box_main.size_hint_align_set(-1.0, -1.0)
351 win.resize_object_add(box_main)
354 bt_calls = elementary.Button(win)
355 bt_calls.label_set(CALL_1)
356 bt_calls.size_hint_weight_set(0.0, 0.0)
357 bt_calls.size_hint_align_set(-1.0, -1.0)
358 bt_calls_icon = elementary.Icon(bt_calls)
359 bt_calls_icon.file_set(DIALER_ICON)
360 bt_calls_icon.size_hint_aspect_set(evas.EVAS_ASPECT_CONTROL_VERTICAL, 1, 1)
361 bt_calls.icon_set(bt_calls_icon)
362 box_main.pack_end(bt_calls)
363 bt_calls.callback_clicked_add(show_missed_calls)
366 bt_sms = elementary.Button(win)
367 bt_sms.label_set(SMS_1)
368 bt_sms.size_hint_weight_set(0.0, 0.0)
369 bt_sms.size_hint_align_set(-1.0, -1.0)
370 bt_sms_icon = elementary.Icon(bt_sms)
371 bt_sms_icon.file_set(MESSAGES_ICON)
372 bt_sms_icon.size_hint_aspect_set(evas.EVAS_ASPECT_CONTROL_VERTICAL, 1, 1)
373 bt_sms.icon_set(bt_sms_icon)
374 box_main.pack_end(bt_sms)
375 bt_sms.callback_clicked_add(show_missed_sms)
380 elementary.shutdown()