Nick's .NET Travels

Continually looking for the yellow brick road so I can catch me a wizard....

Windows Mobile 6.5 + Exchange 2010 + Outlook 2010 = Desktop SMS Messaging

This is awesome! My Exchange account over at www.myhostedsolution.com has been migrated to their new Exchange 2010 hosting servers. This means that I can finally do SMS synchronisation between my mobile, running Windows Mobile 6.5, and my Inbox. Better still, with Outlook 2010 I can both view and reply to SMS messages from within Outlook. All of this without having to configure any additional settings or services.

Here are the few steps you have to do.

  1. Upgrade your Exchange account to Exchange 2010. If you set up hosting with www.myhostedsolution.com you get this included in you subscription for free by default. Did I mention they have unlimited storage so is awesome value.
  2. Go into ActiveSync on your Windows Mobile 6.5 device and enable synchronization of Text Messages. This should enable synchronization of your text messages with your Exchange 2010 server. When I first upgraded to Exchange 2010 the option to synchronize text messages didn’t appear in ActiveSync on my device so I ended up wiping the device and setting up the account again.
    image
  3. The next piece is to install or upgrade to Outlook 2010. This sports a much newer interface, including the ability to send SMS messages. After installing and configuring your account (or if you’re upgrading, after your data file has been upgraded) you should see an email from Outlook 2010 entitled “Send and receive text messages on your computer!” which indicates that your mobile device is synchronizing text messages and Outlook is ready to send messages.

Sending Text Messages from Outlook 2010

From the New Items drop down select Text Message (SMS)
image

This will open the Text Message window where you can enter your message. Note the list of emoticons in the ribbon.

image

Once you’ve written your message, hit Send. When your device next synchronizes you should see a notification that your SMS message has been sent. That’s right, Outlook 2010 synchronizes the message to be sent to Exchange 2010, which then synchronizes it to your mobile device, which then sends it using your mobile phone account. No additional services necessary!

image

If you get an SMS Message it will be synchronized to Exchange 2010, then on to Outlook 2010, appearing in your Inbox along with your email. Careful if you’re working for an organisation that monitors email as your text messages will now be accessible to your Exchange administrators.

image

You can of course reply to an SMS and it will be sent out again via Exchange, Outlook…. your device. You do need to make sure your device is synchronizing, otherwise your SMS messages won’t be sent.

Disabling Debugging Security for Windows Mobile

Every time I get a new device I go through almost one debug cycle before I’ve had enough and decide to disable the Windows Mobile security. If you aren’t familiar with Windows Mobile security there are essentially one (for pocketpc/Windows Mobile Professional) or two levels (for smartphone/Windows Mobile Standard). In both cases, if security is enabled the device will prompt you, as in the following screenshot, to allow untrusted assemblies to run on the device. Of course, this includes a number of assemblies that are used during debugging, so a royal pain to have to click Yes for each assembly that is loaded.

image

The easiest way to disable this “feature” is to use the Device Security Manager that comes with Visual Studio 2008 (Tools –> Device Security Manager). So long as your device is connected via ActiveSync or Windows Mobile Device Center you should see a display similar to the next image ��� this shows my device with Prompt One Tier as the current setting.

image

Selecting “Security Off” and hitting the Deploy to Device means that I can easily debug applications without having to click Yes to those annoying prompts.

image

Happy coding…..

BeeMobile4.NET Gets Designer Support in Visual Studio for Windows Mobile Applications

I’ve just been in contact with the team at BeeMobile4.net and they told me that they now have full designer support within Visual Studio 2005 and Visual Studio 2008 for all their controls. When you purchase their iPack you not only get all their controls but the ability to use them from the toolbox in Visual Studio. Of course, since Windows Mobile application development isn’t supported in Visual Studio 2010 their controls don’t appear there!

Here’s a quick walk through of the experience. Firstly, love the installation process – good attention to detail through the install process.

image

Once installed I was amazed by the number of controls they now have on offer.

image

Rather than go through each of the controls in painful detail I downloaded their sample application that showcases all the controls:

image image image

Here you can see a splash screen with an on screen progress bar and a semi-transparent header. The next image includes two main regions including a list, all with transparency so you can see the background. The third image shows you their semi-transparent message box – this is configurable to control both the text, opacity and the buttons displayed.

imageimage

  image image

These four images just show some of the other controls in action.

If you’re doing Windows Mobile development I’d highly recommend these controls as a great starting point to make your application look amazing. Also, if you have other specific control requirements, contact the team at BeeMobile4.Net as they are able to build controls to suit your requirements.

Windows Mobile Marketplace gets Deep Linking on Device

For quite a while now you have been able to deep link to your application listed on Marketplace using a url of the form https://marketplace.windowsphone.com/details.aspx?appId=LinkID where the LinkID is unique to your application.  If you want to find the LinkID for any application you simply need to find it in the marketplace and then look in the address bar. Depending on how you found your application you will most likely have a url similar to:

http://marketplace.windowsphone.com/details.aspx?appId=89c01d91-48a1-4e09-895e-74db2ced5345&retURL=/search.aspx%3Fkeywords%3Dcricket

As you can see this is essentially a deep link with some additional information on the end of it. Simply strip off all the extra parameters to give you a deep link that you can use.

http://marketplace.windowsphone.com/details.aspx?appId=89c01d91-48a1-4e09-895e-74db2ced5345

Now when it comes to providing a deep link on the device I think the team has completely missed the point. In the post Drive App Downloads with Marketplace Deeplinking they shown how you can invoke the marketplace client application on the device, passing in the LinkID of the application as follows:

System.Diagnostics.Process.Start("\\Windows\\WMMarketplaceFullClient.exe", "/appid:LinkID");

Now I had to double read this… surely the only way to do something like this would be to have an application already running on the device… and doesn’t that imply that the user already has your application installed on the device… which means they’ve probably already been to marketplace, found, purchased and installed your application… what’s the point in providing this mechanism????

Ok, in answer to that question I can see that if you have multiple Windows Mobile applications in marketplace then you can increase sales by providing cross links between your applications. That way once someone buys one of your applications, they are more likely to buy the others. Alternatively you could provide a free/trial version with a link to the paid version.

Personally I see that there is an obvious gap here – how do I provide a deep link to my application on a mobile web site (or even a standard web site that is accessible via a WM device) that can be resolved on the device via the marketplace client. It wouldn’t be out of the question to have a link such as wmapp://LinkID that would be handled by the marketplace client in order to display the appropriate application. This link could be used when the site detects the page being browsed by a windows mobile client.

Getting Started with OpenGL on Windows Mobile

There are a number of good posts on working with OpenGL on Windows Mobile via the .NET Compact Framework but one thing I’ve noticed is that they don’t really try to wrap the OpenGL functionality in a way that makes it reusable as an application/game framework. Mostly the logic for rendering was intermingled with windows forms logic, such as OnPaint, which was intermingled with logic for updating the current scene. If you look at say XNA you notice that the model is very simple – essentially they have a single run loop consisting of Update and Draw. I set out to update the OpenGL ES wrapper initially provided by Koushik Dutta and since extended with some great examples across at XDA Developers. Here’s what I came up with to start with.

