Windows Phone 7 – Emulator Automation

Justin Angel picture

Justin
Angel

Hi Folks,

In this next blog post we’ll review how to automate the Windows Phone 7 Emulator and what are some real-world usages this technique.

Windows Phone 7 Unlocked Windows Phone 7 Emulatoe

This blog post is the second blog post in a series of unrelated advanced Windows Phone 7 blog posts.
The previous blog post in this series is “Windows Phone 7 – Unlocked ROMs”.

 

Why is Windows Phone 7 Automation Important?

Currently, the Windows Phone 7 Emulator can only launch developer packages (XAPs) from inside Visual Studio 2010.
Meaning, if we’ve got a XAP we can’t get the emulator to load it without Visual Studio.

As we’ve seen in a previous blog post the emulator can be launched and even installed on machines that do not have Visual Studio. More on that here.
Let’s consider that in order to load XAPs into the Emulator we currently have to use Visual Studio. 

Developers use Visual Studio to run the WP7 Emulator

The problem is – How do we load XAPs into WP7 Emulators and Devices without using Visual Studio?

So how does our Build Server run nightly tests? Or how do our customers see our applications?

Customers and Build server don't have Visual Studio 2010.

Customers and Build servers don't have Visual Studio 2010 installed.

So, how can we deploy XAPs to an emulator running on these machines?

 

Quit your Jibber-Jabber, show me how to automate the WP7 emulator!

Let’s create a new solution with a Console Application and a Windows Phone 7 Project.

image

We’ll use the ConsoleApplication as our automation harness that can run on any computer with the .Net framework.
The WindowsPhone Application is the application whose deployment we’ll automate.

 

The CoreCon 10 WP7 API

The secret sauce for WP7 Automation is the CoreCon API.
These CoreCon DLLs have been in deep hibernation since 2007 when they last got a major upgrade.
For WP7 Tools the CoreCon API has been updated and are used by Visual Studio 2010 when deploying applications to WP7 devices and emulators.

Let’s add a reference to Microsoft.SmartDevice.Connectivity.dll from the CoreCon API.
On a x64 developer box, the DLL can be found at: C:\Program Files (x86)\Common Files\microsoft shared\Phone Tools\CoreCon\10.0\Bin\Microsoft.Smartdevice.Connectivity.dll 

image 

 

Now that we have the CoreCon DLL reference in place, we can start automating WP7.

Here’s the User Experience we’re aiming for in this demo:

Windows Phone 7 Emulator launched by CMD Automation from a Console app

We’ll have to build the following workflow:

WP7 Automation Diagram - Get WP7 CoreCon SDK     

We’ll start off by getting an instance of the WP7 CoreCon SDK instance to work with:

// Get CoreCon WP7 SDK

DatastoreManager dsmgrObj = new DatastoreManager(1033);

 

Platform WP7SDK = dsmgrObj.GetPlatforms().Single(p => p.Name == "New Windows Mobile 7 SDK");

 WP7 Automation Diagram - Get WP7 Emulator / Device

Next up we’ll have to get a reference to either a WP7 physical device or a WP7 Emulator.
This demo will use the emulator, but if we set “useEmulator = false” this demo will try and connect to a physical WP7 device.

// Get Emulator / Device

bool useEmulator = true;

Device WP7Device = null;

if (useEmulator)

    WP7Device = WP7SDK.GetDevices().Single(d => d.Name == "Windows Phone 7 Emulator");

else

    WP7Device = WP7SDK.GetDevices().Single(d => d.Name == "Windows Phone 7 Device");

WP7 Automation Diagram - Connect to Emulator / Device

Now we’ll launch the WP7 Emulator/Device.
Note that the default WP7 Emulator Image is the one we’ll launch into, and in a previous blog post I’ve explained how to use the Unlocked ROM as the default ROM.

// Connect to WP7 Emulator / Device

Console.WriteLine("Connecting to Windows Phone 7 Emulator/Device...");

WP7Device.Connect();

Console.WriteLine("Windows Phone 7 Emulator/Device Connected...");

WP7 Automation Diagram - Uninstall previous versions

Next, we’ll have to check if our application is already installed, and if it is – we’ll uninstall it.
Since the the UpdateApplication Method in the current CoreCon API doesn’t work, this is our best bet on easily updating installed apps.

