×
Namespaces

Variants
Actions

Archived:Python on Symbian/06. Telephony and Messaging

From Nokia Developer Wiki
Jump to: navigation, search

Archived.pngAquivado: Este artigo foi arquivado, pois o conteúdo não é mais considerado relevante para se criar soluções comerciais atuais. Se você achar que este artigo ainda é importante, inclua o template {{ForArchiveReview|escreva a sua justificativa}}.

All PySymbian articles have been archived. PySymbian is no longer maintained by Nokia and is not guaranteed to work on more recent Symbian devices. It is not possible to submit apps to Nokia Store.

Original Author: Mike Jipping

Article Metadata
Code ExampleArticle
Created: User:Frethop (30 Nov 2010)
Last edited: hamishwillee (08 May 2013)

Symbian supports many operations and has many features. But it is first and foremost a smartphone operating system. The word phone here is what is at the core of Symbian's functionality. Python directly supports the use of Symbian devices as phones.

Phone communication is usually split into two forms: voice and messaging. Python supports each of these in clear, intuitive ways. We handle both of these forms of communication in this chapter, along with a large example for each.

Contents

Introduction

If you think through the actions you perform to make or receive a phone call, or to send or receive a text message, they are very simple. The functionality built into the Python modules that support telephony and messaging reflect this.

The functionality is implemented by callbacks, functions that are called by the operating system when the phone receives a phone call or a message.

Both telephony and messaging support are discussed in this chapter. We walk through the Python support, including callbacks, and we demonstrate this support with complete examples. We conclude the chapter by discussing how Python allows access to records (logs) that the phone keeps about calls and messages that have been made, sent and received.

Telephone Operations

Telephone operations, as humans perform them, are very simple. We can dial a phone. We can answer an incoming call. We can hang up on a call. Python support for telephony reflects this simplicity. Python adds the ability to monitor a phone for a call, an action we also perform when we expect an important call!

Python telephony functionality is built into the telephone module. This module needs to be imported before access to the functionality is possible.

Making a Phone Call

To dial a phone using the dial() function use the calling sequence

telephone.dial(<number>)

The parameter <number> is a string that holds the phone number to dial. It will be dialed as given, so all parts of the number need to be included (country code, area code, etc). For example, this will dial a number in the United States:

telephone.dial(u"+15075551122")

The <number> must be encoded in unicode.

If there is already a phone call going on when the call to dial() is made, the existing phone call is placed on hold automatically and the new phone call is placed.

To hang up (terminate) a phone call use the hang_up() method without a parameter. Calling this method terminates the current call if that call was initiated by a dial() method call.

Let's consider some examples. Let's start by making a local call:

import telephone
telephone.dial("5551234")

This tells the phone make a phone call, as shown in Figure 6-1.

PythonOnSymbian Figure6-1.jpg
Figure 6-1: A Symbian phone making a call using dial()

At this point, the following call terminates the phone call:

telephone.hang_up()

Here are a few important notes about Python's understanding and use of phone calls:

  1. Python has its own idea of the pairing of call initiation and hanging up. For example, if you dial a phone number and start a phone call manually, then call hang_up(), you get the following error:
    Traceback (most recent call last):
    File "<console>", line 1, in <module>
    File "c:\resource\python25\python25.zip\telephone.py", line 60, in hang_up
    _phone_answer.hang_up()
    RuntimeError: no call to hang up
    Even though there is a phone call in progress, Python did not start the call so it cannot terminate it.
  2. Likewise, if you start a phone call with a call to dial(), you must use hang_up() before you call again, even if you hang up manually. Let's say we perform the sequence below:
    >>> telephone.dial("5551234")
    >>> # ...now we hang up the phone manually
    >>> telephone.dial("5551234")
    Traceback (most recent call last):
    File "<console>", line 1, in <module>
    File "c:\resource\python25\python25.zip\telephone.py", line 53, in dial
    _phone.dial()
    RuntimeError: call in progress, hang up first

Answering a Phone Call

Another simple operation that humans do is to answer the phone. The telephone module makes this easy with the answer() method call. Just as answering a phone call when the phone call is not ringing is a bit silly, simply calling answer() is also useless unless there is actually a call coming in. To properly answer a call, the phone must be prepared or configured to do so, then must be able to figure out when a call is coming in.

