|
Last updated January 30, 2009
Questions with links have responses in the text below. Questions without links are in-progress and coming soon...
What caveats should be considered when reading this FAQ or using the tools and code from this project?
All code, examples, and tips are based on our experiences developing research software applications for Windows Mobile devices. We are a small team of researchers and have primarily overseen studies with limited deployments (typically < 10 phone users). We are providing this site to share what we have learned, through trial and error, from other developers on the web, and from feedback from fellow researchers. We are still in the process of learning, however, and apologize for any mistakes, bugs, or misinformation.
Note that there may be new, easier, and better ways to accomplish these tasks using the latest version of the .NET Compact Framework - or the latest discoveries of developers on the web. Additionally, some code and tools only work with .NETCF 2.0 - in some cases, there may be ways to accomplish the same goals using P/Invoke or earlier libraries in order for your application to work on devices with .NETCF1.# devices (e.g., Windows Mobile Smartphone 2003).
We can only maintain this site on a limited basis, but if you have corrections, suggestions, or additions, please contact us and we'll make an effort to update the site.
What are some helpful Windows Mobile projects and libraries?
MyExperience is an open-source
mobile data collection tool developed for Windows Mobile devices. Mobile data can include self-reported experience sampling data (from context-triggered surveys that the user completes) and sensor data (from phone-based sensors and connected remote sensors). Jon Froelich is the primary developer of MyExperience and has contributed extensive code libraries for Windows Mobile devices, as well as a robust software application currently be employed by multiple researchers worldwide. More information and downloads are available from their project page and their documentation wiki.
SharpZipLib is an open-source .NET compression library for zipping and unzipping files, with source code and compiled DLLs for .NET on the PC and the .NET Compact Framework on mobile devices. More information and downloads are available from their project license page and their wiki. SharpZipLib is used by the MobiRnD Remote Updater projects to zip and unzip application files for faster server retrieval. It is also used in the client-server communication example, to zip data files (from a survey application) to be sent to the server.
XDA RAPI Tools are a collection of tools for executing actions on a Windows Mobile device from the PC using ActiveSync/RAPI. Downloads and documentation are available here. These tools are used by the MobiRnD PC-based updater to copy log files from the device and update application files using files on the PC.
The OpenNETCF team has developed extensive Windows Mobile libraries. A list of their open and shared products is available here.
When testing out an applicaton on a Windows Mobile phone, what are some conditions or situations where problems may be discovered?
There are several situations that you may want to test to see if your application will respond in an appropriate way.
- when the user presses the home key, back key, or end call key (see keeping the application in the foreground question)
- when the user changes type modes (e.g., symbol to T9)
- when the user makes a phone call (what happens if an application prompt occurs during the phone call?)
- when user checks email
- when the user locks the device keyboard (see keyboard locking question)
- on shut-down of the device
- during charging while the device is on
- when the device goes into stand-by mode (see PocketPC power management question)
- if the phone storage card is loose or missing
Where do you get devices for running reseach studies?
Both Windows Mobile Smartphones and PocketPCs are often pricey, in the $300 range, but sometimes you can find them for less.
If you are also purchasing a phone contract, you can sometimes get them for just a little additional. When going this route, we usually contact the university phone representatives to find out what options are available.
We know of one researcher who purchased unlocked phones through eBay (HTC Dash phones). We're not sure of the final price, but do think she was able to save some by going this route.
We usually purchase unlocked phones through expansys (formerly MobilePlanet) or through TigerDirect. In early 2009, an unlocked Qtek Smartphone with WIndows Mobile 5.0 was for sale for about $90 from TigerDirect.
We research different phone models (has GPS? form factor? OS? Bluetooth protocol?) on this site:
http://pdadb.net
What does it mean to have an "unlocked" device?
It can be somewhat confusing, because "locked" and "unlocked" can refer to multiple restrictions on the phone.
Usually, an "unlocked" device is one that is not "SIM locked" for a particular phone provider. Phones may be locked, for example, to only work with T-Mobile SIM cards. If you need to able to get the phone to work with a wider variety of mobile providers (e.g., T-Mobile and Cingular/AT&T), including some of those that are available overseas, you need to purchase the device unlocked or using an unlocking service or program (try searching for "sda unlock") to unlock the device. Some phones, such as those used by Verizon, cannot be unlocked to work with other providers.
You can also have a phone that is "app locked," meaning the user is prevented from installing new software on the phone or the types of applications that can be installed are restricted in some way.
A device can have a "security lock" or configuration which dictates whether warning messages will be displayed when new software is installed, a new .exe or .dll are run for the first time, or the PC tries to communicate via RAPI (over ActiveSync) with the phone. You can use the Microsoft Security Configuration Manager Powertoy to change the configuration on a Windows Mobile 5.0/6.0 phone.
Finally, a device can be "keyboard locked," meaning that the buttons, including the keyboard or numberpad, do not respond to being pressed, to prevent the user from inadvertantly pressing buttons while the phone is in a pocket or bag. Please see the keyboard locking question for more information.
How do you get an application to start on start-up of the device?
You can get an application installed on a Windows Mobile Device to automatically start on start-up by placing a short-cut to the application in the \Windows\Startup\ folder.
The easiest way to do this is to connect your device to your PC, use ActiveSync to browse to the application folder and create a short-cut to the .exe file, just as you would when creating a shortcut for executables on your PC (right-click on the file and select "create shortcut" on the pop-up menu"). Then cut this short-cut file, navigate to the \Windows\Startup folder on the device and paste it there.
Try restarting your phone. Your application should start on start-up.
You can also specify that a shortcut to your application be placed in the startup folder during installation of your application .cab file. If you are creating your own .cab using cabwiz, within the ".inf" file that you use to create the .cab file, under the shortcuts section, place the following text, customized for your application file (the %CE4% is a reference to the startup folder):
[Shortcuts]
MyApplication,0,MyApplication.exe,%CE4%
If you are creating
a .cab using a Visual Studio setup project, you can create a short-cut to the application and designate that it be placed in the Startup folder (one of the special folders).
How do you address the PocketPC power management problem?
In PocketPC devices, applications are "suspended" after some period of time, thereby
preventing background tasks, such as Sensors, from running; among many side-effects,
an application cannot prompt the user, unless timed when the user is actively using the device;
To prevent the device from going into a suspend state, this class uses a P/Invoke to call SystemIdleTimerReset periodically. Because this call may put the device into a powerstate where the LCD remains on (and draining battery), this class also includes method calls to explicitly turn off the LCD _or_ to prevent that power state
These blog articles (article 1, article 2, article 3) describe the PocketPC power management scheme:
Essentially, in Smartphone, an application can run in the background continually, even when the display is off. In PocketPC, however, after a timeout period, the display turns off, and the system goes into a "suspend state" where application threads are suspended. This is a problem if you have events (such as prompts) or sensors that need to periodically or continually activate through your application.
To address this, we are using a class we have dubbed "SuspendPreventer." This class uses PowerPolicyNotify and SystemIdleReset to try to address the PocketPC power suspension issue. Selene Mota has done much of the research and implementation of this solution.
In our initial attempts, we discovered that:
1. SystemIdleReset, when used by itself, keeps the system from going into Suspend mode by keeping the phone in another power state. Used by itself, however, it keeps the device in User Idle mode, which means the backlight is off, but the LCD is on (thereby draining battery)
2. PowerPolicyNotify is supposed to switch UserIdle (backlight off/LCD on, system running) to Unattended (backlight and LCD off, system running). When used alone, it does not fully work for some PocketPC models, such as the HTC 3300 - instead, the phone seems to stay in UserIdle state unless the user explicitly presses the power button,in which case it is something like Unattended...
We experimented with a few other suggestions on the web and monitored power state changes, and came to the conclusion that the best approach was to use both PowerPolicyNotify and SystemIdleReset. We call PowerPolicyNotify(UNATTENDEDMODE, true) when the application starts and PowerPolicyNotify(UNATTENDEDMODE, false) when the application closes. We call SystemIdleReset every 45 seconds. Here's what we discovered with this solution.
1. In at least one PocketPC phone (HTC P3600), this solution appears to work.
2. In at least one other PocketPC phone (HTC P3300), we still have the problem with SystemIdleReset putting the phone into UserIdle mode, making the LCD turn on, draining the battery. To address this, we use GetSystemPowerState to check whether the LCD was on prior to the SystemIdleReset call. If it was not on, after the SystemIdleReset call, we call a method from a class written by Peter Foot to explicitly turn of the display again.
3. We initially thought there was a problem with this power solution causing applications to minimize when the LCD is manually powered on again - the application (such as email or MyExperience) was in the foreground for a moment and then was minimized, which was visually annoying. However, Stephen Intille determined that this was actually a side effect of certain implementations of TomTom. We still think this is the case, but would be interested in reports that suggest otherwise.
4. We tried reading the registry to get the "timeout" value so we could set the SystemIdleReset periodicity to be just below that, but found that changes through the phone settings interface to this value aren't always reflected in the registry - instead we decided on a constant 45 second value.
So, what are the issues now?
1. In one phone (HTC Apache), it appears that our method of detecting whether the display/LCD was on is not working consistently, because it aggressively turns off the display at times, even if the user is interacting with the phone. We wanted to do further testing to find out whether the HTC Apache is more like the P3600, not requiring an explicit display power off action, but the user of this phone is not co-located and not in a position to do user-testing for us.
2. Related to this, we are not sure how to determine whether a phone needs the display to be explicitly turned off (P3600 vs. P3300)... we have added a property for the SuspendPreventer called DoesTurnOffDisplay in order to set it dynamically, but application designers will have to decide whether to only set this in the source code after testing on a given device or find a way to dynamically determine whether it is needed.
3. More critical, in at least one phone (HTC P3300), we have observed MyExperience, using the SuspendPreventer, work fine for 1-3 days, and then suddenly quit, without any exceptions being generated. In the logs, it is clear that a call to SystemIdleReset is completed (without errors) just before the application quits. We don't have any leads at this time about whether the problem is in fact the power solution and if so, what the issue is.
4. The power solution seems to be working in the HTC P3600 (DoesTurnOffDisplay=false) and in the HTC Diamond Touch (DoesTurnOffDisplay=true). Please note that we have only done limited testing with the Diamond Touch because we just recently acquired this phone.
How do you keep an application running all the time?
In Smartphone applications, you can keep an application running by having it execute code periodically, for example within a timer. The OS should recognize the application as having not completed and allow it to continue.
You need to do this in PocketPC applications as well, but you will also need to address the power management issue, as described above.
The application does not need to be in the foreground all the time. You can start the application minimized and only show the application when the user activates it from the menu or through proactive prompting. You can also let the user minimize the application explicitly through your user interface or use the home key/back key to return the phone desktop to the foreground (see this question-response if you want prevent this from happening).
How do you keep an application in the foreground?
It is possible for the user to accidentally (or intentionally) minimize the application by pressing the "Home," "Back" or "End Call" keys. If there is a critical interaction that needs to stay in the foreground, you may want to prevent this mininimizing (or deactivation) from happening. Keep in mind that for the period of time you use this method, you are preventing the participant from using the other features of the phone.
One way to do this is to override the Deactivate method of the main application form and place code to re-activate the form there. A code example:
protected override void OnDeactivate(EventArgs e)
{
//prevent application from disappearing
//if user presses the Home or End Call keys
this.Activate();
}
Please note that this can be problematic if you have child forms or at times need for the application to disappear. For those cases, you may want to add a boolean that can be checked when deciding whether to re-activate the form on de-activate.
Also to note, a) the OS will kill your application on Windows Mobile devices if the application is not periodically active, for example, with a Timer or background thread; b) on some devices, if the user keyboard-locks the device, the application will minimize regardless and other steps must be taken for it to re-appear on unlock.
How do you bring an application to the foreground?
It may not be enough to use this.Show() or this.BringToFront() to get an application into the foreground, especially after it has been forcibly minimized by the OS (see keyboard locked question below). Instead, we use P/Invoke calls to set the application window as the foreground window:
using System.Runtime.InteropServices;
...
[DllImport("coredll.dll")]
public static extern IntPtr GetActiveWindow();
[DllImport("coredll.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
/// <summary>
/// Make application visible and give focus
/// Bring application to foreground
/// </summary>
/// <param name="form">Main form of application</param>
public static void BringToForeground(Form form)
{
#region MAKE MAIN FORM ACTIVE WINDOW
form.Show();
form.Focus();
#endregion
#region MAKE ACTIVE WINDOW FOREGROUND WINDOW
IntPtr handlewin = GetActiveWindow();
if (handlewin != IntPtr.Zero)
SetForegroundWindow(handlewin);
#endregion
}
Why does the application disappear when the device is keyboard locked?
Flip-phones and slide phones, like the HTC Shadow, become device/keyboard locked automatically when shut, whereas candybar-style phones typically have a button-press sequence to lock and unlock the device. This prevents the user from inadvertantly pressing buttons - a common occurrence when carrying a phone in a pocket or bag.
We have observed in one model of Smartphone (HTC Dash) the phenomenon where applications get minimized when the device keyboard is locked. Instead, the phone desktop is displayed. This is not a critical issue, except when trying to prompt the user. An application that tries to put itself in the foreground will not succeed as long as the phone is unlocked, and after the user unlocks the phone, the application will not suddenly appear in the foreground unless the application knows to try again. The application can use vibration and/or sound to notify the user of an event, but the user will be unable to interact with the application unless it is brought to the foreground in a timely fashion after the user has unlocked the phone.
One approach to this issue is to continually try to bring the application to the foreground until interaction with the UI is recorded. It's not possible to check whether the application is visible/in front/etc., because it may think it is when it's not.
The other approach is to continually check the keyboard lock status of the phone (by monitoring a registry setting) and to trigger a "bring to front" method on unlock (using sound and vibration to the get user's attention while the device is locked). The registry setting that reflects the keyboard lock status (on the phones we tested), is HKEY_LOCAL_MACHINE\System\State\Lock. You can browse two classes used for this solution here.
We experimented with unlocking the device programmatically, but found that even though we could change the registry setting, the "unlocking" UI that the OS uses never gets the update that this has happened (the device may be unlocked, but the UI does not know that it's unlocked). We explored alternatives (such as trying to simulate the unlock key sequence), but decided that it does not make a lot of sense to unlock the phone programmatically anyway, when the user might mistakenly press a button when retrieving the device.
When the unlock status has been detected, it may not be enough to use this.Show() or this.BringToFront() to get the applicatin to the foreground - please see question above about how to use a P/Invoke call as an alternative.
How do you signal the phone to reboot from your application?
using System.Runtime.InteropServices;
...
[DllImport("aygshell.dll")]
private extern static int ExitWindowsEx(int dwFlags, int dwReason);
const int EWX_AYG_REBOOT = 2;
const int SHTDN_REASON_MAJOR_APPLICATION = 0x00040000;
ExitWindowsEx(EWX_AYG_REBOOT, SHTDN_REASON_MAJOR_APPLICATION);
How do you kill a process?
If you need to kill another process programmatically from code running on the device, you can use P/Invoke calls:
using System.Runtime.InteropServices;//Needed for P/Invoke
...
#region P/INVOKE
private const int PROCESS_TERMINATE = 1;
private const int INVALID_HANDLE_VALUE = -1;
[DllImport("coredll.dll")]
private static extern IntPtr OpenProcess(int flags, bool fInherit, int PID);
[DllImport("coredll.dll")]
private static extern bool TerminateProcess(IntPtr hProcess, uint ExitCode);
[DllImport("coredll.dll")]
private static extern bool CloseHandle(IntPtr _handle);
#endregion
public void Kill()
{
IntPtr hProcess;
hProcess = OpenProcess(PROCESS_TERMINATE, false, (int)_handle);
if (hProcess != (IntPtr)INVALID_HANDLE_VALUE)
{
bool bRet = TerminateProcess(hProcess, 0);
CloseHandle(hProcess);
}
}
This code is used by the RemoteAppUpdater to close the application that is being updated before it begins replacing files (including DLLs and EXE files).
If you are just looking to kill a process manually on the device, you can go to the Start menu on the phone and find the "Task Manager." This will list the applications that are running that have a UI and you can stop any or all of these processes through this interface.
If you are trying to stop a process without a UI (for example, a console application like the WatchDog), Task Manager won't work. Instead, you may want to try the XDA tool, "pkill.exe," which can be run from the PC with the device connected by USB through ActiveSync. A batch file that calls this tool for killing the WatchDog is available in the project source code.
How do you set an application to start minimized (hidden)?
If you have an application with a UI (as opposed to a console appliation), the program.cs file in your project calls Application.Run(Form1) within the Main method, where Form1 is the main form for your application. The Application.Run method call makes this form visible and brings it to the foreground. Even if you try to set the Visible property of this form within the design-time properties or within the Form constructor or OnLoad method, the form will still pop-up.
If you have an application that "runs alls the time" in the background and only supposed to be in the foreground during prompts or when the user initiates an interaction, you may want to start the application minimized.
The best way we have found to do this is to add a Timer to the main form with an interval of 1 msec and enable it through the design-time properties or within the Form constructor. Override the tick event for this Timer and within that method, minimize the application and then disable the Timer (e.g., timerHideStartup.Enabled = false;), as it only needs to run once.
private void timerHideStartup_Tick(object sender, EventArgs e)
{
timerHideStartup.Enabled = false;
Minimize(this); //see below for this method
}
The above suggestion is based on a solution by Christopher Fairbairn.
How do you minimize an application?
Because this.Hide() can result in the application not appearing in the Task Manager, and sometimes not being re-launchable (while running) by clicking on the .exe or an application shortcut, which you may want users to be able to do, we recommend using P/Invoke to Minimize the applications:
using System.Runtime.InteropServices; // support P/Invoke
...
#region P/INVOKE
[DllImport("coredll.dll")]
static extern int ShowWindow(IntPtr hWnd, int nCmdShow);
const int SW_MINIMIZED = 6;
#endregion
public static void Minimize(Form form)
{
try
{
// The Taskbar must be enabled
form.FormBorderStyle = FormBorderStyle.FixedDialog;
form.WindowState = FormWindowState.Normal;
form.ControlBox = true;
form.MinimizeBox = true;
form.MaximizeBox = true;
// Since there is no WindowState.Minimize,
// we have to P/Invoke ShowWindow
ShowWindow(form.Handle, SW_MINIMIZED);
}
catch
{
form.Hide();//Last resort
}
}
The above minimize code is based on a solution by Christian Helle.
|