If you grab the OpenGL ES wrapper you will notice that at its core is essentially a single Windows Form that handles the OnPaint method in order to draw using OpenGL primitives. Nearly all the computation and rendering is done in this method. In the constructor and subsequent initialization methods there are a number of OpenGL ES calls in order to setup the display, surface and context required in order for OpenGL to draw to the screen. In order to create a reusable framework that would be a starting point for any project undertaken in OpenGL all this code would have to be wrapped in a way that it doesn’t need to be duplicated for each project.

I decided to go down the path of creating an abstract form which I called the ApplicationForm. This form has three virtual methods that the overriding form needs to implement:

protected virtual void SetupScene(){}

protected virtual void UpdateScene(float secondsSinceLastUpdate){}

protected virtual void DrawScene(){}

As you can imagine these form the basis of the Draw-Update rendering loop. Of course SetupScene is called prior to the first iteration of this loop to ensure the scene is correctly setup before the first call to Draw. Unlike some implementations which rely on a For/While loop and DoEvents (to allow windows events to be processed) I went with the approach that works in conjunction with the existing windows message pump. When the form needs to be painted the OnPaint method is invoked:

protected override void OnPaint(PaintEventArgs e)
       {
           base.OnPaint(e);

           // Draw the current scene
           RunDrawScene();

           egl.SwapBuffers(_display, _surface);
           gl.Clear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT);

           // Update the current scene
           RunUpdateScene();
       }

As you can see this does a single pass of the rendering loop.  What’s interesting is the implementation of the RunUpdateScene method:

private void RunUpdateScene()
       {
           // Check for running instance - exit if already running
           if (Interlocked.CompareExchange(ref isUpdating, 1, 0) == 1)
           {
               return;
           }

           // Only instance running, so create the thread in which to
           // invoke the UpdateScene method
           ThreadPool.QueueUserWorkItem((async) =>
           {
               try
               {
                   // Calculate the time in seconds since last update
                   var seconds = (float)Environment.TickCount/1000.0f;
                   var diff = 0.0f;
                   if (this.lastUpdate > 0)
                   {
                       diff = seconds - this.lastUpdate;
                   }
                   this.lastUpdate = seconds;

                   // Invoke the virtual UpdateScene method
                   UpdateScene(diff);
               }
               finally
               {
                   // Make sure this method can be re-entered
                   Interlocked.Decrement(ref isUpdating);

                   // Invoke "Invalidate" on the control which will cause
                   // the control to be refreshed (ie OnPaint called) leading
                   // to another iteration of Draw and Update
                   this.BeginInvoke((Action)(() => { Invalidate(); }));
               }
           });
       }

Essentially this method wraps the actual call to UpdateScene for three reasons:

  1. To ensure only one instance of UpdateScene is being invoked at any time
  2. To push the call to UpdateScene onto a separate thread. This prevents the UI from blocking whilst it’s in running.
  3. To invoke Invalidate once UpdateScene has completed. This ensures that OnPaint will be invoked again and that the draw-update loop will be invoked again.

In the next post I’ll show you how to get started with this wrapper by overriding the ApplicationForm.  In the meantime, try it yourself….

Does Windows Mobile 6 Smell (part II)?

In my previous post I talked about Microsoft and the enterprise and how it had help shape Windows Mobile 6.x. Now I want to look at some of the implications of this strategy, specifically looking at how the attitude towards touch input has changed over time.

Touch v’s Non-Touch v’s Multi-Touch

One of the things that really differentiated Windows Mobile was it’s ability to work on multiple different form factors, from your non-touch txt friendly devices with keyboards through to your candy bar devices through to your pda-style devices with on-screen keyboards. Track back a few years and you would have seen the names Pocket PC and Smartphone being used to describe devices with and without a touch interface. With a move to align the two operating systems these came to be known as Windows Mobile Professional and Windows Mobile Standard – personally I think this did more than confuse the market who were already confused by the double use of the word Smartphone.

But this post wasn’t supposed to be a Windows Mobile history lesson, instead it was to look at our opinions on touch have evolved. If you recall back to the Pocket PC days there were very few people who actually used “touch” to interact with their device. Most uses whipped out their stylus and used that to push and poke at the screen. They would tap at the on-screen keyboard or even learn how to use the quirky text recognition capabilities of the device. This process was quite painful, particularly if you were responding to a text message or email. This is in part why both hardware keyboards and the Smartphone increased in popularity – both these addressed the problem of how to quickly navigate and type on the device.

The challenge with a physical keyboard is that no matter how to position it you end up with a tiny keyboard that simply adds weight and size to the device. Text entry, whilst quickest using a full qwerty keyboard was still a far shy from entering it on the desktop and often the extra hassle of sliding out a keyboard, waiting for the screen to reorientate and then entering text was enough to put off a lot of users.

The challenge with Smartphone is that it just sux – ok, you have me, I’m not a Smartphone advocate. Whilst I find that the interface is quick to navigate nearly all the applications are somewhat lacking or clumsy to use.  Take internet explorer for example – you either have a little arrow cursor that you drag around the screen using a dpad or you jump from link to link, often making the text of the website very difficult to read. Personally I’ve never liked this style of device and it was scary a couple of years ago because it seemed that 90% of all new devices being released by OEMs were a Smartphone, rather than having a touch screen.

From a development perspective we saw the convergence of Smartphone and Pocket PC into Windows Mobile as a good thing. It meant we could build a single application that would work on both styles of devices. Unfortunately, this is a bit like building a desktop application and running it on the device – great idea, but results in an aweful user experience as either the desktop application is limited to display what’s available on the device (ie small screen real estate) or the application has to scale down to fit to the device (resulting in small controls that are hard to use). Guidance from Microsoft even suggested that developers should build to target Smartphone so it will work on both devices.

This whole topic became even more interesting when Apple released the iPhone and multi-touch came into the mainstream. Unfortunately the Windows Mobile team failed to get it and released 6, 6.1 and 6.5 without any support for multi-touch.  In fact it’s only been with the release of the HTC HD2 that we’ve even seen capacitive screens for Windows Mobile which would effectively allow multi-touch. I believe this was because there was a misunderstanding on how users wanted to use their device. Too much research focussed on looking at ways to improve what users were currently doing (eg using a stylus), rather than exploring more innovative ways for the users to do things (eg making all controls larger so that the user can use touch instead of a stylus).

Now, finally Microsoft has awoken and we are seeing a new era of devices and operating systems heavily geared towards making touch (and I’m sure in the future multi-touch). Windows Mobile 6.5.3 has restyled controls, repositioned Start menu and Ok buttons, specifically geared to making it easy to navigate with touch and gestures. Windows Phone 7 series is all about touch, swipe, gesture and motion in general. It’s clear to see that this is the way forward and that the old Blackberry style non-touch devices are a thing of the past.

Does Windows Mobile 6 Smell?

If you ask most users what they think of Windows Mobile they either don’t know what it is (most non-techie consumers) or they shudder saying that slow, overly complex phone that I never use now I have…. Anyone would think that Windows Mobile smells. I’d like to put forward some points that at least explains why it looks and smells the way it is. You may even decide to give the current generation of Windows Mobile 6.5.3 devices a go.