To prepare a phone, the telephone module supplies the incoming_call() method. Calling this function sets up the phone to receive a call. The call to this method returns immediately, but the Python runtime system is now listening for an incoming call. Once a call comes in, it can be answered by calling with the answer() method. There are several ways to make your application call the answer() method: for example in response to the user tapping a button on the application's user interface; or in response to a state change of the phone (see the next section for how to detect state changes).

Answering phone call implies nothing more than connecting the two sides of the call. There is no further application interaction after that.

Monitoring Phone Activity

The telephone module provides a way to monitor phone activity. The module identifies 12 states that a phone line can be in, as shown in the table below:

Table 6.1 12 phone line states

Python Name State Value Description
EStatusUnknown 0 the state of calling is unknown
EStatusIdle 1 no active calls are taking place
EStatusDialling 2 dialing is taking place on a phone line
EStatusRinging 3 the phone is ringing
EStatusAnswering 4 the phone is being answered
EStatusConnecting 5 the phone call is connecting to the remote phone
EStatusConnected 6 the phone call has been connected to the remote phone
EStatusReconnectPending 7 something has caused a channel loss and the call is being reconnected
EStatusDisconnecting 8 the phone call is being disconnected
EStatusHold 9 the current call is on hold
EStatusTransferring 10 the current call is being transferred
EStatusTransferAlerting 11 the remote phone is being alerted to the call being transferred

The telephone module enables the state to be monitored through a callback function. An application must specify and register a function that the operating system is to call each time the phone changes between the states above.

Let's look at an example. The function below prints the new state whenever the state changes.

import telephone
def newphonestate (stateInformation):
newState = stateInformation[0]
if newState == telephone.EStatusUnknown:
msg = "The new state is unknown"
elif newState == telephone.EStatusIdle:
msg = "The phone is idle"
elif newState == telephone.EStatusDialling:
msg = "The phone is dialling"
elif newState == telephone.EStatusRinging:
msg = "The new phone is ringing, call is from %s" % stateInformation[1]
elif newState == telephone.EStatusAnswering:
msg = "A call is being answered"
elif newState == telephone.EStatusConnecting:
msg = "A call is connecting"
elif newState == telephone.EStatusConnected:
msg = "A call has been connected"
elif newState == telephone.EStatusReconnectPending:
msg = "The channel has been lost and a reconnect is being attempted"
elif newState == telephone.EStatusDisconnecting:
msg = "A call is being disconnected"
elif newState == telephone.EStatusHold:
msg = "A call is being placed on hold"
elif newState == telephone.EStatusTransferring:
msg = "A call is being transferred"
elif newState == telephone.EStatusTransferAlerting:
msg = "The phone is alerting the remote phone about a transferred call"
 
print "The phone has changed states."
print " ",msg
 
telephone.call_state(newphonestate)

There are several things to note in this example.

  • The function that will be called (the callback function) has a parameter: a tuple that carries information about the new state to which the phone has moved. This tuple has two items: the first is the new state value and the (optional) second item is the phone number for an incoming call.
  • The function is registered by a call to the call_state() function.
  • Every time the phone state is changed, a new call to call_state() is made.

The output of the code above is shown below for a call that comes to the phone, is answered by the phone's user, and is then terminated by the caller:

The phone has changed states.
The new phone is ringing, call is from 15055551234
The phone has changed states.
A call is being answered
The phone has changed states.
A call has been connected
The phone has changed states.
A call is being disconnected
The phone has changed states.
The phone is idle

Code of this type can be used to replace incoming_call(). The disadvantage of using incoming_call() is that execution is suspended so, for example, it would not work in a program with a graphic user interface. Using call_state() with a callback follows the event-driven model of a GUI and is therefore better suited for this type of programming.

A Sample Application: Caller Information

Consider an example of the telephone interface.

Let's say that a person in a sales position keeps notes about her clients in the contacts database on her phone. She thinks it would be nice to pull up that information automatically when a client calls her phone.

Figure 6-2: Example Screenshot of Sales Person App

Figure 6.2 Example Screenshot of Sales Person App

This application is running in the background and pops up the information window when it can find information. You can put an application in the background by starting it, then pressing the applications key to display the application icons. The application keeps running in the Python runtime environment while allowing you to interact with other applications.

We can implement this example fairly easily. In fact, the code below is mostly contact searching rather than telephone call processing. Consider the code below.

import telephone, contacts
import appuifw, e32, graphics, topwindow
 
