msdn magazine

Going Places

sup { vertical-align:text-top; }

Going Places

Adaptable Apps for Windows Mobile

Michael Saffitz

Developers need to build apps that work well on all Windows Mobile devices.

Contents

Adaptable Applications
Design and Architecture
Display Differences
Resolution Awareness for Native Applications
Resolution Awareness for Managed Applications
Basic Device Differences
Other Device Differences
Testing and Further Exploration

When Microsoft first shipped Pocket PC 2000, and for a few years following, developers could relatively easily write one application that ran well on all devices. Generally, all devices had the same capabilities and characteristics: touch support, screen resolutions, portrait orientation, API sets, and so forth. Consequently, you could focus almost exclusively on your application's functionality. You didn't need to worry about these other elements of the device, and you definitely didn't need to worry about the potential that they could change.

But change is inevitable. As the market and technology developed, more and more devices became available, and these devices started to have divergent designs. Fast forward to 2008 and there are now more than 140 different Windows Mobile ® phones available that support a variety of different options—12-key and QWERTY keyboards; candy bar and clam shell styles; with and without GPS; square, portrait, and landscape screens; Wi-Fi, Bluetooth, and infrared communications; and other capabilities that vary from device to device. Unlike Pocket PC 2000, it's now much easier for customers to find a device that matches their needs, tastes, and budget.

Adaptable Applications

This growth in the diversity of Windows Mobile devices, however, has made it necessary for developers to be aware of these differences and to plan for them in their applications. Developers now need to build what are called adaptable applications—apps that work well and look great on all Windows Mobile devices.

Fortunately, as an operating system, Windows Mobile offers one of the most consistent core API sets of any mobile platform across devices. Windows Mobile developers will find the same core API set (designed in many places to match those found on the desktop) regardless of the device's mobile operator or hardware manufacturer.

As a result, most developers building adaptable applications will find that addressing different display resolutions, dots per inch (DPI), and orientations will be the predominant area of focus. For a smaller number of developers, differences in device capabilities (such as presence of telephony, GPS, and so on), API changes between major releases of Windows Mobile, and designing to target both touch and non-touch devices will also be areas to consider.

I'm going to show you some of the tools and techniques that developers can use to build adaptable applications. I'll look at some general design and architecture principles and then dig into the specifics around adapting to differences in screens and capabilities.

While there's certainly some additional care and consideration that must be taken when you choose to build an adaptable application, the benefits of the upfront investment often far outweigh the alternative: developing and testing a version of your application against every current (and future) device, or electing to not support a device and, thus, limiting your potential user base.

Design and Architecture

When building adaptable applications, following time-tested practices and good architectural patterns is essential. From a practices perspective, by carefully and explicitly identifying your requirements, you can begin to understand the minimum device profile that your application needs. You'll also identify the optional capabilities that, when present, your application can use dynamically. In taking this approach, you can be sure that your application runs on the largest number of devices without having to code to the lowest common denominator.

As a brief example, let's say that I have been asked to build a simple package delivery tracking application. I investigated my requirements and determined that I need to collect signatures to indicate that a package has been successfully delivered. As a nice-to-have feature, the application should upload package status to a server for online tracking. As a result of the need to collect signatures, my application will be limited to touch devices (Windows Mobile Professional and Classic). Having identified this, I'm now free to use the additional functionality requiring touch (such as the button control).

At the same time, I should be careful about architecting the connectivity components. If I assumed my application would have access to cellular data connections, for example, I would unnecessarily eliminate Classic devices that don't contain a phone but could have Wi-Fi.

Finally, you should note that if my client changes her mind and removes the signature requirement, I wouldn't necessarily be able to support non-touch devices (Window Mobile Standard), given my subsequent use of the button control.

Display Differences

As mentioned earlier, the differences in screen resolution, DPI, and orientation is frequently the most pressing issue when building adaptable applications. Here too, planning for these differences and being thoughtful in your architecture will have significant impact when implementing your solution.

