Windows Mobile 6.5 SDK is now Missing In Action

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

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 6.5 SDK Available for Download

Windows Mobile 6.5 SDK Available for Download

Just posted to MSDN Downloads is a brand new SDK for doing Windows Mobile development. The SDK is coupled with new emulator image downloads for the following languages GER, FRA, ITA, JPN, CHS and ESP. Go download the bits from the Windows Mobile 6.5 SDK Download page.

Windows Mobile Widget 101 – Persistence

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

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

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

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 >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

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

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

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).