Microsoft and the Enterprise

I think the first point I’d like to make is that I doubt at any stage Microsoft decided that the end user wasn’t the highest priority when designing and building Windows Mobile. The whole “end-user-first” message that’s coming from Microsoft is just another re-hash of the “Age of User Experience” message that we saw a couple of years ago. What I do buy is that Microsoft has changed focus on which end user they’re putting first, or at least, what end user activities should come first.

In the past the design of Windows Mobile was geared towards an end user who worked for an enterprise, was connected to Exchange server and the reason for having a device was to make phone calls, send sms, triage email, work with contacts, calendar and tasks to get their work done. Now we’re seeing a new era where Windows Phone 7 is about supporting end users in every facet of their lives – helping them stay in contact, entertain them, help them relax, get work done, oh and of course make a phone call. Actually the latter seems to have been almost an after thoughts as there is not even a hardware call and/or hang up button according to the specs released by Microsoft last week.

So I guess the question has to be asked as to why the focus was on the enterprise user? Microsoft’s entry into the mobile phone market came as an extension of their embedded operating system. In fact Windows Mobile is essentially Windows CE in a specified configuration, with additional modules, such as Office Mobile and of course a phone stack. As such it seemed logical for them to enter this space in order to support enterprise users.

Once in this space it appears that Microsoft saw RIM as one of the main competitors with their Blackberry devices. Those familiar with Microsoft codenames will know that Crossbow was one of the code names used internally for one of the previous versions of Windows Mobile – this happens (probably coincidentally) to be the name of a pesticide that can be used to get ride of the blackberry plant (ref Website). The Blackberry OS has traditionally been menu centric, so as long as Windows Mobile only had as single “Start” menu it was considered to be a safe bet. Also, since Blackberries didn’t have touch screens, supporting touch (rather than stylus, and definitely not multi-touch) input wasn’t really considered a core use case. Again the result was that Windows Mobile continued to evolve towards a dpad/keyboard driven interface – in the enterprise this resulted in some very effective office worker devices that could be used to rapidly triage email but they weren’t the nicest consumer devices.

More on this discussion in future posts….

Windows Mobile 6.5.3 DTK (not SDK or 6.6) download available

Get it while it's hot from the download center. The content in my original overview of the Windows Mobile 6.5.3 SDK is still accurate. However the installation issues have been resolved and there is a bunch of things (like the help files and the Map Framework sample) are now installed correctly.  The installation of the DTK should not affect any of the existing emulator images you have installed.  Stay tuned for more information on what's in the DTK.

Windows Mobile 6.5.3 DTK - Ready, Set….. Oh wait, hang on….. Go!

As some of you will be aware there was a first attempt at releasing the Windows Mobile 6.5.3 DTK (now missing) earlier this month. Despite a number of bits being missing or not installed correctly there are definitely some good bits coming in the DTK (take for example the Widget development story within VS2008).  According to Todd in his Marketplace Momentum post we should see the real version of the DTK later this week. Check back with this blog to find out more about the actual release when it happens.

Windows Mobile 6.5 SDK is now Missing In Action

According to Twitter, which Microsoft clearly believes as the best way to communicate to its developer community, the Windows Mobile 6.5 SDK has been pulled.

image

Note that whilst this acknowledges that the SDK wasn’t properly tested there is apology to a developer community that collectively has probably wasted thousands of man hours installing, uninstall and reinstalling SDKs to get machines back to a working point.

I totally agree that the SDK should have been pulled as soon as there was a known issue with it but for Microsoft to continue to insult its developer audience is just one slap after the other.

Windows Mobile 6.5 SDK Overview

The first thing to note about the newly released Windows Mobile 6.5 SDK is that it effectively comes in two parts.  If you want to build applications for both the professional (ie touch screen devices) and standard you need to get both versions of the sdk. This way you will get all the emulator images.

For all those who have started working with Visual Studio 2010 the news is not great. As you are not doubt aware from the beta versions there is currently no support within VS 2010 for doing mobile development.  This SDK release does not change this, you will continue to have to use Visual Studio 2008 for doing Windows Mobile development, with the exclusion of widgets, which you can do as a web site in VS 2010 and manually package it up for deployment.

Post install I thought I’d take a look at the readme file to see what’s changed in this SDK. Doh! Someone forgot to check this as the title reads “Windows Mobile 6 SDK Refresh”.  The contents seem to make the title which made me think that I’d installed the wrong SDK but no, there’s a Start Menu item for “Windows Mobile 6.5 SDK” so I’m guessing that I didn’t get it wrong.

Following the readme “fail” I decided to launch Visual Studio 2008 to see whether I could spot the differences myself. From the New Project dialog (below) you can see that there is a new node “Widgets for Windows Mobile”.  Given my recent set of blog posts on building Windows Mobile widgets I was really eager to see what this would entail.

image

After selecting the SimpleWidget option I was presented with a basic web site layout containing sub folders for css and script files. Personally I would have liked to see another sub folder for images.

image

Looked like a good starting point so I thought I’d try running it. Before doing so I went to start up a Windows Mobile 6.5 emulator image. I ran up the Device Emulator Manager only to discover that none of the 6.5 professional images (that were all there from when I’d install the 6.5 emulator image pack released last year) were there. Thinking I must be missing something I installed the Standard edition of the 6.5 SDK. This only made matters worse, now I have no Windows Mobile 6 or 6.5 images.

Thinking that something must have gone wrong I uninstalled both 6.5 SDKs and rebooted my machine. After installing the Windows Mobile 6.5 Professional SDK the professional emulator images reappeared (phew!) and I returned to my SimpleWidget project. I noticed that the device toolbar wasn’t enabled, so the widget project doesn’t understand, or wants to use a device/emulator to debug with after all. This got me thinking about what the debug experience was going to be. I pressed F5 to debug and wow, I got the following debugger experience within IE:

image

After enabling the ActiveX control I got the following output – looks very similar to what I’d expect on the device. Unfortunately the ActiveX prompt appears every time you start the debugger.  The simple work around to this issue is to not stop the debugger.  Because you are effectively working with a mini web site you can change content (ie htm, css, js) and just refresh the browser to see your changes.

image

What’s cool is that you can do the following:

  • Set breakpoints and then walk through your code inspecting variables.

image

  • Use the “hide” (which changes to “show” when clicked) button to mimic the widget going into the background.  The onshow and onhide events get invoked.
  • Change the resolution and orientation of your widget to see what it would look like in different perspectives. Changing resolution is particularly important as you need to cater for these devices differently otherwise your widget will be either unusable or look childish.
  • You can change most of the System State properties to see what effect it has on your device. See my post on System State (aka Notification Broker) and Device Information for more information on working with this information.
  • Even the menus are simulated:

image

Of course, whilst this is convenient for development, you must and I repeat must test your widgets on real devices.

Returning to Visual Studio, I took a further look at the widget project itself. If you go to Properties on the project you get the following:

image 

image