The currently supported Windows Mobile 6 resolutions, DPIs, orientations, and icon dimensions are shown in Figure 1 . In addition to these, Microsoft occasionally adds new configurations, original equipment manufacturers (OEMs), and mobile operators. Also, some devices support dynamic screen orientation rotation. For example, a device with a 240×320 portrait display may rotate to a 320×240 landscape display when its keyboard slides out.

Figure 1 Windows Mobile 6 Display Options

Windows Mobile Professional and Classic (with Touch Screen)
Resolution DPI Orientation Small Icon Large Icon
240×240 96 Square 16×16 32×32
240×320 96 Portrait and Landscape 16×16 32×32
240×400 96 Portrait and Landscape 16×16 32×32
320×320 128 Square 21×21 43×43
480×480 192 Square 32×32 64×64
240×240 192 Portrait and Landscape 32×32 64×64
240×240 192 Portrait and Landscape 32×32 64×64
Windows Mobile Standard (without Touch Screen)
Resolution DPI Orientation Small Icon Large Icon
176×220 96 Portrait 16×16 32×32
240×320 131 Portrait and Landscape 22×22 44×44
320×320 131 Square 22×22 44×44
240×400 131 Portrait and Landscape 22×22 44×44
440×240 131 Landscape 22×22 44×44

More than ever, it's critical that your application not assume one or more screen characteristics and instead be written to dynamically adapt and support all resolutions, orientations, and at least 96 DPI and 131 DPI. (192 DPI is important, too, but tends to be limited to a very small number of devices. 128 DPI is close enough to 131 DPI to not cause major issues.)

There are several resources and tools available for both native and managed application development that make this task easier. I will look at a few of these and review some general approaches and best practices you can use when in the process of building resolution-aware applications.

Resolution Awareness for Native Applications

The Windows Mobile 6 SDK provides two primary resources for writing resolution-aware applications in native code: the reusable ScreenLib class in the UILayout sample and the DeviceResolutionAware.h header. The UILayout sample can be found in the \Samples\Common\CPP\Win32 directory of the Windows Mobile SDK. DeviceResolutionAware.h is installed to the \VC\ce\atlmfc\include directory of the Microsoft® Visual Studio® installation directory.

ScreenLib provides a set of helper functions for aligning elements on the screen. For example, you can use the DockControl function to dock a given control to a screen edge—or to all four edges, filling the client area. The OptimizeWidth and OptimizeHeight functions align and resize a control (or multiple controls, in the case of OptimizeWidth) with the display, leaving a small margin at the left and right or top and bottom, respectively. There are additional functions that provide for alignment of controls and for resizing a set of controls to be the same size. Given these functions, ScreenLib tends to be most useful when working heavily with form-based applications.

DeviceResolutionAware.h picks up where ScreenLib leaves off and provides more than 20 functions and macros that assist in building more complex adaptable applications. These start with basic functions and macros that provide the building blocks for adaptable user interfaces such as GetDisplayMode (which provides display characteristics and capabilities).

You'll find SCALEX, SCALEY, SCALERECT, and SCALEPT, which scale values appropriately for the current resolution. Next, there are functions such as StretchIcon and ImageList_StretchBitmap, which can help scale images for the current display characteristics. And functions such as RelayoutDialog can be used to automatically adjust the layout of a dialog when an orientation change occurs.

ScreenLib and DeviceResolutionAware.h provide a strong foundation on which to build your native resolution-aware applications. At the same time, however, it's important to note that they're not a substitute for designs and solutions that may be unique to your situations, especially when directly interacting with the display buffer or building complex UI.

Resolution Awareness for Managed Applications

For managed-code applications, the Microsoft .NET Compact Framework provides a set of display properties that can assist when creating applications that are resolution-aware. Similar to the functionality in ScreenLib, the .NET Compact Framework provides a Control.Dock property that will bind the specified control to an edge of its parent. Control.Anchor provides similar functionality by binding a control at a fixed distance from an edge of its parent. Using the Control.AutoScroll property will automatically add a scrollbar if the controls within the form do not fit on the display. Furthermore, Control.AutoScale tracks the resolution that the form was designed against, and it will dynamically scale the form if the DPI or resolution changes. As you might imagine, the Control.AutoScale property works well for simpler forms, but as your forms become more complex, the magic that it's able to perform becomes more limited.