In order to Install or Uninstall our application, we’ll need it’s Application Product Identifier (GUID).
We can get the application GUID from the Properties/WMAppManifest.xml file.

 Visual Studio with the WMAppManifest.xml file open

We’ll write the code to check if an application is installed, and if it is – we’ll uninstall it.

Guid appID = new Guid("{5e75bba1-fbf6-463c-94ac-fa4a78f8fd12}");

RemoteApplication app;

if (WP7Device.IsApplicationInstalled(appID))

{

    Console.WriteLine("Uninstalling sample XAP to Windows Phone 7 Emulator/Device...");

 

    app = WP7Device.GetApplication(appID);

    app.Uninstall();

 

    Console.WriteLine("Sample XAP Uninstalled from Windows Phone 7 Emulator/Device...");

}

WP7 Automation Diagram - Install XAP

At this point, we’ll install our XAP.
In order to do that, we’ll need 3 pieces of information:
1. The location of our XAP.
2. The Application GUID.
3. The location of the application icon.

// Install XAP

Console.WriteLine("Installing sample XAP to Windows Phone 7 Emulator/Device...");

 

app = WP7Device.InstallApplication(

    appID,

    appID,

    "NormalApp",

    @"D:\visual studio 2010\Projects\ConsoleApplication1\WindowsPhoneApplication1\ApplicationIcon.png",

    @"D:\visual studio 2010\Projects\ConsoleApplication1\WindowsPhoneApplication1\Bin\Debug\WindowsPhoneApplication1.xap");

 

Console.WriteLine("Sample XAP installed to Windows Phone 7 Emulator...");

WP7 Automation Diagram - Launch Application

The last step is to actually launch our application.

// Launch Application

Console.WriteLine("Launching sample app on Windows Phone 7 Emulator...");

app.Launch();

Console.WriteLine("Launched sample app on Windows Phone 7 Emulator...");

 

We’re done. And indeed when we run our sample application the app runs as expected:

Windows Phone 7 Emulator launched by CMD Automation from a Console app

 

So What is WP7 Automation good for?

There’s a lot of good use cases: Automating Unit tests, Loading Nightly builds into the emulator and even letting customers use the WP7 Emulator.
There’s really a plethora of reasons and situations WP7 Automation can prove useful in and it’s up to you to figure it out for your projects.

For instance in Vertigo, we’re using the WP7 Automation harness to run the WP7 Emulator on multi-touch laptops that our customers have.
So Vertigo’s customers, as part of an iterative process, get access to our current build without having to install or use Visual Studio 2010.

 

Access to Isolated Storage

One use-case in particular interests me, which is automating running all unit tests in the project after a Continuous Integration nightly build.

Windows Phone 7 running unit tests, courtesy of Jeff Wilcox

We can pretty much do all of the work to automate WP7 tests using WP7 Automation we’ve seen so far, but how do we get results into application? Or get instructions in?

The easiest method I can think off is communicate through cold storage – read & write files into Isolated Storage.

Isolated Storage communication strategy diagram

We’ll start off by writing a file into our WP7 Application IsoStore.
Remember that this code executes in the WP7 Emulator/Device.

public MainPage()

{

    InitializeComponent();

 

    SupportedOrientations = SupportedPageOrientation.Portrait | SupportedPageOrientation.Landscape;

 

    using (var isoStore = IsolatedStorageFile.GetUserStoreForApplication())

    using (var sw = new StreamWriter(isoStore.OpenFile("Foo.txt", FileMode.OpenOrCreate, FileAccess.Write)))

    {

        sw.Write("Hello WP7! (Written from WP7 IsoStore, read by Console Harness!)");

    }

}

Basically, We’ve written a Foo.txt file into our IsoStore and added some text into it.

Next, we would have used the RemoteIsolatedStorage class and get access to the emulator IsoStore, but that has not been enabled yet in CoreCon10.

Reflector showing GetIsolatedStorage throwing an exception

We would have used RemoteApplication.GetIsolatedStorage() but that has not been implemented yet.

We’ll use a FileDeployer class instead.
There’s some reflection magic associated with getting a copy of a FileDeployer class that can be used for our application.

Thread.Sleep(10000);