I’m not entirely sure what all the parameters mean yet but I’m sure they’re in the help files somewhere (actually, no it appears not. The help files seem to be the standard WM6 SDK files). What does interest me is the Output Path parameter. If I navigate there I notice three files: the first two, Harness.html and Harness.js are what make the debugger happen, the last, SimpleWidget1.widget is of course the widget file which you can copy and install on your device or emulator to see how it runs on your device.

image

I must admit I expected to see a manifest file editor as part of the project properties. Not seeing it there I thought I’d double-click the config.xml files (which of course is the manifest file for a widget). Wow – notice the nice editor it displays, rather than a basic xml editor.

image

My only criticism here is that the team haven’t really thought this through.  For a widget you would typically supply two icons if you are going to deploy to both professional and standard devices, one being a png, the other being an ico.

That’s enough about widgets. Let’s take a quick look at the emulator.  Notice that this isn’t the 6.5 we’re used to see in the emulator.  In fact if you look in the second image you’ll see that this is build 23090 which is around the build number that everyone has been talking about for Windows Mobile 6.5.3.

image image

In brief you’ll notice that the start and ok/X buttons are at the bottom of the screen. A number of the menus are now graphical.  The notification area drops down to be a graphical set of links and the tabs are no longer tabs, they’re more of a scrolling system (left-right) at the top of the page. These are all moves to better support touch input and going forward capacitive screens.

I’m sure there’s plenty more in the Windows Mobile 6.5 SDK that I haven’t discovered yet. Other than the major FAIL around the installation process (I would recommend uninstalling any previous WM6.5 emulators first) and the readme/help documentation I’m glad to see Microsoft starting to release new tools for us mobile developers.

Windows Mobile Widget 101 - Persistence

Prior posts in this series:

Out of the box the Windows Mobile widget API provides only basic support for saving and retrieving data. The documentation on MSDN shows how you can read and write basic key-value pairs for values up to 4000 bytes but what happens if you want to store more than that? And, what do you do if you want your widget to run as a gadget or on a desktop browser? The following code, which we’ll add to widget.js handles all these scenarios.

-----------------
widget.js
-----------------

//-----------------------------------------------------------------------
// Storage
//-----------------------------------------------------------------------

        // saves key-value pair (length restricted, use persistData for long string values)
        saveKeyValue: function (key, value) {
            if (window.widget) {
                window.widget.setPreferenceForKey(value, key);
            }
            else if (isGadget && isGadget == true){
                return System.Gadget.Settings.writeString(key,value);
            }
            else {
                return Cookie.set(key,value,365);
            }
        },

        // retrieves key-value pair
        retrieveKeyValue: function (key) {
            if (window.widget) {
                return window.widget.preferenceForKey(key);
            }
            else if (isGadget && isGadget == true){
                return System.Gadget.Settings.readString(key);
            }
            else {
                return Cookie.get(key);
            }
        },
        // Persists Data (any length)
        persistData: function (key, value) {
            if (!value || value == null) {
                WidgetAPI.saveKeyValue(key, 0);
                return;
            }

            var str = value;
            var i = 0;
            var j = 0;

            while (j < str.length) {
                var inc = 2000;
                if (j + inc > str.length) {
                    inc = str.length - j;
                }
                var tmp = str.substring(j, j + inc);
                j += inc;
                WidgetAPI.saveKeyValue(key + i, tmp);
                i += 1;
            }
            WidgetAPI.saveKeyValue(key, i);
        },
        // Checks to see if data exists
        dataExists: function (key) {
            var count = WidgetAPI.retrieveKeyValue(key);
            if (typeof(count)=="undefined" || count == null || count <= 0) {
                return false;
            }
            else {
                return true;
            }
        },

        // Retrive data (any length)
        retrieveData: function (key) {
            var count = WidgetAPI.retrieveKeyValue(key);
            if (!count || count == null || count <= 0) {
                return null;
            }
            var str = "";
            for (var i = 0; i < count; i++) {
                str += WidgetAPI.retrieveKeyValue(key + i);
            }
            return str;
        }

And of course we need some sample code added to main.js and main.htm to demonstrate this in action:

----------------- 
main.htm
-----------------

        <div id="welcome">Welcome....</div>
        <div id="persistenceDemo">Name:
            <input id="nameTextbox" type="text" />
            <input id="submitButton" type="button" value="Save" onclick="saveName()"/>
        </div>

----------------- 
main.js
-----------------

function onLoad() {
    // Code omitted as same as previous posts

    sayWelcome();
}

function sayWelcome() {
    var welcome = $get("welcome");
    var name = WidgetAPI.retrieveData("Name");
    if (!name || name == null) {
        name = "...";
    }
    welcome.innerHTML = "Welcome " + name;
}

function saveName() {
    var txt = $get("nameTextbox");
    WidgetAPI.persistData("Name", txt.value);
    sayWelcome();
}

When you run the widget you can enter a name, which will be persisted across runs of your widget. The following screenshots are from the widget running as a widget, gadget and in the desktop browser. Note that the gadget is unique in that if you close the gadget and open another instance it will not remember your settings.  This is because each instance of the gadget has its own unique storage (so you can run multiple instance of the gadget at once). However, if you restart your computer with your gadget running you will notice that it remembers the values. This is because it is the same gadget instance!

imageimage image

Windows Mobile Widget 101 – System State (aka Notification Broker) and Device Information

Prior posts in this series:

Whilst Windows Mobile widgets are great, they definitely have their shortcomings when compared for true mobile application. One such area is in the ability to interact with device hardware and information. Further, it appears that every OS provider seems to be tackling this differently.  If you look at S60 they have expose a wealth of device and user information via their widget API. Unfortunately one of the weaknesses of the current Microsoft implementation of widgets is that there are only a few pieces of device information you can query (out of the box) and no user information (ie contacts, calendar…). If you want to do more, you have to build and deploy ActiveX controls to assist your widget.

Returning to the Windows Mobile widgets and out of the box you get the following pieces of system information. All are exposed via the SystemState object.

CradlePresent

A Boolean value indicating whether the device is cradled.

DisplayRotation

An integer value indicating whether the display is in portrait or landscape mode.

PhoneHomeService

A Boolean value indicating whether the device is presently registered on its home network.

PhoneOperatorName

A string indicating the name of the device’s mobile operator.

PhoneRoaming

A Boolean value indicating whether the device is currently roaming.

PhoneSignalStrength

An integer indicating the phone signal strength, expressed as a percentage of full strength.

PowerBatteryState

An integer indicating the current state of the battery, such as whether the battery level is critically low or if the battery is charging.

PowerBatteryStrength

An integer indicating the current battery strength, expressed as a percentage of full strength.

And here’s an example of how you would access one of these properties. You first need to create an instance of the SystemState object. Next, query the actual property you are interested. Finally, if you want to receive notification when that property changes, you need to add an event handler to the “changed” event, passing in the callback method as the second parameter.

var systemState = widget.createObject("SystemState");
var cradledState = systemState.CradlePresent;
cradledState.addEventListener("changed", cradled);

Note, that the SystemState properties and the callback event are all exposed via the Windows Mobile Notification Broker that has been around since Windows Mobile 5. What I don’t get is why only this limited set of properties?

