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

Windows Phone 7 - Part #6: Taking advantage of the phone

(5 votes)
Andrea Boschin
>
Andrea Boschin
Joined Nov 17, 2009
Articles:   91
Comments:   9
More Articles
1 comments   /   posted on Feb 22, 2011
Categories:   Windows Phone

This article is compatible with the latest version of Silverlight for Windows Phone 7.

This is part 6 from the article series on Windows Phone 7.

One thing you need to remember when you are writing an application for your phone is that it is running into a phone. It may seem clear and evident but since your hardware performs very good the differences between a mobile app and a normal desktop application are often subtle and indistinguishable. Giving a refresh to this awareness is often a way to make applications more user friendly and taking a lot of advantage from interactions that are phone-specific.

Up to this point you have always worked without any awareness of the device where you are running. Your phone is not a closed box: there are a lot of useful informations and tools you can rely on to write effective application. You can collect informations about the device, you can interact with the device software, and you obviously can handle the input of the user from the screen, not simply detecting "clicks" but relying on a full set of gestures. All these things make your work easy and your application well integrated with the underlying device.

Capture1Being aware of your device

Having a detailed knowledge of the device where your app is running may be useful. The Windows Phone 7 is currently a standardized operation system and there is very few differences between manufacturer and manufacturer but there are some cases you may need to know something about the underlying device. For this purpose it is available a class, named DeviceExtendesProperties, you can use to read these informations. The common usage of this class is to retrieve what is commonly named "device unique id", that is an array of 20 bytes that uniquely identify your device all over the world. Side by side with the DeviceExtendedProperties class you also have the UserExtendedProperties class that is able to provide only a single information about the user that have been registered into the device. This information is named "Anonymous Windows Live ID".

The very first thing you have to do, when you need to access these informations, is to ensure you have added two properties to the WPAppManifest.xml capabilities section. They are the ID_CAP_IDENTITY_DEVICE and ID_CAP_IDENTITY_USER flags that let you use the two classes without getting a security exception. The sole drawback of having these flags is that the marketplace will warn the people that download you app that the device requires to read the user sensible data. This is a little price to pay, and for sure a warranty for the final user that his data are not stolen.

<Capabilities>
    <Capability Name="ID_CAP_IDENTITY_DEVICE" />
    <Capability Name="ID_CAP_IDENTITY_USER" />
    <!-- add here other capabilities -->
</Capabilities>

Now you can use the GetValue and TryGetValue methods to read a number of variables using a string key to get the value. I strongly suggest the use of the TryGetValue method that tries to get the information and returns a boolean stating if the read was successful instead of raising an exception. You can find the detailed description of the DeviceExtendedProperties variables here.

The UserExtendedProperties, despite of the plural of the name, only lets you to get a variable named "ANID". This variable is a string that contains some values in the format of a querystring separated by the ampersand. The information we really need is a string of 32 chars starting at the position 2, representing an hexadecimal number that may be trasformed to a Guid. Here I've prepared a class that reads all these variables and exposes a typed property for each one.

public class Informations
{
    public System.String DeviceUniqueId 
    {
        get { return Convert.ToBase64String(GetDeviceProperty<byte[]>("DeviceUniqueId", false)); }
    }
 
    public System.String DeviceName
    {
        get { return GetDeviceProperty<System.String>("DeviceName", false); }
    }
 
    public System.String DeviceManufacturer
    {
        get { return GetDeviceProperty<System.String>("DeviceManufacturer", false); }
    }
 
    public System.String DeviceFirmwareVersion
    {
        get { return GetDeviceProperty<System.String>("DeviceFirmwareVersion", false); }
    }
 
    public System.String DeviceHardwareVersion
    {
        get { return GetDeviceProperty<System.String>("DeviceHardwareVersion", false); }
    }
 
    public System.Int64 DeviceTotalMemory
    {
        get { return GetDeviceProperty<System.Int64>("DeviceTotalMemory", false); }
    }
 
    public System.Int64 ApplicationCurrentMemoryUsage
    {
        get { return GetDeviceProperty<System.Int64>("ApplicationCurrentMemoryUsage", false); }
    }
 
    public System.Int64 ApplicationPeakMemoryUsage
    {
        get { return GetDeviceProperty<System.Int64>("DeviceTotalMemory", false); }
    }
 
    public System.Guid UserUniqueId
    {
        get { return this.GetANID(); }
    }
 
    private T GetDeviceProperty<T>(string name, bool isUserInfo)
    {
        object value;
        bool success = DeviceExtendedProperties.TryGetValue(name, out value);
        if (success) return (T)value;
        return default(T);
    }
 
