Introduction
This article is going to cover the basics of call management with Windows Mobile using the State and Notifications Broker combined with P/Invoke. We’ll end up building an application you can deploy to your Windows Mobile phone that lets you programmatically handle calls to your device during times you don’t want to handle them yourself, like during meetings, sleeping, watching a movie, etc. Rather than answer the calls, they can be programmatically sent to voice mail, ignored, or have an SMS auto-respond-message sent.
Background
It started out innocently enough – I received a phone call on my mobile phone while I was at work. Looking down, I didn’t recognize the number…it was an 866 number. I hesitated, and then answered it…ugh-how the heck is some telemarketer calling me on my mobile phone? I hung up, but then later, another 866 number called. I promptly hit the “ignore” soft-key and away my troubles went. Fast forward about 40 minutes, and the same number calls me again. Ignore again, and this time I saved it in my contacts list as “Annoying 866 caller”, which had reminded me of a similar story I’ll tell you all about a woman in Ohio who kept dialing my number by mistake for months, but for now, let’s get back to the problem at hand.
I started thinking about it, and then it really bothered me…this is my cell phone after all, so why can’t I control whether I want to be bothered by such calls? Well, with Windows Mobile, I can! The app we build in this article is the result of my annoyance with these calls.
Let’s lay a few ground rules first – to the best of my knowledge, there does not exist a way to automatically (read that programmatically) reject an incoming call without any kind of notification to the user. I can live with that and work around that. My end goal in designing this project was to eliminate the need for me to deal with pesky toll-free numbers calling me on my cell phone…it was only after I completed this first iteration of the project that other ideas crept into my head and I realized there’s a lot more that can be done to make my phone truly work for me…more on that later.
Since we can’t automatically reject a call, what’s left to do? Well, looking at my normal actions, I can break it down like this:
- Phone Rings – look at the incoming number displayed on my screen.
- Is the number an 800 number? If so, press the “Ignore” soft-key and then acknowledge the “missed call” notification.
Since that’s a short series of manual steps, we can automate that and my life becomes easier again :)
Making friends with the State and Notifications Broker
If you’re developing software with Windows Mobile, you don’t go very far before realizing you need to get acquainted with the State and Notifications Broker (SNB). The SNB gives you an incredible mechanism for storing and working with information related to state changes associated with your mobile device. I won’t re-hash what’s already been written about SNB – instead, you can read about it on MSDN to get started. Here's the link: http://msdn2.microsoft.com/en-us/library/aa455748.aspx.
The SNB plays a key role in our project because it is going to detect the presence of an incoming call and then retrieve the number of that incoming call. Once we have the number, we’re just going to analyze it and then let it go through so I can answer it, or programmatically press the “Ignore” soft-key and I won’t have to deal with it. So, let’s take a look at the code we’re going to use for this.
I’ve set up a small function called MonitorNotifications
which is called when the form loads. This function adds my phoneStatus
System State Notification to an array list I’ve created (in case I later want to add more System State Notifications to this project).
You’ll notice the SystemProperty
I’m monitoring in this case is PhoneIncommingCall
, and I’ve added a handler for when that status changes.
Private Sub MonitorNotifications()
Dim s As SystemState
s = New SystemState(SystemProperty.PhoneIncomingCall)
AddHandler s.Changed, AddressOf ChangeOccurred
StateNotificationList.Add(s)
End Sub
So, what happens then in the event handler for ChangeOccured
? Take a look below:
Private Sub ChangeOccurred(ByVal sender As Object, ByVal args As ChangeEventArgs)
If SystemState.PhoneIncomingCall = True And chkIgnoreAllCalls.Checked = True Then
BounceCall()
End If
If SystemState.PhoneIncomingCall = True And _
SystemState.PhoneIncomingCallerNumber = txtIgnoreThisNumber.Text Then
BounceCall()
End If
End Sub
Basically, this just handles the logic for the phone call management. First, we’re checking to see if I feel like ignoring all calls (via a check box on my form), and then we’re checking to see if the incoming call number is in my simple “block number” (a text box on the screen). If either of those conditions are true, then bounce the call with the BounceCall
function.
The BounceCall
function makes use of P/Invoke to programmatically press the “Ignore” soft-key that shows up on screen when an incoming call is present on your device. A full write-up on P/Invoke is beyond the scope of this article, so take this as a starting point and learn from it…I’ll cover more about P/Invoke in later articles. Here’s the code we’re working with:
Const KEYEVENTF_KEYUP = &H2
Const KEYEVENTF_KEYDOWN = &H0
<dllimport("coredll.dll", charset:=""Runtime.InteropServices.CharSet.Unicode)"" /> _
Private Shared Sub keybd_event(ByVal bVk As Byte, ByVal bScan As Byte, _
ByVal dwFlags As Integer, ByVal dwExtraInfo As Integer)
End Sub
Public Shared Sub BounceCall()
keybd_event(115, 0, KEYEVENTF_KEYDOWN, 0)
keybd_event(115, 0, KEYEVENTF_KEYUP, 0)
End Sub
</dllimport("coredll.dll", />
First, we’ve defined two constants for use with our keyboard events. Then, we use P/Invoke to handle the actual keyboard event. BounceCall
simply does a programmatic “Key Down” and then “Key Up” on the appropriate soft-key.
Now that we’ve gone over the basics of the code involved, let’s see the app in action.
Here, we have the basic form up and running in our emulator. Notice my neat little bouncer guy – I thought it an appropriate graphic for the project!
Next, fire up the Cellular Emulator tool (if you’re not sure how to configure this to work with the emulator, take a look at my previous article which details these steps: http://ilovevb.net/Web/blogs/vbmobile/archive/2008/01/07/vb-net-mobile-hello-world.aspx).
Once you’ve got the Cellular Emulator running, place a call to the device emulator to see it show up on the screen as shown below:
Notice the “Accept” and “Ignore” soft-keys present when an incoming call is in progress. Go ahead and ignore the test call for now, and then take that same number you just called with and put it in the text box on the form, as shown below:
When you place the call a second time, you may not actually notice anything in the emulator – but go ahead and click on the “Missed Call” notification icon in the top bar of your screen... you should now see two missed calls – the first one you manually did to test, and the second one programmatically handled by our call bouncer, as shown below:
And, the cool thing is, with it working that fast in the emulator, imagine how fast it can act on your device! Unless I have my phone set to vibrate and it’s on some kind of hard surface, I don’t even realize that my call bouncer just rejected a call….it happens so quickly. What typically happens is that, later in the day, I notice a missed call icon and click to view it…sure enough, there’s an 800 number there.
A few final notes about this project...
So, what really happens when you programmatically press the ignore button on the phone? In my case, it drops the caller to voice mail – but the trick here is, I purposefully do not have a voice mailbox set up on my account (I have one available, I just never set it up), so they just get a message saying that the current subscriber does not have voice mail configured – goodbye. In your case, maybe you do have voice mail set up, in which case, you’ll likely get a voice mail notification later on.
Also – in this project, I mention dropping “800” numbers which my phone does now. This example, however, limits it to just a single number in a text box to compare with versus using some kind of matching (hint: regular blocked expression for 800 numbers). I’m leaving that implementation up to the reader to figure out, grow and learn with based on the foundational knowledge I’ve provided here. Once you’ve hooked into the SNB and are handling a call, what you do with it is up to you.
Oh - and about that lady from Ohio that called my phone repeatedly over the course of a few months. The first time she called, I answered because I actually do have friends from Ohio who maintain their cell phone numbers there. When she asked for someone who I clearly did not know, I told her she had the wrong number, and she called back a few minutes later. Same story - same wrong number. Annoyed, I saved the number to my contacts list as "Ohio Wrong Number". A few days later, I recognized the number calling me again, and this time answered it "Ohio Telecom Wrong Number Department, How may I direct your call?". The rest of the conversation follows:
Her: "I'm trying to get in touch with Sara at (555) 555-1212 (number masked to protect the innocent)".
Me: "Sorry - you dialed (111) 111-1111 by mistake (my number masked, so I don't have to add a bunch of you to my blocked call app!). To get in touch with Sara, you'll need to hang up and dial (555) 555-1212.
Her: "OK thanks!"
And then, I wondered how long before she'd catch on to the flaw in that whole transaction. In any case - she never did catch on. Over the next few months, she occasionally continued to call and I would continue to answer as the "Wrong Number Department". Occasionally, I would be with friends when she would call, and I'd have them answer as the "Wrong Number Department" too. Sometime late last year, she finally stopped calling me. Now, I just have her in my call block list for this app on my phone!