One of the frustrating things about working with widgets is determining whether your widget has a connection, firstly to a network and secondly to your server. Whilst there is no “IsConnected” property exposed via the SystemState object, you can use a combination of properties to try and deduce if there is a network connection.

Lets start with the widget.js file. You have to be careful when working with the widget API to ensure you don’t break your cross-platform capabilities.  Of course if you don’t want your widget to run as a gadget you can eliminate quite a bit of the following code.

-----------------
widget.js
-----------------

var WidgetAPI = function () {
    return {
        // Code omitted as same as previous post
        systemState: null,
        stateEvents: null,
        createSystemState: function () {
            if (WidgetAPI.systemState != null) return;

            if (window.widget) {
                WidgetAPI.systemState = window.widget.createObject("SystemState");
            }
            else {
                WidgetAPI.systemState = {};
            }
        },
        getCradleState: function () {
            WidgetAPI.createSystemState();

            if (!WidgetAPI.systemState.CradlePresent) {
                WidgetAPI.systemState.CradlePresent = true;
            }

            return WidgetAPI.systemState.CradlePresent;
        },

        listenForCradleStateChanged: function (callback) {
            WidgetAPI.listenForStateChanged(WidgetAPI.getCradleState(), callback);
        },

        getPhoneStrengthState: function () {
            WidgetAPI.createSystemState();

            if (!WidgetAPI.systemState.PhoneSignalStrength) {
                WidgetAPI.systemState.PhoneSignalStrength = 100;
            }

            return WidgetAPI.systemState.PhoneSignalStrength;
        },

        listenForPhoneStrengthStateChanged: function (callback) {
            WidgetAPI.listenForStateChanged(WidgetAPI.getPhoneStrengthState(), callback);
        },

        listenForStateChanged: function (state, callback) {
            if (window.widget) {
                state.addEventListener("changed", WidgetAPI.createSafeListenerCallback(callback));
            }
        },
        entered: false,
        createSafeListenerCallback: function (callback) {
            try {
                WidgetAPI.stateEvents = new Date();
                WidgetAPI.stateEvents.setTime(WidgetAPI.stateEvents.getTime() - 60 * 1000);
                var func = function () {
                    if (WidgetAPI.entered == true) return;
                    try {
                        WidgetAPI.entered = true;
                        var lastInvoke = WidgetAPI.stateEvents;
                        lastInvoke.setTime(lastInvoke.getTime() + 1 * 1000);
                        if (lastInvoke < (new Date())) {
                            WidgetAPI.stateEvents = new Date();
                            if (callback && callback != null) {
                                callback();
                            }
                        }
                    }
                    finally {
                        WidgetAPI.entered = false;
                    }
                };
                return func;
            }
            catch (e) {
                alert(e);
            }
        }

    };
} ();

The other thing you will notice about this code is that there is a wrapper used for calling the event callback. When certain system events are raised (eg PhoneSignalStrength) a number of events will be raised within a short period of time. This wrapper protects against this. Warning: Some events will be hidden by this wrapper, so only use it if you don’t mind if some events are missed. In our case we are only using the change in state to prompt the application to check if it still has connectivity.

In the utils.js file we’re going to add a simple Ping routine that can be used to detect if a server is reachable. It does so by downloading a specified image within a given timeframe. Note that you should use a small image as you don’t want to waste network bandwidth.

-----------------
Utils.js
-----------------

var Ping= {};
Ping = {
    img: null,
    imgPreload: null,
    timer: null,
    success: null,
    fail: null,
    hasFailed: false,
    init: function (imgUrl, pingCallback, failCallback) {
        Ping.img = imgUrl;
        Ping.success = pingCallback;
        Ping.fail = failCallback;

        Ping.imgPreload = new Image();
        Ping.hasFailed = false;
        Ping.imgPreload.onload = function () {
            clearTimeout(Ping.timer);
            Ping.timer = null;
            if (Ping.hasFailed == false && Ping.success != null) {
                Ping.success();
            }
        };

        Ping.imgPreload.src = Ping.img;
        if (Ping.fail != null) {
            Ping.timer = setTimeout(Ping.fail_to_ping, 10000);
        }
    },

    fail_to_ping: function () {
        clearTimeout(Ping.timer);
        Ping.timer = null;
        Ping.imgPreload = null;
        Ping.hasFailed = true;
        if (Ping.fail != null) {
            Ping.fail();
        }
    }
};

Now, to bring these together we’re going to introduce a new file, network.js, that registers for changes to the cradle and phone signal strength, and then based on those changes calls the Ping function to determine if the server can be reached. Note that as we don’t have any WiFi state information we can’t just assume that because the device is not cradled and there is no phone signal there is no data connection. As such, we just use the change in state to invoke ping the server. Again, there is some time checking around the Ping function to make sure it isn’t called too frequently.

----------------- 
Network.js
-----------------

var Network = function () {
    return {
        isConnected: false,
        connectionTestUrl: "
http://www.builttoroam.com/ping.gif",
        lastPing: null,
        minimumPingSeparationInSeconds: 30,
        connectionStateChanged: null,
        init: function (stateChangedCallback) {
            if (stateChangedCallback && stateChangedCallback != null) {
                Network.connectionStateChanged = stateChangedCallback;
            }

            WidgetAPI.listenForCradleStateChanged(Network.cradledStateChange);
            WidgetAPI.listenForPhoneStrengthStateChanged(Network.phoneStrengthChange);

            Network.testConnection();
        },

        cradledStateChange: function () {
            Network.testConnection();
        },
        phoneStrengthChange: function () {
            Network.testConnection();
        },

        testConnection: function () {
            var pingOk = false;
            if (Network.lastPing == null) {
                pingOk = true;
            }
            else {
                var pingTime = new Date();
                pingTime.setTime(Network.lastPing.getTime() + Network.minimumPingSeparationInSeconds * 1000);
                if (pingTime < (new Date())) {
                    pingOk = true;
                }
            }

            if (WidgetAPI.getCradleState() == false || WidgetAPI.getPhoneStrengthState() <= 0) {
                pingOk = true;
            }

            if (pingOk) {
                Network.lastPing = new Date();
                Ping.init(Network.connectionTestUrl, Network.connectionTestSuccessful, Network.connectionTestFailed);
            }
        },

        connectionTestSuccessful: function () {
            var isConnected = true;
            Network.setConnectedState(isConnected);
        },

        connectionTestFailed: function () {
            var isConnected = false;
            Network.setConnectedState(isConnected);
            Network.lastPing = null;
        },

        setConnectedState: function (connectedState) {
            if (Network.isConnected != connectedState && Network.connectionStateChanged != null) {
                Network.connectionStateChanged(connectedState);
            }

            Network.isConnected = connectedState;
        }
    };
} ();

Some minor changes to main.htm and main.js in order to display the connected state. Add a div, isConnected, to main.htm, and add a call to Network.init and a callback function to main.js.

-----------------
Main.htm
-----------------

<div id="isConnected">N/A</div>

-----------------
main.js
-----------------

