Developing for Mobile Devices Lab (Part 2 of 2) Overview In the previous lab you learned how to create desktop and mobile applications using Visual Studio. Two important features that were not covered are accessing native code and accessing mobile communication hardware. Accessing native code is extremely important in mobile device development, as many low-level functions are only available through native access - such as reading a deviceʼs battery levels, or making a phone vibrate. Similarly, accessing mobile communication hardware is vital on mobile devices to access the Internet, communicate with other mobile devices, sense the environment, and to drive P2P systems. Today we will examine how to do these two tasks. The work in this lab assumes you have completed the previous lab and so does not go into much detail in creating projects. If you have not done the first lab, please ask for a copy of the first lab sheets and spend todayʼs lab doing that instead. Please note that from the start of this lab you will need access to mobile hardware, as a lot of the examples will not run on the emulator (for example, you can not scan for Bluetooth devices using the emulator as it has no physical BT hardware). Unfortunately, there may not be enough devices for everyone to use at once. Therefore, please try to work with someone else whenever you can so as you can share a device between two. Accessing Native Code Accessing native code is important both in desktop and mobile applications. Native code is often much faster than managed code, and can provide access to hardware or low-level system functions that are not available from managed code alone. This example uses a call to native code to power off the device. This is typical of the type of task that can not be done in managed code, and instead requires a call to native code to access the lowlevel power functions. The native code to call the power functions is held in the coredll dynamic link library, which contains the majority of the Windows API on a mobile device, and is equivalent to the kernel32 DLL in desktop versions of Windows. In Visual Studio create a new C#, Windows Mobile 5 SmartPhone, Device Application project called ʻNativeAccessʼ. While doing this, name the solution ʻHCI4Lab2ʼ so that you have a single workspace for all of todayʼs work. Use the screenshot in figure 1 to verify that you have entered the correct settings. As before, the location should be the only value that is different, as obviously it will point to somewhere in your own filespace.
Figure 1 In the form that appears, add an ʻExitʼ button to the menu that simply calls Close() when the user clicks it, and add another button called ʻPower Offʼ. Double-click ʻPower Offʼ to create the method that will be called when the user clicks it, but donʼt fill in any code yet. At the top of the code, at the end of the using statements, add the code to use interprocess services...... using System.Windows.Forms; using System.Runtime.InteropServices; Now add the code that imports the power method we need from coredll. Add the following code after the class declaration of Form1 but before the constructor for Form1. The first line can appear confusing due to the lower case ʻLʼs and upper case ʻiʼ. Note that the import on the first line is is DLL Import. [DllImport( coredll.dll )] private static extern void PowerOffSystem(); With this import added you can now call the PowerOffSystem method from anywhere in your class. Add a call to it in the code that is called when the user clicks the ʻPower Offʼ button. private void menuitem2_click(object sender, EventArgs e) { PowerOffSystem(); } Now test your application on a real mobile device (it should work on both phones and PDAs). Note that for accessing native code and any hardware the emulator often does not respond correctly. For example, if you run this code on the emulator it will do nothing when the user clicks the ʻPower Offʼ button. Therefore, it is vital to test calls to native code on real devices to ensure it behaves correctly.
As you can see, using native code can provide access to some very powerful functions. Turning off a mobile device is something that should be used with care, as obviously we would not want to do it when the user did not expect or desire it. Other examples of common native calls allow for setting the system clock, turning on and off any LEDs on the device, vibrating a phone or PDA, making a phone ring, and setting the system volume level. As previously stated, the majority of these native methods are held in coredll on mobile devices. Wireless scanning Using the communication technologies available on mobile devices is important in order to detect and communicate other peers, detect a deviceʼs surroundings and context, and to drive data through a P2P community. In this example we will experiment with accessing 802.11 hardware. Right-click the ʻHCI4Lab2ʼ solution and select Add->New project. When the add new project dialog appears again select a C# WM5 Smartphone project, Device Application, and name it ʻScannerʼ. Use figure 2 to ensure you have entered the correct details. Figure 2 When the form editor opens add an ʻExitʼ menu item and put the standard Close() call in the code that executes when the user selects it. Additionally, remember to right-click the Scanner project in the solution project and set it as the startup project. To access the wireless functions on the mobile device we will use an 802.11 scanner library and a wireless hardware library, which already have code for accessing the native functions required to use the 802.11 hardware. Download the libraries from the following URL... http://www.marekbell.com/files/scan.zip Copy the two files from the zip into the following directory in your filespace... YourFileSpace\HCI4Lab2\Scanner\
Right-click the references in the Scanner project in the solution explorer and select ʻAdd Referenceʼ (figure 3). Figure 3 In the dialog that appears select the browse tab, highlight both ScanLib.dll and WiFiLib.dll, and click OK to add the two DLLs as references (figure 4). Figure 4 At the top of the code add the following lines to the using statements... using ScanLib; using WiFiLib; Before the constructor for Form1 add a class variable called scanner with the following line... private WiFiScanner scanner; Edit the Form1 constructor, add the code to initialise the scanner and hook in a listener that will be called whenever a scan is completed... public Form1() { InitializeComponent(); scanner = new WiFiScanner(); scanner.init(); }
Go back to the GUI editor by selecting Form1 in the solution explorer and clicking the ʻView Designerʼ button (figure 5). Figure 5 Edit the right menu on the form so that it has the entries shown in figure 6. Figure 6 Also add a ListView widget to the form by dragging it from the toolbox onto the form. Try to align and size it so it fits well on the form. In the properties window change the View type of the list from ʻIconʼ to ʻListʼ (figure 7). Figure 7 Now we will add a Timer. A Timer is a simple clock that creates a tick at set intervals. When a timer ticks at the interval you can make it execute any code you want. To add a Timer simply drag the Timer widget from the Toolbox onto the grey area at the bottom of the GUI designer where mainmenu1 is located (figure 8)
Figure 8 If you canʼt see the properties window then select View->Properties from the main menu. In the properties window change the interval of the timer from 100ms to 10000ms (figure 9). Figure 9 Click the little lightning icon in the properties window (it represents ʻeventsʼ). Double-click the blank space in the ʻTickʼ property and you will be taken to the code that is executed when the timer ticks (figure 10).
Figure 10 When the timer ticks we will clear the listview and then add the currently scanned mac addresses. Thus, the list will always show the currently detected access points. Fill in the timer tick event with the following code... private void timer1_tick(object sender, EventArgs e) { // conduct a 1 second scan... AccessPointScan[] aps = scanner.scanaps(1000); // clear the list listview1.items.clear(); } // add the results from the scan to the list foreach (AccessPointScan ap in aps) { listview1.items.add(new ListViewItem(ap.SSID + " : " + ap.mac + " : " + ap.signalstrength)); } Finally, go back to the GUI editor and add methods for the four items in the ʻToolsʼ menu by double-clicking each one. Add the following code for each. // in the Power On method... scanner.poweron = true; // in the Power Off method... scanner.poweron = false; // in the Start method... timer1.enabled = true; // in the Stop method... timer1.enabled = false; Test the application on either a real phone or a real PDA (it wonʼt work on the emulator). When you test the application make sure you select ʻPower Onʼ before ʻStartʼ, otherwise the scans will come back with no findings since the 802.11 card is not powered up. After clicking start youʼll have to wait at least 10 seconds for the scan list to appear. You could easily work around this by manually calling the tick method as soon as the ʻStartʼ button is clicked... timer1_tick(sender, e);
Conclusion In this lab you have learned how to access native code using DllImport, how to conduct 802.11 scans, and how to use a few more GUI widgets in Visual Studio. Calling native code allows access to very powerful, low-level features of mobile devices. The scan data you gather from the 802.11 scanning could potentially form the basis of many different types of applications. For example, you could use it to create a wifi scanner, a positioning system, an application that changes phone profiles (silent, vibrate, loud, etc) based on the 802.11 access points detected, a program to detect nearby peers and then share files, and many others.