#--------------------------------------------------------------------------------
# This function is called when a phone call is made. It does the
# contact lookup and the display of the info window.
#--------------------------------------------------------------------------------
 
def displayNotes(infoTuple):
 
# Get the phone's state
phoneState = infoTuple[0]
 
# Only react when the phone is ringing
if phoneState == telephone.EStatusRinging:
 
# Start by opening the contacts database and looking up the phone number
db = contacts.open()
contactList = db.find(infoTuple[1])
 
# Build the list of notes in a string, separated by "\n"
if contactList:
try:
noteString = '\n'.join(note.value for note in contactList[0].find(type='note'))
except:
noteString = u"No notes available"
else:
noteString = u"The phone number was not found"
 
# Now we build the topwindow window from the notes
notes = noteString.split("\n")
window = topwindow.TopWindow()
window.size = (350, 40+(30*len(notes)))
window.position = (10, 40)
img = graphics.Image.new((310, 30*len(notes)))
img.clear(0x99CCFF)
position = 20
for note in notes:
img.text((20, position), unicode(note), font = 'title')
position += 30
window.add_image(img, (20, 20))
window.background_color = 0xDDDDDD
window.shadow = 4
window.corner_type = 'corner5'
 
# Display the window and sleep for 5 seconds. Then hide it.
window.show()
e32.ao_sleep(5)
window.hide()
 
# Finally, install the function as the phone callback
 
telephone.call_state(displayNotes)

Let's go through this code in pieces. The import statements reveal what we need to make this idea work:

import telephone, contacts
import appuifw, e32, graphics, topwindow

The bulk of the code is implemented in the displayNotes() function, which is the callback for the system when the state changes. As we discussed in the previous section, this function is defined with a parameter, called infoTuple here, that has information about the call. The first thing that we do is extract the state of the phone:

# Get the phone's state
phoneState = infoTuple[0]

We only want to do something when the phone is ringing, so this is the only state the function reacts to:

# Only react when the phone is ringing
if phoneState == telephone.EStatusRinging:
...

The code proceeds to open the contacts database and look up the contact using the phone number in the infoTuple variable:

# Start by opening the contacts database and looking up the phone number
db = contacts.open()
contactList = db.find(infoTuple[1])

The remainder of the displayNotes() function retrieves the notes from the contact entry, then builds a TopWindow window to display it. You can examine how this code works yourself.

The code finally registers the displayNotes() function as the callback for phone calls:

# Finally, install the function as the phone callback
telephone.call_state(displayNotes)

Note.pngExercise: Extend This Code: The sales person would like to know how many times she has spoken with someone. You might change the code to (a) react to some different call status types (EStatusAnswering perhaps), (b) find a note with the count on it and (c) change that note. You have most of the code you need in the above example, except for code that adds a field to a contact and changes a field.

Messaging Operations

As with telephone operations, the operations when dealing with SMS and MMS messaging are simple. We can send messages; we can receive messages; and we can store messages. Each of these operations are handled through a Python module.

Sending SMS Messages

The messaging module handles the sending of SMS messages. The method used to send a SMS message in the messaging module is the sms_send() method, whose format is shown below:

sms_send(<number>, <message>,[<encoding>, <callback>, <name>])

The parameters are as follows:

  • <number> is the telephone number of the recipient of the message.
  • <message> is the body text of the message to be sent.
  • <encoding> is a specification of the encoding of the message. It can can be 7-bit encoding ("7bit"), 8-bit encoding ("8bit") or Unicode ("UCS2"). The default setting is for 7-bit encoding.
  • <callback> is the name of the function to call when the status of the message changes. This callback function is called with a single parameter: the state value of the message. The default value for this parameter is None (that is, no callback).
  • <name> is the name to be given to the message when it is recorded. The default value of this parameter is the telephone number of the recipient.

A message can be in one of nine states, from created to sent. The messaging module has constants that represent each state, as shown in the table below:

Table 6.2 Constants representing the nine message states

Python Name State Value Description
ECreated 0 the message has been created
EMovedToOutBox 1 the message has been moved to the Outbox
EScheduledForSend 2 the message is waiting for the phone to send it
ESent 3 the message has been sent
EDeleted 4 the message has been deleted from the Outbox
EScheduleFailed 5 the message cannot be schedule for sending
ESendFailed 6 the message cannot be sent
ENoServiceCentre 7 a state for a message in a phone emulator, indicating no service is possible
EFatalServerError 8 the message has encountered an error from the phone service's message server

