Contact

Technology

Sep 10, 2009

Google Voice Dialer for Windows Mobile

Dustin Talk

Dustin Talk

Default image background

(To skip the article and go straight to the download click: here)

Windows Mobile 6.1 Screenshot

Introduction:

7/15/2009. (googleblog) Google comes out with Google Voice applications for the Android and the Blackberry platforms.

As a Google Voice user, while it was exciting to see mobile development for Google Voice, it left me as a Windows Mobile user in the dark. I still had two options though for my outbound calls to appear as my new Google Voice Number. One option was to connect to the online mobile interface for Google Voice to initiate calls (google.com/voice), or the second option of calling my own Google Voice number and utilizing the telephony menu system to perform and outgoing call. This second method seemed like the best option to me since it did not require the use of a data plan. Now the challenge was automating it by creating a dialer.

The dialer concept is not hard, but requires the use of new tools and frameworks; the Microsoft .Net Compact Framework. For this instance we will be specifically focusing on the .Net CF version 3.5. While one could make a dialer as fancy or minimal as they wanted, I will give a brief outline of the most important features I have implemented:

  • Dialing outbound calls with automated input

  • Saving settings to a local XML file

  • Importing a list of contacts from the phones contact list

  • Saving speed dial numbers to the registry

While these section overviews will provide only brief code samples, the full source of the project is available in for download.

Note: The forms in the code and the binary have been specifically designed to fit a mobile landscape QVGA window for a non touch-screen device. This is compatible with devices such as the Verizon HTC Ozone, Sprint Snap, and T-Mobile Dash 3G, and many others. Compatibility with other devices may require modification to the code.

Environment:

The tools necessary to setup the correct environment to compile and publish this application are listed below. I used the full version of Visual Studio and not the express version because the full version allows for a drag and drop form designer for mobile applications, along with quick deployment to a simulator for debugging. The code may work with Visual Studio Express, but will require custom compilation via the command line. I have also used the Windows Mobile 6.0 Standard SDK and not the Professional since I am not running the Professional version on my device. If you have a touch screen phone with Windows Mobile Professional, I see no reason that this code could not be adapted to work with either SDK.

  • Visual Studio 2008, C#

  • Windows Mobile 6.0 Standard SDK

Outbound Calling:

Using the reference (this must be added to the project) Microsoft.WindowsMobile.Telephony, there are only two simple lines of code needed to use the phone systems dialer to place a call.