    private Guid GetANID()
    {
        object value;
        bool success = UserExtendedProperties.TryGetValue("ANID", out value);
 
        if (success)
        {
            Match match = Regex.Match((string)value, "^A=(?<A>[0-9A-Fa-f]{8,8})(?<B>[0-9A-Fa-f]{4,4})(?<C>[0-9A-Fa-f]{4,4})(?<D>[0-9A-Fa-f]{4,4})(?<E>[0-9A-Fa-f]{12,12}).*$");
 
            return new Guid(
                match.Groups["A"].Value + "-" + 
                match.Groups["B"].Value + "-" + 
                match.Groups["C"].Value + "-" + 
                match.Groups["D"].Value + "-" + 
                match.Groups["E"].Value);
        };
 
        return Guid.Empty;
    }
}

The sole thing I would make evident is that since the Device unique ID is a byte array I user Convert.ToBase64String() to convert it into a base64 representation becausi this makes it more easily usable.

Launcher & Choosers

Your phone is a perfect place to run your Silverlight works, and there is a lot of areas you can provide of useful applications, tailored for specific purposes. That said you have to be aware that there are a set of tasks that the phone can execute side by side with your code, things that are supported directly from a set of system applications. Placing a call with your phone, writing an email or text message, visit a page with the browser. These and other features are all available into our phone for free, without the need of writing specific (and complex) procedures, thanks to the "Launchers & Choosers". Under this names there are a set of hooks that you can use to easily amalgamate your own code with the underlying system.

 

Launchers

Choosers

  • EmailComposeTask

  • MarketplaceDetailTask

  • MarketplaceHubTask

  • MarketplaceReviewTask

  • MarketplaceSearchTask

  • MediaPlayerLauncher

  • PhoneCallTask

  • SearchTask

  • SmsComposeTask

  • WebBrowserTask

  • CameraCaptureTask

  • EmailAddressChooserTask

  • PhoneNumberChooserTask

  • PhotoChooserTask

  • SaveEmailAddressTask

  • SavePhoneNumberTask

The list of tasks in the figure is the complete set of tools you can rely on. The difference between launchers and choosers is that the first are useful to start tasks that do not change the running application. Differently, the choosers are useful to peek up some informations that you can then elaborate into your app. To give an example, the WebBrowserTask launcher can be used to open an instance of a browser and show a web page. After the task has started there is nothing you app can do to interact with the browser and with the page it is showing. The PhotoChooserTask instead is a chooser and is able to peek up a photo from the media library and give you a stream to its content.

Starting a Launcher or a choosers is nothing complicated. You can do it with few lines of code. In this snippet, taken from the example attached to this article, I show how to open a PhotoChooserTask and a CameraCaptureTask to peek up an image:

private void choosePhotoItem_Click(object sender, EventArgs e)
{
    PhotoChooserTask chooser = new PhotoChooserTask();
    chooser.Completed += new EventHandler<PhotoResult>(chooser_Completed);
    chooser.ShowCamera = true;
    chooser.Show();
}
 
private void shootPhotoItem_Click(object sender, EventArgs e)
{
    CameraCaptureTask task = new CameraCaptureTask();
    task.Completed += new EventHandler<PhotoResult>(task_Completed);
    task.Show();
}
 
private void chooser_Completed(object sender, PhotoResult e)
{
    if (e.TaskResult == TaskResult.OK)
        this.LoadPhoto(e.ChosenPhoto);
}
 
private void task_Completed(object sender, PhotoResult e)
{
    if (e.TaskResult == TaskResult.OK)
        this.LoadPhoto(e.ChosenPhoto);
}

As you can see there is some properties you can specify to customize the behavior of the chooser. In this case specifing ShowCamera make the PhotoChooserTask able to choose pictures you have captured with the camera.

There is only a thing you must be careful when you use a chooser or a launcher. When you launch a task the OS can decide to tombstone your application due to the need of more resources, so you have to be aware of this an handle the lifetime events to save the state of the application and restore it when the returning back to it.

Handling gestures

Watch now your phone. It has a very big capacitive screen, also if it is one of the most economic, and from the specs you can read it support multitouch up to four points. This is for sure a very great opportunity for writing astounding applications that rely of the gestures that the user draws on the screen. CaptureUnfortunately once you try to handle the manipulation events, exposed by the UIElement class, you will find that getting rid of the raw informations you get from them is not an easy task. The manipulation events, named ManipulationStarted, ManipulationDelta and ManipulationCompleted, give you a huge number of data about what the user is doing on the screen, and if you use them it can give you a very detailed feedback. But, as usual, when you are developing an application your needs often does not need an so detailed stream of data, but simply you need to relay on some well-known gestures that are widely adopted. This makes your user already trained when he has to start using your software and the most of the times it is more than sufficent.

 

 