The relationships between these states is shown below in Figure 6.3:

Figure 6-2: Relationships between message states

Figure 6.3 Relationships between message states

The lines through the diagram provide a path of state changes for messages. For example, a message could be created, moved to the Outbox, scheduled for sending, then sent. A message might also be created, moved to the Outbox, scheduled for sending, then deleted

Consider this example of sending a message. As with the telephone example, our callback simply prints a string that shows the state of our message as it moves from creation to sending.

import messaging
def newmessagestate (newState):
if newState == messaging.ECreated:
msg = "A message has been created"
elif newState == messaging.EMovedToOutBox:
msg = "The message has been moved to the Outbox"
elif newState == messaging.EScheduledForSend:
msg = "The message has been scheduled for sending"
elif newState == messaging.ESent:
msg = "The message has been sent"
elif newState == messaging.EDeleted:
msg = "The message has been deleted"
elif newState == messaging.EScheduleFailed:
msg = "The message scheduling has failed"
elif newState == messaging.EStatusConnected:
msg = "Attempts to send the message have failed"
elif newState == messaging.ENoServiceCentre:
msg = "You are using an emulator; you cannot send from the emulator"
elif newState == messaging.EFatalServerError:
msg = "A fatal error has occured with the messaging system"
 
print "The message has changed states."
print " ",msg
 
messaging.sms_send("15055551234", "This is a text message for testing state changes", callback=newmessagestate)

Using this code with an actual phone number (a real recipient) produces the following output:

The message has changed states.
    A message has been created
The message has changed states.
    The message has been moved to the Outbox
The message has changed states.
    The message has been scheduled for sending
The message has changed states.
    The message has been sent
The message has changed states.
    The message has been deleted

There are several things to note about the sending procedure and the sms_send() method:

  • Until a message has transitioned through all of the states that it can -- consider the paths through the diagram in Figure 6-2 -- the sms_send() method cannot be used again.
  • The name given to the text message in the call to the sms_send() method has a maximum size of 60 characters.
  • The behaviour when no callback is specified is to block until the message has transitioned through all of the states that it can.

Sending MMS Messages

MMS messages resemble SMS messages. They have a short text body, but they also may contain attachments. These attachments are media attachments: images, video, sound files, etc.

Sending an MMS message with Python is not nearly as detailed or as informative as sending an SMS message. The messaging module supports MMS messages through a single method, mms_send(), which has the format below:

mms_send(<number>, <message>, [<attachment>])

The parameters closely match those for sms_send(). The <number> is the telephone number of the recipient. The <message> is a string whose value is the message to send. The optional <attachment> is the pathname in the phone's file system for the file to be attached to the message.

For example, you might want to send a picture of yourself to your friend. You would take a picture with your phone, then send it using the following call:

messaging.mms_send("15055554321", "Here is picture of me.  Aren't I beautiful?", "E:\Images\12262008038.jpg")

The mms_send() method only allows one attachment.

The Inbox Module

The inbox module supports mailbox management in Symbian. In a confusing naming twist, the inbox module defines an Inbox class that represents a folder in Symbian message store. It is confusing because an Inbox object (an instance of an Inbox class) can examine the contents of the Outbox, Sent and Drafts folders as well as the Inbox.

Objects created from the Inbox class can examine all four folders in the message storage:

Table 6.3 Folders in the message storage

Python Name Description
EInbox the Inbox folder on the Symbian OS device
EOutbox the Outbox folder on the Symbian OS device
ESent the folder of sent messages
EDraft the folder of draft messages

An Inbox object is created like this:

inbox = Inbox([<foldertype>])

Here, <foldertype> is one of the names in the table above. If the <foldertype> is not specified EInbox is used.

Once you have created an Inbox object you can get a list of SMS messages by using the sms_messages() method. This returns a list of message IDs as integers. This code prints the number of SMS messages in your Inbox:

import inbox
box = inbox.Inbox(inbox.EInbox)
messages = box.sms_messages()
print "You have %d SMS messages waiting." % len(messages)