//app.GetIsolatedStore(); <-- Throws NotImplementedException

object ConManServer = WP7Device.GetType().GetField("mConmanServer", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(WP7Device);

FileDeployer f = (FileDeployer)typeof(FileDeployer).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0].Invoke(new object[] { ConManServer });

Next, we’ll copy the Foo.txt file from the application isolated storage into our local binary folder and read it into the console:

f.ReceiveFile(@"\Applications\Data\" + appID + @"\data\isolatedstore\Foo.txt", @"\Foo.txt");

 

Console.WriteLine("\t" + File.ReadAllText(@"foo.txt"));

 

When we run this sample we can see the text written from IsoStore showing up on our console.

Windows Phone 7 Emulator Automation reading from IsoStore

And we’re done, we’ve esteblished a two-way communication channel between WP7 Emulator/Device and Managed .net code.  

 

Console WP7 Automation Harness Source Code

Here’s the source code we’ve built in this project:

// Get CoreCon WP7 SDK

DatastoreManager dsmgrObj = new DatastoreManager(1033);

 

Platform WP7SDK = dsmgrObj.GetPlatforms().Single(p => p.Name == "New Windows Mobile 7 SDK");

 

// Get Emulator / Device

bool useEmulator = true;

Device WP7Device = null;

if (useEmulator)

    WP7Device = WP7SDK.GetDevices().Single(d => d.Name == "Windows Phone 7 Emulator");

else

    WP7Device = WP7SDK.GetDevices().Single(d => d.Name == "Windows Phone 7 Device");

 

// Connect to WP7 Emulator / Device

Console.WriteLine("Connecting to Windows Phone 7 Emulator/Device...");

WP7Device.Connect();

Console.WriteLine("Windows Phone 7 Emulator/Device Connected...");

 

 

Guid appID = new Guid("{5e75bba1-fbf6-463c-94ac-fa4a78f8fd12}");

RemoteApplication app;

if (WP7Device.IsApplicationInstalled(appID))

{

    Console.WriteLine("Uninstalling sample XAP to Windows Phone 7 Emulator/Device...");

 

    app = WP7Device.GetApplication(appID);

    app.Uninstall();

 

    Console.WriteLine("Sample XAP Uninstalled from Windows Phone 7 Emulator/Device...");

}

 

// Install XAP

Console.WriteLine("Installing sample XAP to Windows Phone 7 Emulator/Device...");

 

app = WP7Device.InstallApplication(

    appID,

    appID,

    "NormalApp",

    @"D:\visual studio 2010\Projects\ConsoleApplication1\WindowsPhoneApplication1\ApplicationIcon.png",

    @"D:\visual studio 2010\Projects\ConsoleApplication1\WindowsPhoneApplication1\Bin\Debug\WindowsPhoneApplication1.xap");

 

Console.WriteLine("Sample XAP installed to Windows Phone 7 Emulator...");

 

// Launch Application

Console.WriteLine("Launching sample app on Windows Phone 7 Emulator...");

app.Launch();

Console.WriteLine("Launched sample app on Windows Phone 7 Emulator...");

 

Console.WriteLine("Reading Foo.txt Isolated Storage file:");

 

Thread.Sleep(10000);

//app.GetIsolatedStore(); <-- Throws NotImplementedException

object ConManServer = WP7Device.GetType().GetField("mConmanServer", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(WP7Device);

FileDeployer f = (FileDeployer)typeof(FileDeployer).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0].Invoke(new object[] { ConManServer });

f.ReceiveFile(@"\Applications\Data\" + appID + @"\data\isolatedstore\Foo.txt", @"\Foo.txt");

 

Console.WriteLine("\t" + File.ReadAllText(@"foo.txt"));

 

Console.ReadLine();

 

Fin

In this blog post we’ve talked about why Automating the WP7 Emulator and Device deployment process is important and how to go about doing that.
Hopefully now you know how to automate WP7 XAP Deployment.

In the next blog post in this series we’ll talk about setting up a Continuous Integration build for WP7.

 

Leave a Comment

Are there any other use cases for WP7 Automation?
Are you planning on using this technique somewhere?
Was this a good blog post? Sound off in the comments.

 

Sincerely,

-- Justin Angel



Comments