For this purpose, the team behind the Silverlight Toolkit added a useful GestureService that digest for you the stream coming from manipulation event and translate it into a set of gestures ready to be consumed by your applications. The available gestures are the following

Tap: it is the gesture of touching the screen a single time

Double-tap: As you can imagine it is raised when the user taps the screen two times fastly

DragStarted, DragDelta, and DragCompleted: These three events are raised when the user try to drag something using a single finger.

Flick: This is the gesture you usually use to close the notification popup of the text messages. A single and fast drag from the left to the right.

Hold: The same gesture that usually open the context menu on your phone. Hold a finger in a point for a while.

PinchStarted, PinchDelta, and PinchCompleted: these events detect the action made with two fingers to enlarge or restrict the distance between them. It is usually used to stretch or reduce images.

The example provided with the article is a simple puzzle game. You can pick an image from the media library and is broken in a 5x5 matrix of tiles. Then using gestures you can drag the tiles and recreate the puzzle. It is a good example of how to handle the gestures. First of all using the GestureService I retrieve the instance of the GestureListener and attach the event handlers.

GestureListener listener = GestureService.GetGestureListener(image);
listener.DragStarted += new EventHandler<DragStartedGestureEventArgs>(listener_DragStarted);
listener.DragDelta += new EventHandler<DragDeltaGestureEventArgs>(listener_DragDelta);
listener.DragCompleted += new EventHandler<DragCompletedGestureEventArgs>(listener_DragCompleted);

Now that the gestures is attached, I handle the three events and calculate the position of a tile on the basis of the data that are coming from the DragDelta event. I have the HorizontalChange and VerticalChange that gives me the delta between a sample and the previous.

private void listener_DragStarted(object sender, DragStartedGestureEventArgs e)
{
    Image image = sender as Image;
    Canvas.SetZIndex(image, 10000);
    this.Transform = new CompositeTransform();
    this.Transform.ScaleX = 1.3;
    this.Transform.ScaleY = 1.3;
    image.RenderTransform = this.Transform;
    image.RenderTransformOrigin = new Point(.5, .5);
}
 
private void listener_DragDelta(object sender, DragDeltaGestureEventArgs e)
{
    Point mouse = e.GetPosition(this.ContentPanel);
    Point position = this.GetPosition(mouse, e.HorizontalChange, e.VerticalChange);
    this.Transform.TranslateX += e.HorizontalChange;
    this.Transform.TranslateY += e.VerticalChange;
}
 
private void listener_DragCompleted(object sender, DragCompletedGestureEventArgs e)
{
    Image image = sender as Image;
    Canvas.SetZIndex(image, 1);
    image.RenderTransform = null;
    this.Transform = null;
 
    // continue swapping images...
}

You have only to be cautious when you need to use gestures for overlapped elements. The gesture service is unable to detect the overlapping so usually the events are raised also if the listened element is covered by another element. For this purpose you can only attach a GestureListener to the overlapped element and set the Handled property to true when you get the events.

Play the game

The game I've added to this article is funny. Thanks to the CameraCaptureTask it is simple to take a picture of your friend and then joke with them to recompose their images. But for us, the most enjoyable part is writing our applications and the toolset we have spoken about today is for sure a good friend for our games. Have a good play.

Download the source code
 

About the Author

Andrea BoschinAndrea Boschin is 41 years old from Italy and currently lives and works in Treviso, a beautiful town near Venice. He started to work in the IT relatively late after doing some various jobs like graphic designer and school teacher. Finally he started to work into the web and learned by himself to program in VB and ASP and later in C# and ASP.NET. Since the start of his work, Andrea found he likes to learn new technologies and take them into the real world. This happened with ASP.NET, the source of his first two MVP awards, and recently with Silverlight, that he started to use from the v1.0 in some real projects.
 


Subscribe

Comments

  • kamalrawat

    Re: Windows Phone 7 - Part #6: Taking advantage of the phone


    posted by kamalrawat on Jan 25, 2012 07:31

    I would like to thank Andrea for this wonderful article which helped me a lot to understand the facts...It is a nice article series for new learners and lead to us a great development using WindowsPhone7.

Add Comment

Login to comment:
  *      *       

From this series