Most of the remaining methods in the inbox module operate on an individual messages, specified using <messageID>.

  • content(<messageID>) returns the content of the message as a string
  • time(<messageID>) returns the time that the message arrived (in seconds since the epoch - see Time Operations in Chapter 3)
  • address(<messageID>) returns the address of the sender of the message. This may be a telephone number or a name in the device's contacts list.
  • unread(<messageID>) returns the "read" status of the message. A status value of 1 means that the message is unread and a status of 0 means the message has been read.
  • set_unread(<messageID>,<status>) sets the status of the message to unread (1) or read (0)
  • delete(<messageID>) attempts to delete the message. If the message does not exist Python raises a (SymbianError) exception.

In the following example we pick a text message to examine by taking the first message id in the message list.

import inbox
box = inbox.Inbox(inbox.EInbox)
messages = box.sms_messages()
id = messages[0]

Now, let's examine this message's attributes. It was received via Twitter and it was posted by a Nokia enthusiast.

>>> box.content(id)
u'nokconv: Post: You say business phones need long haul batteries... but do all phones? http://ow.ly/15RMSR'
>>> print time.strftime("Message received on %a, %d %b %Y at %H:%M:%S", time.localtime(box.time(id)))
Message received on Tue, 29 Sep 2009 at 07:43:52
>>> print "Message received from %s" % box.address(id)
Message received from Twitter
>>> print box.unread(id)
1

Notes: I have the phone number of the Twitter service entered into my contacts under "Twitter", so the system reported the source of the message as "Twitter", not a number. Also, although we printed the contents of the message, the message remains unread. The unread status of the message is a property of the user interface.

There is one more method in the Inbox class, which we discuss below.

Receiving Messages

The Inbox class uses a callback function to process received messages. A callback function must be registered using the bind() function as shown below.

inbox.bind(<function name>)

When a message arrives, the system calls the callback function with with the message ID as the parameter. Consider the example below:

import inbox
import time
 
box = inbox.Inbox(inbox.EInbox)
 
def incomingMsg(messageID):
print messageID
print time.strftime("Message received on %a, %d %b %Y at %H:%M:%S", time.localtime(box.time(messageID)))
 
box.bind(incomingMsg)

This code looks as though it should print the ID of the message and the time of arrival, nicely formatted. However, it throws an exception as shown below:

Traceback (most recent call last):
  File "<console>", line 3, in incomingMsg
SymbianError: [Errno -21] KErrAccessDenied

To understand the problem with this code we must understand what is going on in the phone. The phone's built-in Messaging application, the one that displays messages, is running and has also registered a callback with the operating system. When we run our Python code there are two programs competing for the same resource (the message store). The messaging application is designed to run fast and will almost always access the message store before our Python code. Our Python code cannot access the message store at the same time, hence our exception.

To solve this race condition we can add a call to time.sleep(). This pauses the code long enough for the messaging application to relinquish access to the message store. The example now looks like this:

import inbox
import time
 
box = inbox.Inbox(inbox.EInbox)
 
def incomingMsg(messageID):
time.sleep(5)
print messageID
print time.strftime("Message received on %a, %d %b %Y at %H:%M:%S", time.localtime(box.time(messageID)))
 
box.bind(incomingMsg)

The results of the code now look like this:

1051799
Message received on Tue, 06 Oct 2009 at 15:58:52

The above code works in most cases, but it is not guaranteed to work all the time. The best solution is to try to access the message store for a certain number of times and trap the exception as a way to count the number of access failures. Consider the code below:

import inbox
import time
 
box = inbox.Inbox(inbox.EInbox)
 
def incomingMsg(messageID):
print messageID
for times in range(10):
try:
print time.strftime("Message received on %a, %d %b %Y at %H:%M:%S", time.localtime(box.time(messageID)))
break
except:
pass
 
box.bind(incomingMsg)

A Sample Application: SMS Autoreply

Let's consider a larger example. Here is an application that automatically responds to incoming SMS messages with a "nice" vacation message. That is, a message formatted with the name of the sender which indicates that we will send a reply later. We only do this if we can find a name for the sender; we do not want our reply message to look tacky by using a telephone number as the name.

Consider the code below as version 1:

import messaging, inbox, time
 
box = inbox.Inbox(inbox.EInbox)
 
def autoreply(messageID):
time.sleep(5)
sender = box.address(messageID)
text = box.content(messageID)
if not any(c.isdigit() for c in sender):
reply = sender + \
", I am not able to read your message at this time." + \
" I will respond soon."
print 'Sending "'+reply+'" to '+sender
messaging.sms_send(sender, reply)
 
box.bind(autoreply)

