(X) Hide this
    • Login
    • Join
      • Say No Bots Generate New Image
        By clicking 'Register' you accept the terms of use .

Windows Phone 7.5 - Accessing your phone

(3 votes)
Andrea Boschin
>
Andrea Boschin
Joined Nov 17, 2009
Articles:   91
Comments:   9
More Articles
1 comments   /   posted on Oct 24, 2011
Categories:   Windows Phone
Tweet This!

At the start of this year, on February, I wrote an article about the programmatic interaction with the phone services, with the title "Taking advantage of the phone".

In that article I explored a bunch of features that enabled you to interact with some parts of the operating system with Launchers & Choosers, and getting informations about the device and the user. With the new release of the Windows Phone 7.5, these features has been expanded, with the addition of lot of new "handles" you can use to programmatically access informations and change them. In this article I would like to give you a brief resume of these improvements that grant you new opportunities to better integrate your applications with the phone environment.  

Download the source code

Accessing phone information with DeviceStatus

A number of the information about the device hardware and status are now exposed throught a new static class called DeviceStatus. Differently from the old DeviceExtendedProperties this class exposes some strongly types properties that simplify the code and add interesting data. So, as and example, to access the DeviceName you can now write a single line: Here is the comparison between OS 7.0 and OS 7.5

 1: // OS 7.0 --------------------------------
 2:  
 3: object value;
 4:  
 5: bool success = DeviceExtendedProperties.TryGetValue("DeviceName", out value);
 6:  
 7: if (success) 
 8:     MessageBox.Show(value.ToString());
 9: else
 10:     MessageBox.Show("Unable to retrieve value");
 11:  
 12: // OS 7.5 --------------------------------
 13:  
 14: MessageBox.Show(DeviceStatus.DeviceName);
 15:  

Side by side with this useful but not life-changing feature, the new OS 7.5 take some new properties and events. These properties allow you to react to the presence of an external keyboard, to its deploment and to the change of the power source. Knowing about the keybord may be key to decide about the presentation of your user interface, and knowing about the power source can impact the behavior of an application that , as an example, is running under the locked screen. Detecting these changes is really simple as it is attaching an event, but you have to know that the event is not raised on the UI thread so you have to use the dispatcher to update the user interface.

 1: public PhoneInfo()
 2: {
 3:     InitializeComponent();
 4:  
 5:     DeviceStatus.KeyboardDeployedChanged += new EventHandler(DeviceStatus_KeyboardDeployedChanged);
 6:     DeviceStatus.PowerSourceChanged += new EventHandler(DeviceStatus_PowerSourceChanged);
 7: }
 8:  
 9: public void DeviceStatus_PowerSourceChanged(object sender, EventArgs e)
 10: {
 11:     this.Data.Dispatcher.BeginInvoke(this.Load);
 12: }
 13:  
 14: public void DeviceStatus_KeyboardDeployedChanged(object sender, EventArgs e)
 15: {
 16:     this.Data.Dispatcher.BeginInvoke(this.Load);
 17: }
 18:  
 19: public void Load()
 20: {
 21:     // update here te user interface
 22: }

New Launchers and Choosers

As you remember for sure Launchers & Choosers are useful tools that let you interact with various services provided by the phone. With Launchers you can start something that do not return anything to your application. A simple example is given by the EmailComposeTask. It allows to start writing an email with the configured client and you do not have to expect any result from it. On the other side Choosers, like the name suggest, are useful to choose something into your phone. EmailAddressChooserTask lets you scan the address book searching for email address and obviously it returns the found address.

With OS 7.5 there are a small set of Launchers and Chooser added but they give some useful tasks. Here is the updated table containing the new tasks in red:

 

 

 

 

 

 

 

 

 

 

 

 

 

Under the Launchers category we see the new Bing Maps services. They lets you open the mapping application at a given position and getting directions betweek two points. The last one starts the mapping application loading a route between the provided coordinates and initiate a navigation. When you are in a location where this service is enabled you will ear the voice suggesting directions while driving.

On the side of the Choosers you can finally add a contact to the address book using the SaveContactTask, search for an address in the same way you can search for a number with AddressChooserTask, start a game invitation with the GameInviteTask and save a ringtone to the media library. The SaveRingToneTask require you specify the file to add respecting the following constraints:

  • Ringtone files must be of type MP3 or WMA.

  • Ringtone files must be less than 40 seconds in length.

  • Ringtone files must not have digital rights management (DRM) protection.

  • Ringtone files must be less than 1 MB in size.