For more complex forms, these properties provide a starting point, but they aren't necessarily a complete solution, especially when it comes to dynamically adjusting for orientation changes. One approach is to use the Orientation Aware Control (OAC) that the Microsoft patterns & practices group has released as part of the Mobile Client Software Factory (msdn2.mi­cro­soft.com/library/aa480471). The OAC delivers an easy way to target multiple orientations, especially for forms-based applications.

Once installed, the OAC allows you to use the managed form designer in Visual Studio to lay out your UI in a portrait mode and then, using the OAC, rotate to landscape. Once in this new orientation, you can adjust your UI as appropriate for landscape. The OAC will track the changes so that the appropriate layout will be used at run time when the end user is in portrait or landscape mode.

There are downsides, however, in using the OAC. First, the OAC is essentially allowing you to design specific orientation and resolution combinations; this approach is discouraged, as the supported orientations and resolutions can change in the future. It further doesn't allow you to explicitly design for different DPIs or for square screens that have recently become popular on Windows Mobile Standard-based smartphone devices. Finally, given that the OAC is creating and managing multiple layouts for each of your screens, there is a performance degradation that becomes more significant as you add additional forms and complexity (at the extreme, this can add noticeably to your application's launch time).

Because of these downsides, the Windows Mobile team has been encouraging developers to move away from the OAC. The group is releasing a new version of the Windows Mobile Line of Business Accelerator (go.microsoft.com/fwlink/?LinkId=115317) that includes a component to assist in building resolution-aware applications that have a single UI and make use of docking, anchoring, and other techniques.

Basic Device Differences

Despite the various tools, and even with the new accelerator, there's no single cure-all for writing adaptable applications. Each approach has advantages and disadvantages that need to be evaluated against your needs and situation. But regardless of the approach you take, there's some general guidance that may be helpful.

Start with the three basic orientations—square, portrait, and landscape—and think about how you'll lay out your UI for each. With this complete, you can then focus on ensuring that your UI will scale appropriately across the various resolutions and DPIs. For a complex UI, it may be easier to adjust the design and spread it across multiple forms than to keep it on a single form and rearrange it when an orientation change occurs.

As you implement your application for visual adaptation, it will become even more important to have a clean separation between your UI and your application's logic. By thinking of your UI as points of interaction and avoiding a form-based mindset, you can encapsulate your UI elements in management classes that centralize and abstract the details of how these elements map to individual forms.

It may be tempting to design exclusively for square screens, docking controls to the top and left, delivering a sort of adaptability by effectively reducing portrait and landscape orientations to square. But when you do this, you're robbing your application and the user of between one-third and two-thirds of potential screen real estate. Further, what at first appears to be a development time saver may end up taking more time—with even less screen real estate, you're forced to either design your UI more rigorously or include additional screens.

Other Device Differences

While addressing the differences in display characteristics is often the most significant portion of writing adaptable applications, there are other aspects as well. The version of Windows Mobile is important, as APIs have been introduced, modified, and deprecated over the years. There are device-specific capabilities that you may want to employ when they are available.

For these and other situations, it's still possible to write applications in a way that allows them to run on all devices. One technique for you to consider is the factory pattern, especially in combination with interfaces that define base capabilities and have device-specific implementations.

Let's look at a simple example that includes some of the design and requirements gathering practices discussed earlier. I've been asked to build a city guide that includes restaurant reviews. My core requirements are to include a directory of restaurants and reviews, and the ability to select and view a specific restaurant and read its review. My application must run on Windows Mobile 2003 and later versions. Finally, I have a requirement that when I'm using a device that provides telephony, I can directly call the restaurant from the review screen.