[code language=”c#”]

Phone phoneCall = new Phone();

phoneCall.Talk(myGVPhoneNum);

[/code]

The trick part is performing dialing and punching keys after the phone’s internal dialer has taken over. We are able to do this by waiting for the call to be connecting, then a callback is issued to our program where we send simulated keystrokes to the OS’s global keyboard buffer. A full listing of all of the keycodes can be found here: Keys and Keycodes for Windows Mobile.

[code language=”c#”]

public static void SendKey(byte key)

{

const int KEYEVENTF_KEYUP = 0x02;

const int KEYEVENTF_KEYDOWN = 0x00;

keybd_event(key, 0, KEYEVENTF_KEYDOWN, 0);

keybd_event(key, 0, KEYEVENTF_KEYUP, 0);

}[/code]

[DllImport(“coredll”, SetLastError = true)]

private static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);

Saving data to XML:

The System.Xml class XmlTextWriter provides a simple mechanism to stream data to a well formated xml file. In our program we use it to write a settings file to the filesystem. Not wanting to provide a complex encryption mechanism, and not wanting a plain-text storage of passwords, I have chosen to write the google vocie password as a base-64 encoded string. For files much larger, I would suggest prompting for a storage location or checking for file space availability first. As always, wrap IO functions to be caught in the event of an error.

[code language=”c#”]

System.Text.ASCIIEncoding encoding=new System.Text.ASCIIEncoding();

XmlTextWriter writer = new XmlTextWriter(exeDirectory + “\\dialgv.xml”, null);

writer.WriteStartElement(“settings”, “gvdial”);

writer.WriteElementString(“connDelay”, “gvdial”, txtConnDelay.Text);

writer.WriteElementString(“pinDelay”, “gvdial”, txtPinDelay.Text);

writer.WriteElementString(“dialDelay”, “gvdial”, “500”);

writer.WriteElementString(“myGVPhoneNum”, “gvdial”, txtPhone.Text);

writer.WriteElementString(“myGVPinNum”, “gvdial”, Convert.ToBase64String(encoding.GetBytes(txtPin.Text)));

writer.WriteEndElement();

writer.Close();

[/code]

Reading in the settings is similar to writing them, however we must account for the password stored in base-64 and take measures to convert it back into plain-text.

[code language=”c#”]

try

{

XmlTextReader xmlReader = new XmlTextReader(exeDirectory + “\\dialgv.xml”);

if (xmlReader == null)

{

frmSettings.giveMessage();

}

else

{

xmlReader.WhitespaceHandling = WhitespaceHandling.None;

while (xmlReader.Read())

{

switch (xmlReader.Name.ToString())

{

case “connDelay”:

set_connDelay(System.Convert.ToInt32(xmlReader.ReadString()));

frmSettings.set_connDelay(get_connDelay());

break;

case “pinDelay”:

set_pinDelay(System.Convert.ToInt32(xmlReader.ReadString()));

frmSettings.set_pinDelay(get_pinDelay());

break;

case “myGVPhoneNum”:

set_myGVPhoneNum(xmlReader.ReadString());

frmSettings.set_myGVPhoneNum(get_myGVPhoneNum());

break;

case “myGVPinNum”:

set_myGVPinNum(xmlReader.ReadString());

frmSettings.set_myGVPinNum(get_myGVPinNum());

break;

}

}

}

xmlReader.Close();

}

catch (FileNotFoundException)

{

frmSettings.giveMessage();

}

[/code]

Phone Contacts:

Microsoft provides the reference Microsoft.WindowsMobile.PocketOutlook, to access the contact information stored on the phone. We iterate through each of our contacts and add the phone numbers as they are found, similar to the default contact schema of Windows Mobile 6.1. An upgraded version of this would be to connect to Google Contacts and synchronize this list and store it offline. This may not be applicable however if you setup Activesync to sync contacts with Google.

[code language=”c#”]

OutlookSession mySession = new OutlookSession();

ContactCollection collection = mySession.Contacts.Items;[/code]

foreach (Contact contactItem in collection)

{

//add each contact

}

Reading and Writing to the Registry:

Writing to the registry is made very simple in the .Net 3.5 CF. Our first step is to create and instantiate a RegistryKey object which we will use to perform reading / writing. This object is seeded with the location of the registry key we wish to write to. In this instance it is “HKLM\\SOFTWARE\\Dustin Talk\\dialgv”. Then, careful to catch any errors we write a speed dial number to the registry by setting the string value name to the speed dial number (ex: 2) and data of the phone number it belongs to (ex: 214-722-5239).

[code language=”c#”]

RegistryKey reg = Registry.LocalMachine.CreateSubKey(“SOFTWARE\\Dustin Talk\\dialgv”);

try

{

int num = Convert.ToInt32(textBox.Text);

reg.SetValue(num.ToString(), String);

}

catch (Exception ex)

{

MessageBox.Show(“Unable to save speed dial: ” + ex.Message, “Error”);

}

[/code]

To read the speed dials from the registry we create a similar object as we did before seeding the same location key in the registry. We will then read an array of strings from the RegistryKey object by calling the function GetValueNames(); Catching any errors, and detecting no names available, we add each item that was previously saved to our listView of items.

[code language=”c#”]

try

{

RegistryKey reg = Registry.LocalMachine.OpenSubKey(“SOFTWARE\\Dustin Talk\\dialgv”, true);

string[] vals = reg.GetValueNames();

if (vals.Length <= 0) { MessageBox.Show("You do not have any speed dials saved", "Error"); return; } for (int i = 0; i < vals.Length; i++) { ListViewItem lvI = new ListViewItem(vals[i]); lvI.SubItems.Add(pNum); lvSpeeds.Items.Add(lvI); } } catch (Exception) { MessageBox.Show("You do not have any speed dials saved", "Error"); } [/code]

License:

This article, along with any associated source code and files, is licensed under Apache License, Version 2.0

About the Author:

Dustin Talk is a consultant at Credera. He graduated from Texas A&M University with his Masters of Computer Science, B.S. in Computer Science, and a minor in Business. Throughout his academic career he developed applications using Java and .Net technologies. While in school, he worked for The Department of Statistics as a Network Administrator. He has interned for Anheuser-Busch Inc. as a Systems Engineer developing in .Net and working with industrial software.

Download:

Project Source Code

Binary Installation Cab for Window Mobile 6.1 Smartphone

Please use the contact me if you can offer any interesting modifications or suggestions to the code, or if you would like additional resources on your project.

Drive digital transformation with enterprise web and mobile applications through Microsoft Solutions

Explore Our Microsoft Consulting Services  →

    Conversation Icon

    Contact Us

    Ready to achieve your vision? We're here to help.

    We'd love to start a conversation. Fill out the form and we'll connect you with the right person.

    Searching for a new career?

    View job openings