After you add the ringtone it is available in the Settings page where you can choose a tone for the phone. Please be aware that the ringtone is only available for incoming calls and not for all the other notifications like SMS, Email and so on.

Some of these choosers may seems to be launchers because you don't expect any result from them (e.g. the SaveRingtoneTask) but they are really choosers because they returns the result of the operation with a possible exception occured.

In the following sample I show how to use the AddressChooserTask and BingMapsDirectionsTasks to make a route between two of your contacs.

 1: public partial class UsingLaunchers : PhoneApplicationPage
 2: {
 3:     public AddressChooserTask ChooseStart { get; set; }
 4:     private string StartAddress { get; set; }
 5:     private string StartLabel { get; set; }
 6:     public AddressChooserTask ChooseEnd { get; set; }
 7:     private string EndAddress { get; set; }
 8:     private string EndLabel { get; set; }
 9:  
 10:     public UsingLaunchers()
 11:     {
 12:         InitializeComponent();
 13:  
 14:         this.ChooseStart = new AddressChooserTask();
 15:         this.ChooseStart.Completed += new EventHandler<AddressResult>(chooseStart_Completed);
 16:  
 17:         this.ChooseEnd = new AddressChooserTask();
 18:         this.ChooseEnd.Completed += new EventHandler<AddressResult>(chooseEnd_Completed);
 19:     }
 20:  
 21:     void chooseStart_Completed(object sender, AddressResult e)
 22:     {
 23:         if (e.Error == null)
 24:         {
 25:             this.txtStart.Text = 
 26:                 this.StartAddress = e.Address;
 27:             this.StartLabel = e.DisplayName;
 28:         }
 29:     }
 30:  
 31:     void chooseEnd_Completed(object sender, AddressResult e)
 32:     {
 33:         if (e.Error == null)
 34:         {
 35:             this.txtEnd.Text =
 36:                 this.EndAddress = e.Address;
 37:             this.EndLabel = e.DisplayName;
 38:         }
 39:     }
 40:  
 41:     private void bSearchDirections_Click(object sender, RoutedEventArgs e)
 42:     {
 43:         if (!string.IsNullOrEmpty(this.StartAddress) &&
 44:             !string.IsNullOrEmpty(this.EndLabel))
 45:         {
 46:             GeoCoordinate start = 
 47:                 this.GeoCodeAddress(this.StartAddress);
 48:             GeoCoordinate end = 
 49:                 this.GeoCodeAddress(this.EndAddress);
 50:  
 51:             BingMapsDirectionsTask task = new BingMapsDirectionsTask
 52:             {
 53:                 Start = new LabeledMapLocation
 54:                             {
 55:                                 Label = this.StartLabel,
 56:                                 Location = start
 57:                             },
 58:                 End = new LabeledMapLocation
 59:                         {
 60:                             Label = this.EndLabel,
 61:                             Location = end
 62:                         }
 63:             };
 64:  
 65:             task.Show();
 66:         }
 67:     }
 68:  
 69:     private GeoCoordinate GeoCodeAddress(string address)
 70:     {
 71:         // TODO: implement here a GeoCoding service to get coordinates from address
 72:         return new GeoCoordinate();
 73:     }
 74:  
 75:     private void bChooseStart_Click(object sender, RoutedEventArgs e)
 76:     {
 77:         this.ChooseStart.Show();
 78:     }
 79:  
 80:     private void bChooseEnd_Click(object sender, RoutedEventArgs e)
 81:     {
 82:         this.ChooseEnd.Show();
 83:     }
 84: }

 

Please pay attention I have not implemented a GeoCoding of the addresses retrieved from the AddressChooserTask. You have to do this for example using the Bing Maps Geocoding Service but it requires you subscribe to the service for a developer key before to place a call to the online services.

Accessing Contacts and Appointments

Using a Chooser to search for an Address is for sure a good thing but sometimes it may happen you want to directly integrate the contacts into your applications. With the new OS 7.5 it is now possible to enumerate the contacts and directly access their information. The Contacts class provide a way to start searches into contacts and then display results with a detailed object model that exposes almost every available information. These searches span over different accounts you added to your phone and, infact, you have an Accounts property that let you know what are the accounts you are searching over. Unfortunately there is not any way of searching over one of the catalogs but the SearchAsync method always start the search over all the accounts.