For this example, I'm going to use C#, but the concepts presented are applicable in Visual Basic ® and C++ as well. The managed telephony APIs were first introduced in Windows Mobile 5.0, and, as a result, my app will need to know which version of Windows Mobile it's running on and use the appropriate implementation.

I'll start by creating a telephony interface that defines the common functionality I require, regardless of the device and any specific implementation:

interface ITelephony { 
  bool HasPhone {
    get;
  }
  void MakeCall(string phoneNumber);
}

Next, Figure 2 shows my two implementations—one for devices prior to Windows Mobile 5.0 and one for devices running Windows Mobile 5.0 or later. For brevity, I've omitted the P/Invoke that is required on devices prior to Windows Mobile 5.0.

Figure 2 Implementing ITelephony

class PreWindowsMobile5 : ITelephony {
  public bool supportsTelephony {
    get { return File.Exists(@"\Windows\Phone.dll"); }
  }

  public void MakeCall(string phoneNumber) {
    // call Native Phone API
  }
}

class PostWindowsMobile5 : ITelephony {
  public bool supportsTelephony   {
    get { return SystemState.PhoneRadioPresent; }
  }

  public void MakeCall(string phoneNumber) {
    Phone thePhone = new Phone();
    thePhone.Talk(phoneNumber);
  }
}

Finally, I'll create a TelephonyFactory class that centralizes and isolates the different implementations from my app's core logic (see Figure 3 ). For this example, I've elected to have my TelephonyFactory class contain awareness of whether the device supports telephony, and in cases where it's not supported, throw an exception. Now, when I want to use telephony within my application, I can simply run the following:

  try {
    ITelephony myTelephony = 
      TelephonyFactory.GetTelephony();
    myTelephony.MakeCall(phoneNumber);
  }
  ...

Through the use of this pattern, I've isolated the differences that occur between devices and made the application easier to update and service, all while delivering adaptability and ensuring that my application can run on all Windows Mobile devices.

Figure 3 TelephoneFactory

class TelephonyFactory {
  static ITelephony _myTelephony = null;        

  public static ITelephony GetTelephony() {
    if (_myTelephony == null) {
      if (Environment.OSVersion.Version.Major >= 5)
        myTelephony = new PostWindowsMobile5();
      else
        myTelephony = new PreWindowsMobile5();
    }
    if ( ! myTelephony.supportsTelephony)
      throw(new NotImplementedException());

    return _myTelephony;
  }
}

Testing and Further Exploration

Good design and attentive coding are two of three aspects to writing adaptable applications. Fortunately, the final aspect—testing—is made easier by the diversity of emulator images provided as part of the Windows Mobile SDK and in standalone packages. The emulator images allow you to test your application under almost all possible display characteristics, including dynamic rotation.

Additional tools in the SDK allow for the simulation of GPS functionality, multiple types of cellular networks, and even various security configurations, allowing you to test dynamic capability detection and use. Finally, much of the emulator environment is programmable through the Device Emulator Manager Automation APIs and the Core Connectivity Framework, allowing you to automate aspects of testing multiple device configurations.

Providing a platform where a single application can target a rich diversity of devices is just one way that Windows Mobile offers the best mobile development platform today. Whether you're a seasoned veteran or new to the platform, the Windows Mobile developer Web site (msdn.microsoft.com/windowsmobile) offers documentation, tutorials, and tools that, in concert with the broad APIs and advanced technologies, make the development possibilities on Windows Mobile limitless. Additional materials and up-to-date information about the adaptability issues discussed in this column are available at msdn.microsoft.com/windowsmobile/adaptyourapp.

Special thanks to Jim Wilson (pluralsight.com/blogs/jimw), whose "Adapt Your App" talks inspired and contributed material to this column.

Michael Saffitz is a Program Manager on the Windows Mobile Developer Experience team at Microsoft. He focuses on application compatibility, platform consistency, and ISV evangelism. Send your questions and comments to goplaces@microsoft.com.