function onLoad() {
    // Omitting code from previous post
    Network.init(connectionStateChanged);
}

function connectionStateChanged(isConnected) {
    var connected = $get("isConnected");
    if (isConnected == true) {
        connected.innerHTML = "Connected!";
    }
    else {
        connected.innerHTML = "Not connected!";
    }
}
 

After deploying this widget, you should see that the connected status is displayed below the rest of your content. Of course, you may want to use a nicer icon/image to represent the connected state.

image

Windows Mobile Widget 101 - Menus

Prior posts in this series:

One of the reasons that widgets are an interesting alternative to mobile web sites is their ability to integrate into the Windows Mobile shell similar to native or managed applications. Menus are one of these integration points. When designing your widget you should consider using the menus in additional to placing links within the content on your html page. Menus are a great way of controlling navigation within your application as they are always at the bottom of the screen, regardless of where the user has scrolled to (like mobile websites, widgets tend to be elongated, allowing vertical scrolling but eliminating horizontal scrolling where possible).

For example, the menu may contain items such as Home, Exit, About – items that are will be there regardless of where the user is in the widget.  This is not to say you can’t dynamically control what’s displayed in the menu, in fact far from it as you can easily add and remove, enable and disable menu items.

In the previous post you saw how we can display manifest information to the user. Whilst this was useful in demonstrating how to read information from the manifest, it’s not likely that we always want that information to be displayed.  Lets add a menu item that will toggle the visibility of this information.

To start with, we need to encapsulate the manifest information in the main.htm file into a single div that we can hide and show.  This way we only need to toggle a single div, rather than each of the manifest information divs.

-----------------
Main.htm
-----------------

<div id="about" style="display:none;">
    <div id="manifestVersion" class="manifest"></div>
    …
</div>

The next thing we need to do is add some helper methods to make working with widget menus that much easier. Note that this code will create menu items when running as a widget but it will also create div elements for menus when running in a standard browser, this aids debugging as you can test the navigation/event handling of your menus from within Visual Studio.

-----------------
widget.js
-----------------

        // Creates a menu with specified label and click handler
        createMenuItem: function (label, handler) {
            var mi = null;
            this.LAST_MENU_ID ++;
            if (window.widget && window.widget.menu) {
                var mi = window.widget.menu.createMenuItem(this.LAST_MENU_ID);
                if (mi) {
                    mi.text = label;
                    if (handler) {
                        mi.onSelect = handler;
                    }
                }
            }
            else if (isGadget != true) {
                mi = document.createElement("div");
                mi.innerHTML = label;
                mi.text = label;
                if (handler) {
                    mi.onclick = handler;
                }
                mi.id = "menu" + id;
            }
            return mi;
        },
        //  Returns a menu item whose ID is specified
        getMenuItemById: function (id) {
            var mi = null;
            if (window.widget && window.widget.menu) {
                mi = window.widget.menu.getMenuItemById(id);
            }
            else {
                mi = $get("menu" + id);
            }

            return mi;
        },
        getMenuText: function (mi) {
            if (window.widget && window.widget.menu) {
                return mi.text;
            }
            else {
                return mi.innerHTML;
            }
        },
        //  Appends the menu item to the main menu at the end. If the id of the menuitem to be added already exists in the menu, an exception will be thrown.
        appendMenuItem: function (mi) {
            if (mi && window.widget && window.widget.menu) {
                window.widget.menu.append(mi);
            }
            else {
                    var right = $get("rightSoftKey");
                    right.appendChild(mi);
                    right.parentNode.style.display = "block";
            }
        },
        //  Appends the menu item to the parent menu at the end. If the id of the menuitem to be added already exists in the menu, an exception will be thrown.
        appendSubMenuItem: function (parent, mi) {
            if (parent && mi && window.widget && window.widget.menu) {
                parent.append(mi);
            }
            else {
                if (parent.childNodes.length == 1) {
                    var list = document.createElement("div");
                    list.style.margin = "10px";
                    parent.appendChild(list);
                }
                parent.childNodes[1].appendChild(mi);
            }
        },
        // Removes the menu item from the main menu. If the specified id does not correspond to an item in the menu, an exception will be thrown.
        removeMenuItem: function (mi) {
            if (mi && window.widget && window.widget.menu) {
                window.widget.menu.remove(mi);
            }
            else {
                var right = $get("rightSoftKey");
                right.removeChild(mi);
            }
        },
        // Removes the menu item from the sub main menu. If the specified id does not correspond to an item in the menu, an exception will be thrown.
        removeSubMenuItem: function (parent, mi) {
            if (parent && mi && window.widget && window.widget.menu) {
                parent.remove(mi);
            }
            else {
                parent.childNodes[1].removeChild(mi);
                if (parent.childNodes.length == 1) {
                    parent.removeChild(parent.childNodes[1]);
                }
            }
        },

        // Sets the softkey of the widget. Currently we supprt setting the left softkey and right soft key.
        // If there is an error setting the soft key, exception will be thrown. If the softkey index is invalid, exception will be thrown.
        setSoftKey: function (mi, softkeyIndex) {
            if (mi && window.widget && window.widget.menu) {
                window.widget.menu.setSoftKey(mi, softkeyIndex);
            }
        },
        // Sets the left softkey for the widget menu item
        setLeftSoftKey: function (mi) {
            if (mi && window.widget && window.widget.menu) {
                window.widget.menu.setSoftKey(mi, widget.menu.leftSoftKeyIndex);
            }
            else {
                    var left = $get("leftSoftKey");
                    left.appendChild(mi);
                    left.parentNode.style.display = "block";
            }
        },
        // Sets the right softkey for the widget menu item
        setRightSoftKey: function (mi) {
            if (mi && window.widget && window.widget.menu) {
                window.widget.menu.setSoftKey(mi, widget.menu.rightSoftKeyIndex);
            }
            else {
                var right = $get("rightSoftKey");
                right.removeChild(mi);
                right.parentNode.style.display = "block";
            }
        },
        // enable/disable a menu item
        toggleMenuItem: function (id, on) {
            var mi = this.getMenuItemById(id);
            if (mi) {
                mi.enabled = on;
            }
        }

And of course we need to add code to main.js in order to actually create the menus:

-----------------
main.js
-----------------

function onLoad() {
    // Omitted code as it is the same as previous posts
    createMenuItems();
}

// Create the  menu items
function createMenuItems() {

    // create Refresh as left soft key for the main page
    createLeftSoftKey();

    // create right soft key and its sub menu items
    createRightMenuItems();
}

// create Blog link as left soft key
function createLeftSoftKey() {
    // Add the Back menu item and set it to disabled
    var mi = WidgetAPI.createMenuItem("Blog", onNavigateToBlog);
    if (mi && mi!=null) {
        mi.enabled = true;
        WidgetAPI.setLeftSoftKey(mi);
    }
}