This code uses the function isdigit() to determine whether any of the characters from sender is a digit. Admittedly, this is a very crude way of detecting whether sender is a (telephone) number.

When we run this code and then receive a text message, the output looks like this:

Sending "Joe Smith, I am not able to read your message at this time.  I will respond soon." to Joe Smith

However, the message is not sent. In fact, when we look at the Outbox, we see:

Figure 6-3: The message has not been sent.

And when we move the message to the Drafts folder and try to work on it, we get the following error:

Figure 6-4: There's an error in contact details.

We get this error because:

  1. the phone "filtered" the message through our contacts, which gave us a name ("Joe Smith") instead of a telephone number as the source of the message and
  2. we then tried to send the message to "Joe Smith" instead of a telephone number.

To correct this, we must retrieve the phone number from the contact in the Contacts database. Consider the code below:

import messaging, inbox, time, contacts
 
box = inbox.Inbox(inbox.EInbox)
 
def autoreply(messageID):
time.sleep(5)
sender = box.address(messageID)
text = box.content(messageID)
if not any(c.isdigit() for c in sender):
db = contacts.open()
firstName = sender.split(" ")[0]
lastName = sender.split(" ")[1]
contactList = db.find(firstName)
for contact in contactList:
if contact.find("last_name")[0].value == lastName:
phoneNumber = contact.find('phone_number')[0].value
reply = sender + \
", I am not able to read your message at this time." + \
" I will respond soon."
print 'Sending "'+reply+'" to '+phoneNumber
messaging.sms_send(phoneNumber, reply)
break
 
box.bind(autoreply)

Let's walk through the autoreply() function. The first part of the function is the same: we sleep for 5 seconds and extract the sender and the text from the message. If there are no digits in the sender string we begin to process the message.

This fragment opens the contacts database, finds the first and last name, and finds all contacts in the database with the first name we extracted:

db = contacts.open()
firstName = sender.split(" ")[0]
lastName = sender.split(" ")[1]
contactList = db.find(firstName)

The contact is guaranteed to be in the database because the phone has already returned a name to this function rather than a phone number. It has already looked through the Contacts database and found the contact.

There could, however, be more than one contact entry with the same first name. So, we have to look through all them for the correct last name:

for contact in contactList:
if contact.find("last_name")[0].value == lastName:

All that remains is to extract the phone number and to send the message:

phoneNumber = contact.find('phone_number')[0].value
reply = sender + \
", I am not able to read your message at this time." + \
" I will respond soon."
print 'Sending "'+reply+'" to '+phoneNumber
messaging.sms_send(phoneNumber, reply)
break

And, indeed, this code correctly sends a text message.

Note.pngExtend This Code: This code is a bit simplistic

  • It assumes that the first name and the last name are separated by a space; names like "Frederik Siewertsz van Reesema" might not work.
  • It assumes that "phone_number" is the number to use for text messages; on S60 3rd edition phones, "mobile_number" might be the better choice.
  • There is no "guarantee" that this code will find the contact in the database; if the first name field is not used and the name appears in the last name field, this code will fail.
How might you fix the code to make it more robust?

Accessing and using logs

All S60 devices keep a log of phone call and message activity. These logs are available through the logs Python module.

Log entries are seen as dictionaries in Python. For example, a phone call log entry as it might look to Python is shown below. Because of the large amount of data collected per entry this type of representation can be confusing so the data is separated into key/value pairs, one per line. Notice that the string value are represented with Unicode.

 {
'status': u'No delivery', 
'direction': u'Incoming', 
'description': u'Voice call', 
'duration type': 1, 
'number': u'1616xxxxxxx', 
'name': u'', 
'contact': -1, 
'flags': 0, 
'time': 1254283601.7287519, 
'duration': 80, 
'link': 0, 
'data': '', 
'id': 8500, 
'subject': u'6'
}

Here is a dictionary object depicting a text message entry. Each key is described in the table below.


{
'status': u'Delivered', 
'direction': u'Incoming', 
'description': u'Short message', 
'duration type': -1, 
'number': u'40404', 
'name': u'', 
'contact': -1, 
'flags': 0, 
'time': 1254333004.285248, 
'duration': 0, 
'link': 0, 
'data': '\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00', 
'id': 8576, 
'subject': u'AAS: Ovi Developer Day http://bit.ly/ImAiO'
}

Each of these entries have similar fields, described here:

Table 6.4 Text message entries

