Responding to Incoming Phone Calls on WP7

While working on a Windows Phone 7 application recently, I discovered some limitations of the platform that were rather frustrating.  The application allowed audio to be recorded and played back, and it was expected that recording would pause if an incoming phone call was received on the phone.  The app was already designed to pause recording when the app was deactivated, and initially I thought an incoming phone call would cause deactivation.  I was surprised to discover that it did not.  Instead, the app continued to run uninterrupted while a phone call was taken.  If the app was recording at the time, recording would continue throughout the phone call.  Interestingly, the XNA Microphone class appeared to be muted during the phone call, with that portion of the recording being blank, neither side of the conversation captured.

A little searching confirmed that an incoming phone call does not deactivate a WP7 app.  Instead, the app is “obscured”, and the only way to detect the phone call is by subscribing to the Obscured event of the PhoneApplicationFrame class.  Unfortunately, the Obscured event simply indicates that something from the OS is obscuring the visual of your app (“the shell chrome is covering the frame”, in the words of the MSDN docs), without providing any detail about the source cause.  As a result, many things can cause Obscured to fire, including an incoming phone call, locking of the screen, an incoming text message, a calendar event notification, and a MessageBox.  There are no events fired specific to the different types of OS interruptions that can occur, nor any properties in the ObscuredEventArgs to indicate the source cause.  There is an IsLocked property within ObscuredEventArgs that can be used to detect if locking of the screen caused Obscured to fire, but otherwise no other useful information is given.

This presented a problem for our application, and I could imagine it being a problem for others as well.  In our app we wanted to handle incoming phone calls differently than other types of OS interruptions, such as incoming text messages or calendar event notifications.  The former should pause recording, while the latter should not.  (Pausing recording in response to something as innocuous as a calendar notification would be an awful experience within our app, as the user could easily be unaware recording had stopped, causing potentially important audio to be missed.)

Even the ability to discriminate a screen lock as the source of the Obscured event is of limited value.  We’ve set up our app to continue running (and recording) under lock screen, and at first glance it seems like it would be helpful to ignore the Obscured event if a screen lock was the cause.  Unfortunately, once the screen is obscured, no other OS interruptions fire the Obscured event until the screen is once again unobscured.  Although we did not want to pause recording in response to the lock screen, we did want to pause recording in response to an incoming phone call, including when the screen was locked.  The Obscured event is not fired in response to the incoming phone call if the screen is locked, however.  It would be impossible for us to have consistent behavior both while the screen is locked and unlocked.

As a result of these limitations, we decided to ignore the Obscured event altogether, and simply allow recording to continue while a phone call was taken.  Most users will likely dismiss incoming phone calls while recording, but if they take the call, at least their conversations will not be recorded.  (Instead a blank gap appears in the recorded audio.)  Hopefully future versions of WP7 offer more information about OS interruptions, so apps can respond in an intelligent manner dependent upon the source of the interruption.

Declaring Capabilities in WP7 Apps

If you’ve ever created a Windows Phone 7 application, you’re probably aware that before submitting for Marketplace approval you must enable only those “capabilities” that are actually being used.  Capabilities required by your app must be listed in the WMAppManifest.xml file, found in the Projects folder of your UI project.  For new solutions, all capabilities are by default included, as shown below:

	<Capabilities>
	  <Capability Name="ID_CAP_GAMERSERVICES"/>
	  <Capability Name="ID_CAP_IDENTITY_DEVICE"/>
	  <Capability Name="ID_CAP_IDENTITY_USER"/>
	  <Capability Name="ID_CAP_LOCATION"/>
	  <Capability Name="ID_CAP_MEDIALIB"/>
	  <Capability Name="ID_CAP_MICROPHONE"/>
	  <Capability Name="ID_CAP_NETWORKING"/>
	  <Capability Name="ID_CAP_PHONEDIALER"/>
	  <Capability Name="ID_CAP_PUSH_NOTIFICATION"/>
	  <Capability Name="ID_CAP_SENSORS"/>
	  <Capability Name="ID_CAP_WEBBROWSERCOMPONENT"/>
	  <Capability Name="ID_CAP_ISV_CAMERA"/>
	  <Capability Name="ID_CAP_CONTACTS"/>
	  <Capability Name="ID_CAP_APPOINTMENTS"/>
	</Capabilities>

If you include capabilities that are not actually used in your app, your submission to the marketplace will fail.  Fortunately, the Marketplace Test Kit (found via the context menu of the UI project in Visual Studio) can be used to verify what capabilities are required.  The “Capability Validation” result of the “Automated Tests” lists all capabilities used within you app.  The result below shows two capabilities used by an app.

Capabilities

Unfortunately, if you do not declare a capability that your app does actually use, you can easily run into trouble.  The automated tests of the Marketplace Test Kit will list all the capabilities that you make use of, but they will not indicate that you have missed a required capability.  The test will also still indicate a “passed” status, even though you have not declared a required capability.  Instead, functionality within your app can simply break, with no clear indication of the cause.

It’s usually best to leave all of the capabilities listed in the manifest file until you’re near the completion of your development, and then use the Marketplace Test Kit to determine which ones you can remove.  Since this is the typical development process, it’s unusual to encounter a problem.  If you’re starting with existing code, however, this can be the cause of a real headache.  Perhaps you’re returning to a solution you worked on earlier, in order to add new functionality.  Or perhaps you’ve started with a sample solution you came across online, expanding it with additional functionality.  In either case, if you add code that requires a capability no longer included in the manifest, you may end up chasing down bugs that don’t make much sense.

Recently I was exploring the possibilities of recording and playing back audio on WP7.  A quick search led me to a great starting point, in the form of a demo app for a WP7 voice recorder (http://www.codeproject.com/Articles/175122/Making-a-Voice-Recorder-on-Windows-Phone).  That solution uses the Microphone class of the XNA Framework for recording, and the XNA SoundEffect class for playback.  Although the SoundEffect class offers the interesting ability to adjust the pitch of the sound, it does not provide a way to specify the temporal position within the audio file.  I wanted a scrub bar to allow the user to move the playback position arbitrarily.  Switching to a MediaElement for playback would allow me to do this.

After making the appropriate changes, I was disappointed to find playback wasn’t working.  Subscribing to the MediaFailed event of the MediaElement revealed that a failure was occurring as soon as its source was set.  (The error message was the fairly useless “3100 An error has occurred”.)  After much digging around, I finally realized that MediaElement requires another WP7 capability (“ID_CAP_MEDIALIB”), and by introducing it into my project I needed to add the capability to my manifest file as well.

The lesson I learned is that if I’m starting with an existing WP7 solution and plan on making extensive changes, I should first visit the manifest file and make sure all capabilities are included.  This could prevent some serious debugging headaches.  Also, if I encounter bugs that don’t make much sense, it’s a good idea to run the automated tests of the Marketplace Test Kit, and ensure all capabilities listed in the results are included in the manifest file.  Only when I’m close to submitting for approval do I remove unnecessary capabilities from the manifest (and I comment them out, rather than remove them, making it easier to add them all back in if I revisit the code at a later time).