To make a search you have to create an instance of the Contacts class then use the StartAsync method providing the search key and the field you want to use for your search. The search key changes its meaning depending on the field you are searching. If you search the DisplayName it is used as a LIKE criteria but if you search for an EmailAddress the part before the @ is searched by start and the other part performs a smart matching trying various combinations. The following box shows how to search contacts by DisplayName

 1: private void Button_Click(object sender, RoutedEventArgs e)
 2: {
 3:     string searchKey = this.SearchKey.Text;
 4:  
 5:     Contacts contacts = new Contacts();
 6:     contacts.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(contacts_SearchCompleted);
 7:     contacts.SearchAsync(searchKey, FilterKind.DisplayName, null);
 8: }
 9:  
 10: private void contacts_SearchCompleted(object sender, ContactsSearchEventArgs e)
 11: {        
 12:     this.MyContacts.ItemsSource = e.Results;            
 13: }

After you got the contacts you can access the information stored in the result set and perform linq queries with LinqToObjects. The set is really complete and includes lot of collections with PhoneNumbers, EmailAddresses, and so on. In the following box I display the PhoneNumbers collection when the item is selected in the ListBox

 1: private void MyContacts_SelectionChanged(object sender, SelectionChangedEventArgs e)
 2: {
 3:     Contact contact = this.MyContacts.SelectedValue as Contact;
 4:  
 5:     if (contact != null)
 6:         this.MyContactsNumbers.ItemsSource = contact.PhoneNumbers;
 7:     else
 8:         this.MyContactsNumbers.ItemsSource = Enumerable.Empty<Contact>();
 9: }

In this case each phone number has a Kind property that let you know if the number is registered as a Mobile, Work, etc... From the Contacts result set you are also able to access the picture if it is available. Using the GetPicture method you get a stream to the image or "null" of the picture is not available. Here is the previous method changed to also diplay the contact picture:

 1: private void MyContacts_SelectionChanged(object sender, SelectionChangedEventArgs e)
 2: {
 3:     Contact contact = this.MyContacts.SelectedValue as Contact;
 4:  
 5:     if (contact != null)
 6:     {
 7:         Stream picture = contact.GetPicture();
 8:  
 9:         if (picture != null)
 10:         {
 11:             BitmapImage image = new BitmapImage();
 12:             image.SetSource(picture);
 13:             this.MyContactsImage.Source = image;
 14:         }
 15:         else
 16:             this.MyContactsImage.Source = null;
 17:  
 18:         this.MyContactsNumbers.ItemsSource = contact.PhoneNumbers;
 19:     }
 20:     else
 21:     {
 22:         this.MyContactsImage.Source = null;
 23:         this.MyContactsNumbers.ItemsSource = Enumerable.Empty<Contact>();
 24:     }
 25: }

The same way you can access contacts you can also access appointments. Using the Appointments class you can scan the calendar of the phone to integrate your application with it. The way you perform searches is very similar to contacts but you have to provide a timeframe. In the following snippet I make a search for the current week.

 1: void AppointmentsExplorer_Loaded(object sender, RoutedEventArgs e)
 2: {
 3:     DateTime start = DateTime.Today.Subtract(
 4:         TimeSpan.FromDays((int)DateTime.Today.DayOfWeek));
 5:  
 6:     Appointments appointment = new Appointments();
 7:     appointment.SearchCompleted += new EventHandler<AppointmentsSearchEventArgs>(appointment_SearchCompleted);
 8:     appointment.SearchAsync(start, start.AddDays(7), 100, null);
 9: }
 10:  
 11: void appointment_SearchCompleted(object sender, AppointmentsSearchEventArgs e)
 12: {
 13:     this.MyAppointments.ItemsSource = e.Results;            
 14: }

The SearchAsync method has various overloads and in this case you are able to make your search on a specific account providing an instance from the Accounts property.

Considerations

The changes I've explained in this article are someway good because they simplify some tasks and add interesting features. The sole problem to me is the read-only access to calendar and appointments. In my opinion the read-only access to the store is good for contacts by I preferred to have a read-write access to the calendar to be able to add appointments from an application. I'm able to figure out a wide set of cases where this would be a beautiful feature.


Subscribe

Comments

  • PrzemyslawSoszynski

    Re: Windows Phone 7.5 - Accessing your phone


    posted by PrzemyslawSoszynski on Oct 27, 2011 16:42

    Hi. very good article. When I am trying to print it, only visible parts of the code show up!

    regards, Przemek

Add Comment

Login to comment:
  *      *       

From this series