Python Name Description
status a brief depiction of the event
direction the direction with respect to the phone of the event: either "Incoming" or "Outgoing"
description a longer description of the event
duration type a description of the type of event, such as a data event or a phone event
number the remote phone number associated with the event
name the name associated with the event
contact the number ID of the contact associated with the event
flags an indication of what cause the event; for example: the user checked for missed calls
time time, in standard notation, when the event occurred
duration number of seconds the event took
link valid if this event was linked to another application
data data associated with the event (for example, the message text)
id the ID of the event in the log database
subject the subject of the event; for example, the text of a message

Logs are kept for several different types of communication events. These types are: call, sms, data, fax, email and scheduler. The types are self-explanatory.

The methods in the logs module are quite straightforward. You can retrieve all log data, log data of a certain type, or log data of a certain type between specific times. When retrieving log entries, you can also filter the entries by mode, a descriptor of each message. Mode specifiers can be in, out, fetched, missed, in_alt or out_alt. Unless specified, the mode is the default value of in.

The methods of the logs module are as follows. Log data is returned as a list of dictionary objects.

  • raw_log_data() returns all events of all types.
  • log_data(<type>, [start_log=<start>, num_of_logs=<number of entries>, mode=<mode>]) returns log entries of a type specified by the <type> parameter. Optionally, you can specify where to start collecting the entries, the number of entries and the mode.
  • log_data_by_time(<type>, <start time>, <end time>, [mode=<mode>]) retrieves entries of the type specified between <start time> and <end time>, optionally of a specific mode. Times must be specified as standard Unix time in seconds from the epoch.
  • calls([start_log=<start>, num_of_logs=<number of entries>, mode=<mode>])
  • faxes([start_log=<start>, num_of_logs=<number of entries>, mode=<mode>])
  • emails([start_log=<start>, num_of_logs=<number of entries>, mode=<mode>])
  • sms([start_log=<start>, num_of_logs=<number of entries>, mode=<mode>])
  • scheduler_logs([start_log=<start>, num_of_logs=<number of entries>, mode=<mode>])
  • data_logs([start_log=<start>, num_of_logs=<number of entries>, mode=<mode>])
These calls retrieve specific types of log entries -- quite self-explanatory -- with the same optional parameters. You can specify the starting point of retrieval, the number of entries to retrieve, and the mode of entry to retrieve.

Here are a few examples. If we want to count the calls we missed in the last 24 hours, we could execute this code:

import logs
 
missed = logs.log_data_by_time('call', time.time()-86400, time.time(), 'missed')
print 'You missed ' + str(len(missed)) + ' calls.'

If we want to show the senders of the last 10 messages received, we could execute this code:

import logs
 
for msg in logs.sms(num_of_logs=10):
print msg['number']

With respect to the previous example, we should consider this question: is the first log entry the oldest one or the latest one? In other words, does the code above print the latest 10 messages received or the first 10 messages received? The answer is the latest, but it is left to you to write code to prove this.

Summary

Smartphones running Symbian are capable of many things, but fundamentally they are phones, which means they can make and receive phone calls, and send and receive SMS and MMS messages. This chapter discussed the support Python provides, through the telephone module, for making and answering phone calls; and, through the messaging module, for sending and receiving messages. We concluded the chapter by discussing how Python supports activity logs with the logs module, which works with information about calls and messages that have been made, sent and received.

Python support for telephony and messaging is provided mainly through callbacks, which are functions that are registered with the operating system and then called by the operating system when phone calls or messages are received by the phone. The use of callbacks was illustrated with several examples.

The modules described above provide a clean, convenient interface to the telephony and messaging functions of a phone. Platform services, which are covered in Chapter 12, also provide telephony and messaging functionality. Platform services are more difficult and less convenient to use, but access deeper and more powerful functionality.

Licence icon cc-by-sa 3.0-88x31.png© 2010 Symbian Foundation Limited. Portions copyright Bogdan Galiceanu, Hamish Willee, Marcelo Barros de Almeida, Mike Jipping, Pankaj Nathani and others in wiki document history list. This document is licensed under the Creative Commons Attribution-Share Alike 2.0 license. See http://creativecommons.org/licenses/by-sa/2.0/legalcode for the full terms of the license.
Note that this content was originally hosted on the Symbian Foundation developer wiki.

This page was last modified on 8 May 2013, at 08:48.
96 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×