function onNavigateToBlog() {
    window.open("
https://blogimages.builttoroam.com/nick");
}

// Add sub menu items to right soft key "Menu"
function createRightMenuItems() {
    // Add the Home menu item and set it to disabled
    aboutMenu = WidgetAPI.createMenuItem("About", onAbout);
    if (aboutMenu && aboutMenu != null) {
        aboutMenu.enabled = true;
        WidgetAPI.appendMenuItem(aboutMenu);
    }

}

Lastly, returning to the main.htm file we need to add two hidden divs which will be used during testing to display the menu items when the widget is run on the desktop. These divs will remain hidden when the widget is run on the device.

-----------------
Main.htm
-----------------

        <!-- Testing on desktop only -->
            <div style="display:none;">
                LEFT:
                <div id="leftSoftKey">
                </div>
            </div>
            <div style="display:none;">
                RIGHT:
                <div id="rightSoftKey">
                    <div onclick="window.close()" >Exit</div>
                </div>
            </div>
    </body>
</html>

Here’s the widget in action – you can see that the left menu (which used to read Exit) now reads Blog and that the right menu includes both the standard Exit item and an About item. Clicking the About item displays the hidden manifest information.

image image

If you run this from within Visual Studio, what you will see is that the left and right menus are simulated by divs that are created at the end of the page. In the same way as the widget running on the device, clicking the About will display/hide the manifest information area.

image image

 

Windows Mobile Widget 101 – The Manifest File

Prior posts in this series:

In this post we’re going to drill a little further into the config.xml file (ie the Manifest file) that is shipped with your widget and how you can access its content from your widget javascript code. In the post Widget Anatomy – The Manifest, Jorge covers a number of points about working with the manifest file. Here I’m going to add code to our on going example which you can use to wrap the widget object, allowing you to use the same code regardless of whether your widget is running in a normal browser, as a gadget or as a widget.

Let’s start with the html page.  We’re just going to add some div tags into which the values from the manifest file will be inserted.

-----------------
Main.htm
-----------------

<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Hello Widget</title>
        <!-- Javascript -->
        <script type="text/javascript" src="js/utils.js"></script>
        <script type="text/javascript" src="js/widget.js"></script>
        <script type="text/javascript" src="js/main.js"></script>
    </head>
    <body onload="onLoad();">
        Hello Widget World!
        <hr />
        <div id="manifestVersion" class="manifest"></div>
        <div id="manifestId" class="manifest"></div>
        <div id="manifestName" class="manifest"></div>
        <div id="manifestDescription" class="manifest"></div>
        <div id="manifestAuthorEmail" class="manifest"></div>
        <div id="manifestAuthorName" class="manifest"></div>
        <div id="manifestAuthorURL" class="manifest"></div>
        <div id="manifestHeight" class="manifest"></div>
        <div id="manifestWidth" class="manifest"></div>
        <div id="manifestLocale" class="manifest"></div>
        <div id="manifestIconSource" class="manifest"></div>
    </body>
</html>

Next, let us add code to widget.js to wrap the calls to the widget API:

-----------------
widget.js
-----------------

var WidgetAPI = function () {
    return {
        // gets the widget id 
        getId: function () {
            if (isGadget && isGadget == true) return System.Gadget.path;
            return window.widget ? window.widget.identifier : "
http://builttoroam.com/invalidid";
        },
        getVersion: function () {
            if (isGadget && isGadget == true) return System.Gadget.version;
            return window.widget ? window.widget.version : "0";
        },
        // gets the widget name
        getName: function () {
            if (isGadget && isGadget == true) return System.Gadget.name;
            return window.widget ? window.widget.name : "Not a Widget nor a Gadget";
        },
        // gets the widget description
        getDescription: function () {
            return window.widget ? window.widget.description : "Default description....";
        },
        // gets the widget author Information
        getAuthor: function () {
            if (window.widget) {
                return { name: window.widget.authorName,
                    email: window.widget.authorEmail,
                    url: window.widget.authorURL
                };
            }
            else {
                return { name: "Nick Randolph",
                    email: "[email protected]",
                    url: "
https://blogimages.builttoroam.com/nick"
                };
            }
        },
        // gets the widget height
        getHeight: function () {
            return window.widget ? window.widget.height : "n/a";
        },
        // gets the widget width
        getWidth: function () {
            return window.widget ? window.widget.width : "n/a";
        },
        // gets the widget locale
        getLocale: function () {
            return window.widget ? window.widget.locale : "unknown";
        },
        // gets the current icon information for the widget
        getIconInformation: function () {
            return window.widget ? window.widget.currentIcon : { height: 0, width: 0, src: "n/a" };
        },

        // The rest has been omitted as it is the same as in the previous post

Now to update the main.js to iterate through the div tags and set their values:

-----------------
main.js
-----------------

function onLoad() {
    // Code in this method omitted as it is the same as in the previous post
    setupAboutInformation();
}

function setupAboutInformation() {
    updateManifestDiv("manifestVersion", WidgetAPI.getVersion());
    updateManifestDiv("manifestId", WidgetAPI.getId());
    updateManifestDiv("manifestName", WidgetAPI.getName());
    updateManifestDiv("manifestDescription", WidgetAPI.getDescription());
    var author = WidgetAPI.getAuthor();
    updateManifestDiv("manifestAuthorEmail", author.email);
    updateManifestDiv("manifestAuthorName", author.name);
    updateManifestDiv("manifestAuthorURL", author.url);
    updateManifestDiv("manifestHeight", WidgetAPI.getHeight());
    updateManifestDiv("manifestWidth", WidgetAPI.getWidth());
    updateManifestDiv("manifestLocale", WidgetAPI.getLocale());
    var icon =  WidgetAPI.getIconInformation();
    updateManifestDiv("manifestIconSource", icon.src);
}

function updateManifestDiv(divName, information) {
    var div = $get(divName);
    if (div != null) {
        div.innerHTML = information;
    }
}

In the updateManifestDiv method you’ll notice we are using $get. This method is not defined by default so we need to define it in utils.js (the name of this file is not important so long as you include it into your Main.htm file).

-----------------
utils.js
-----------------

// gets the element from the dom
function $get(id) {
    return document.getElementById(id);
}

Lastly, don’t forget to define the .manifest class in the css files (both high and low res):

-----------------
highres.css & lowres.css
-----------------

.manifest
{
    width: 100%;
}

And that’s it, now when you run it you will see information about your widget/gadget:

image image

New Development Certificates for Windows Mobile

As indicated by Peter Foot’s post on Expired Development Certificates the certificates that ship with the Windows Mobile 6 SDK have now expired. So you either need to play around with your system clock or, you can now download (yes I know, yet another Windows Mobile development download) the new certificates from the following blog post http://windowsteamblog.com/blogs/wmdev/archive/2010/01/12/new-windows-mobile-developer-certificates.aspx

Where’d My Applications Go, A Windows Mobile Marketplace Mystery

This morning I was looking for update to the WWOS Cricket widget which NineMSN published late last year. I had already “purchased” (it’s a free app, so it’s not really purchasing) the widget so I was surprised that it was not listed under My Applications within the Marketplace application on the device. Being a little confused by this I thought it may be specific to my device so I loaded up one of the emulators and again, no applications to install.

After a bit of thinking (actually I went off and did other things) it came to me that it may be to do with the region I have my device set to.  For whatever reason when I rebuilt my device last I had forgotten to set the region back to Australia.  Similarly, the default region for the emulators is also the US, which is why neither the device or emulator was showing my applications. Sure enough, when I reset my region back to Australia, which requires a reboot, I could again see my applications.

In my opinion this is just confusing – if I’ve bought an application/widget and I’ve signed into Marketplace I should see all the applications/widgets I’ve purchased, regardless of which region my device is currently set to.

For those not familiar with the Marketplace application or haven’t seen the WWOS Cricket widget, here’s a few images to get you started.

 image image 

image image

Windows Mobile Widget Development using Visual Studio

There’s been quite a bit of talk since the early CTP/Beta release of Visual Studio 2010 regarding the lack of support for Windows Mobile development. However, what most people fail to pick up on is that you can build Windows Mobile Widgets using either Visual Studio 2008 or Visual Studio 2010 (in fact you can probably do it using earlier versions of Visual Studio but I haven’t tried it). Interestingly an update to the Developing Widgets for Windows Mobile 6.5 MSDN article talks about coming support within Visual Studio for doing widget development:

Starting with Windows Mobile 6.5.3, developers can create Windows Mobile widgets using Visual Studio.

Given that you can already do most of the development within Visual Studio this would suggest better IDE support for perhaps debugging or packaging your widget…. This is pure speculation but if you want to get a bit of a heads up on widget development using Visual Studio, try the following posts.

The version of Windows Mobile mentioned in the MSDN article and by Mary Jo in Is Microsoft (slowly) picking up the pace with Windows Mobile? must be a reference to some of the leaked builds that I’ve been piloting on my Touch Pro (see New Windows Mobile build with Zooming for the latest ROM I’m running).

Windows Mobile Widget 101 – Handling Form Factors

So far in this series I’ve covered Getting Started, generating Start Menu Icons and a Gadget Side Note, all with a single static page that will generally display ok on all devices. However, when you get into building more complex widgets and testing on different devices you will notice that what works on higher resolution devices (Eg the HTC Diamond 2 or the HTC HD2) won’t look good on a smaller device (Eg HTC Snap). Whilst you may be thinking “Oh goodness, please don’t tell me we have to handle all the different resolutions differently,” the good news is that for the most part you only really need to worry about two classifications “high res” and “low res” devices.  Devices are typically divided into those with a width >=480 (high res) and those with a width<480 (low res).

The easiest way to change the way your widget displays for different resolutions is to use different css files to determine the style of each element. Our widget doesn’t currently use a css file, so lets add two css files in order to handle high and low resolution displays. Actually, while we’re at it we’ll include a gadget.css file which we will use in order to specify the height/width properties that were manually added to the Main.htm file in the previous post. Put all of these css files into a css folder to keep your project tidy.

In order to dynamically set the correct css file we’ll need to write some javascript. We’ll actually add two javascript files, one called main.js which will do most of the user interaction logic and one called widget.js which will contain most of the widget specific logic (the idea being that this file can be reused amongst your widgets). Again, put these files into a js folder within your project.

The last files we’re going to include are two background images, one for high res and one for low res.  In this case the files are background.png (480x328) and background_lowres.png (240x164) in the images folder. With all these files added the build files list should look like:

-----------------
files.txt
-----------------

config.xml
Main.htm
icon.ico
icon.png
js\*.js
css\*.css
images\*.png

-----------------
gadget_files.txt
-----------------

gadget.xml
Main.htm
icon.png
js\*.js
css\*.css
images\*.png

In this case the only difference between the high and low resolution layouts is that it’s going to use a different background image. This makes the css files relatively simple:

----------------- 
highres.css
-----------------

body
{
    background: transparent url('../images/background.png') no-repeat center top;
}

----------------- 
lowres.css
-----------------

body
{
    background: transparent url('../images/background_lowres.png') no-repeat center top;
}

----------------- 
gadget.css
-----------------

body
{
    height:200px;
    width:200px;
    border:1px solid #000000;
}

Note that the gadget.css doesn’t specify the background – instead of having a third layout we are going to combine the highres.css and the gadget.css values. This means that the gadget.css only needs to contain values that are unique to the gadget layout. You could take this approach with the low res display as well but given that most elements/class styles will change between high and low res it's probably easier to manage as two unique layouts.

Ideally we want to specify the style sheet as early as possible in the initial loading/rendering of the widget.  This is done by hooking into the onLoad event of the body element in Main.htm. Note that you also need to include references to the javascript files:

----------------- 
Main.htm
-----------------

<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Hello Widget</title>
        <!-- Javascript -->
        <script type="text/javascript" src="js/widget.js"></script>
        <script type="text/javascript" src="js/main.js"></script>
    </head>
    <body onload="onLoad();">
        Hello Widget World!
    </body>
</html>

In the onLoad event we simply need to determine whether the widget is running on a high or low res device and load the appropriate css files:

----------------- 
Main.js
-----------------

/****** Constants ******/
var HighResCss = "css\\highres.css";
var LowResCss = "css\\lowres.css";
var GadgetCss = "css\\gadget.css";

/****** Variables ******/
var isGadget = false;

/********************************************************************
This is the entry point to Widget code.
*********************************************************************/
function onLoad() {
    // Determine if this is running as a gadget (true if System.Gadget is defined)
    if (typeof System != "undefined" && typeof System.Gadget != "undefined") {
        isGadget = true;
    }

    if (WidgetAPI.isHighResolution() == true) {
        WidgetAPI.applyCssFile(HighResCss);
    }
    else {
        WidgetAPI.applyCssFile(LowResCss);
    }

    if (isGadget == true) {
        WidgetAPI.applyCssFile(GadgetCss);
    }
}

And we of course need to implement the WidgetAPI functions in the widget.js file.  Note that to avoid confusion we create a WidgetAPI object rather than the existing window.widget object.

----------------- 
Widget.js
-----------------

var WidgetAPI = function () {
    return {
        // returns true or false to indicate if widget is running on a high resolution device or not
        isHighResolution: function () {
            return this.getClientWidth() >= 480;
        },

        // gets the widget's client width
        getClientWidth: function () {
            return (document.documentElement.clientWidth==0) ? document.body.clientWidth : document.documentElement.clientWidth;
        },

        // apply css file
        applyCssFile: function (cssFileName) {
            if (typeof(cssFileName)!="undefined" && cssFileName!=null) {
                var cssNode = document.createElement('link');
                if (cssNode) {
                    cssNode.setAttribute('rel', 'stylesheet');
                    cssNode.setAttribute('type', 'text/css');
                    cssNode.setAttribute('href', cssFileName);
                    document.getElementsByTagName('head')[0].appendChild(cssNode);
                }
            }
        }
    };
} ();

Running this gives the following displays: Widget (high res), Widget (low res) and Gadget

 image image

image

Note: After you have installed your widget on a device you don’t need to reinstall or upgrade your widget every time you want to see your updates.  Instead you can locate where your widget has been extracted to on the device and simply copy across the files that have changed.  For example the widget is currently extracted to \Program Files\Widgets\User\17 so when I make changes, say to Main.htm, I just copy that file across to this folder. Then I just need to exit and restart the widget to see the changes take effect.