Tracking your GPS-enabled Mobile Phone

Introduction

Tracking applications are increasingly popular. People appear to track everything: their vehicles, their employees, their children and even their pets. There are plenty of such applications which use Virtual Earth. Most of these applications are not publicly accessible but there are also some which everybody can access over the web such as iFly.com’s Flight Tracker

image

…or BCFerries

image

We also find more and more GPS-enabled devices and there is an increasing trend of using these devices to track not just vehicles but also outdoor activities, expeditions or bicycle-races or to map your own position, so that your friends and family know where you are. Particularly with more and more social networks popping up there will certainly be many more use cases.

The following sample is addressing these kind of scenarios and I will demonstrate how you can relatively easy create a basic tracking application. Please keep in mind, that this sample is just meant to be demo. It is not secure and there is plenty of room for improvement but it shows the basic principle.

The Idea

On the mobile device, we want to capture the location via GPS and either display the results, store them in a local SQL Server Compact Edition or send them to a remote SQL Server. For the latter we will create a HTTP request to a web service or Generic Web Handler which creates and executes an INSERT-Statement on behalf of the mobile device. This is just for simplicity of this sample. In a real-live application you would probably want to set up something like remote SQL via the ‘SQL Server Web Synchronisation Agent’ or an IP-channel communication.

The web application to display the track is in our sample a HTML-Document with some JavaScript-code to display the map and create an AJAX-call to a web service which retrieves and updates the data from our database in a pre-defined interval.

image

What we need

  1. a mobile phone with build-in or attached GPS. I am using my Orange SPV M700
  2. The Orange SPV M700 is a Windows Mobile 5 phone so I will use for the development Visual Studio 2008 and the Windows Mobile 5.0 SDK for Pocket PC.
  3. The .NET Compact Framework is part of the Visual Studio and can be deployed automatically during the development. However, if you need a redistributable package you will find it here.
  4. For the live-tracking part we wouldn’t need it but since I want to be able to store my outdoor-activities on the device even if I don’t have an Internet connection I’m also using a SQL Server Compact. Again this is already part of Visual Studio but you can find a downloadable version as well here.
  5. Well of course we also need a database and a web server for our live-tracking application.

The Windows Mobile Application

If you are a Windows Mobile developer you probably discovered already that the Window Mobile SDK comes some samples. These samples are by default in the folder "C:Program FilesWindows CE Toolswce500Windows Mobile 5.0 Pocket PC SDKSamplesCs" and amongst them you will find one sample which demonstrates the use of GPS through the "GPS Intermediate Driver" which was introduced with Windows Mobile 5. Using this driver has 2 major advantages:

  • You don’t need to know for which COM-port the GPS is configured and
  • You don’t need to deal with the parsing of the GPS-output

We will use this sample as a baseline for our Windows Mobile application or rather we will use the helper classes in the Microsoft.WindowsMobile.Samples.Location-project. So let’s fire up Visual Studio and create a new ‘Smart Device Project’ for Windows Mobile 5 Pocket PCs. This will create automatically a Form and on this form we drop a couple of controls:

  • A TabControl with 2 TabPages labelled ‘Status’ and ‘Setup’
  • On the first TabPage we drop a label lblStatus
  • On the second TabPage we drop some labels and ComboBoxes as shown below. In these ComboBoxes we will set some thresholds. Since we probably don’t need continuous tracking we allow to set intervals for when the next position is being logged. The logging shall be triggered based on elapsed time, distance from the last logged location or change in heading. In this example we create the following items for the ComboBoxes:
    • cbDistance: 10, 20, 50, 100, 500, 1000
    • cbHeading:15, 30, 45, 90
    • cbTime: 5, 10, 20, 30, 60, 120, 300, 600
  • A menu with the items as show below
    • mShow as a option to just show the position (this MenuItem will have the property checked)
    • mStoreLocal to store the data in my local SQL Server Compact Edition
    • mStoreRemote to send the data to a remote SQL Server
    • mStart to start the GPS and begin the tracking
    • mStop to stop the GPS and finish tracking (this MenuItem will have the property Enabled=False):
    • mExit to stop the GPS, finish tracking and exit the application

image

Before we start writing our code for this Form we add another project of type ‘Class Library’ to our solution and into this new project we add the following classes from the Windows Mobile 5 sample project ‘Microsoft.WindowsMobile.Samples.Location’:

image

All right, now let’s start coding in our Form1.vb class:

First we will import a few namespaces which we will need later on:

Imports GpsUtilsCF 'Our GPS Utilities 
Imports System.Data.SqlServerCe 'For the local option
Imports System.Net 'for the remote option we create web requests
Imports System.IO 'we need the StreamReader to deal with the response from the web request
Imports System.Text 'this is needed for the encoding of the response

In the class Form1 we start with some global declarations:

    'Declarations for GPS
    Dim gps As GPS = New GPS
    Dim updateDataHandler As EventHandler
    Dim device As GpsDeviceState = Nothing
    Dim position As GpsPosition = Nothing

    'Declarations for SQL CE
    Dim adp As SqlCeDataAdapter = New SqlCeDataAdapter
    Dim conn As New SqlCeConnection("Data Source = 'My DocumentsGPS.sdf'")
    Dim cmd As SqlCeCommand = conn.CreateCommand
    Dim DevName As String = System.Net.Dns.GetHostName

    'dummy's
    'A record is logged every 5 minutes ...
    Dim UTCdummy As DateTime
    Dim myTimeThreshold As Integer
    '... or if the heading changes for more than 45 degrees ...
    Dim HeadingDummy As Double
    Dim myHeadingDummy As Integer
    '... or if the distance between the current and the last position is more than 1000m
    Dim LatDummy As Double = 0
    Dim LonDummy As Double = 0
    Dim myDistanceThreshold As Integer

Now let’s deal with the Form_Load-event. We set the preferences for the thresholds in the setup-page and display a status message. Afterwards we define a few handlers which determine if the status of the GPS has changed and if the location has been changed.

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
    cbDistance.Text = cbDistance.Items.Item(5)
    myDistanceThreshold = cbDistance.Text
    cbHeading.Text = cbHeading.Items.Item(2)
    myHeadingDummy = cbHeading.Text
    cbTime.Text = cbTime.Items.Item(6)
    myTimeThreshold = cbTime.Text
    lblStatus.Text = "Application Loaded"
    updateDataHandler = AddressOf UpdateData
    AddHandler gps.DeviceStateChanged, AddressOf gps_DeviceStateChanged
    AddHandler gps.LocationChanged, AddressOf gps_LocationChanged
End Sub

The 2 handlers for the leverage classes from the Windows Mobile SDK sample and will invoke the handler to update the data in the UI or in the database depending on the selected option.

    Protected Sub gps_LocationChanged(ByVal sender As Object, ByVal args As LocationChangedEventArgs)
        position = args.Position
        ' call the UpdateData method via the updateDataHandler
        Try
            Invoke(updateDataHandler)
        Catch ex As Exception
            lblStatus.Text = ex.Message.ToString
        End Try
    End Sub

    Private Sub gps_DeviceStateChanged(ByVal sender As Object, ByVal args As DeviceStateChangedEventArgs)
        device = args.DeviceState
        ' call the UpdateData method via the updateDataHandler
        Try
            Invoke(updateDataHandler)
        Catch ex As Exception
            lblStatus.Text = ex.ToString
        End Try
    End Sub

The updateDataHandler calls our main function. We determine which of the options has been selected. If we just want to display the data we use some classes from the Windows Mobile SDK sample to retrieve the location and some other information. We the use these information to build a string and update the UI:

    Private Sub UpdateData(ByVal sender As Object, ByVal args As System.EventArgs)
        If gps.Opened Then
            If mShow.Checked = True Then
                'Update the Form
                Dim str As String = ""

                If Not device Is Nothing Then
                    str = device.FriendlyName.ToString + " " _
                        + device.ServiceState.ToString + ", " _
                        + device.DeviceState.ToString + "" & vbLf
                End If

                If Not position Is Nothing Then
                    If position.LatitudeValid Then
                        str = str + "Latitude (DD):" & vbLf & "   " _
                            + position.Latitude.ToString + "" & vbLf
                    End If

                    If position.LongitudeValid Then
                        str = str + "Longitude (DD):" & vbLf & "   " _
                            + position.Longitude.ToString & vbLf
                    End If

                    If position.SeaLevelAltitudeValid Then
                        str = str + "Altitude (m above msl):" & vbLf & "   " _
                            + position.SeaLevelAltitude.ToString + vbLf
                    End If

                    If position.SpeedValid Then
                        str = str + "Speed (knots):" & vbLf & "   " _
                            + position.Speed.ToString + "" & vbLf
                    End If

                    If position.HeadingValid Then
                        str = str + "Heading:" & vbLf & "   " _
                            + position.Heading.ToString + "" & vbLf
                    End If

                    If position.SatellitesInSolutionValid _
                        AndAlso position.SatellitesInViewValid _
                        AndAlso position.SatelliteCountValid Then
                        str = str + "Satellite Count:" & vbLf & "   " _
                            + position.GetSatellitesInSolution.Length.ToString + "/" _
                            + position.GetSatellitesInView.Length.ToString + " (" _
                            + position.SatelliteCount.ToString + ")" & vbLf
                    End If

                    If position.TimeValid Then
                        str = str + "Time:" & vbLf & "   " _
                            + position.Time.ToString + "" & vbLf
                    End If
                End If
                lblStatus.Text = str

If we selected the option to insert into our local SQL Server Compact Edition, we build and execute a SQL Statement:

            Else
                'Update the local and remote database
                If Not position Is Nothing Then
                    If position.Time >= UTCdummy.AddSeconds(myTimeThreshold) _
                    OrElse position.Heading >= HeadingDummy + myHeadingDummy _
                    OrElse position.Heading <= HeadingDummy - myHeadingDummy _
                    OrElse CalcDistance(LatDummy, LonDummy, position.Latitude, position.Longitude) >= myDistanceThreshold Then
                        UTCdummy = position.Time
                        HeadingDummy = position.Heading
                        LatDummy = position.Latitude
                        LonDummy = position.Longitude
                        cmd.CommandText = "INSERT INTO Tracks (DevName, GPSdate, GPStime, Lat, Long, Alt, Speed, Heading) VALUES(" & _
                          "'" & DevName & "', " & _
                          "'" & Microsoft.VisualBasic.Left(position.Time.ToString, 8) & "', " & _
                          "'" & Microsoft.VisualBasic.Right(position.Time.ToString, 8) & "', " & _
                          position.Latitude & ", " & _
                          position.Longitude & ", " & _
                          position.SeaLevelAltitude & ", " & _
                          position.Speed & ", " & _
                          position.Heading & ")"
                        adp.InsertCommand = cmd
                        If mStoreLocal.Checked = True Then
                            adp.InsertCommand.ExecuteNonQuery()
                            lblStatus.Text = "Local SQL Server Mobile being updated"

And if we selected the option to update the remote SQL Server we will build a URL with the GPS-data as parameters before we execute a web request. We will also capture the response and display it in our lblStatus:

                        ElseIf mStoreRemote.Checked = True Then
                            Try
                                Dim url As String = "http://YourWebServer/Insert.ashx" + _
                                  "?Name=" + DevName + _
                                  "&Date=" + Microsoft.VisualBasic.Left(position.Time.ToString, 8) + _
                                  "&Time=" + Microsoft.VisualBasic.Right(position.Time.ToString, 8) + _
                                  "&Lat=" + position.Latitude.ToString + _
                                  "&Long=" + position.Longitude.ToString + _
                                  "&Alt=" + position.SeaLevelAltitude.ToString + _
                                  "&Speed=" + position.Speed.ToString + _
                                  "&Heading=" + position.Heading.ToString
                                Dim req As WebRequest = WebRequest.Create(url)
                                Dim result As WebResponse = req.GetResponse()
                                Dim ReceiveStream As Stream = result.GetResponseStream()
                                Dim encode As Encoding = System.Text.Encoding.GetEncoding("utf-8")
                                Dim sr As New StreamReader(ReceiveStream, encode)
                                lblStatus.Text = sr.ReadToEnd.ToString
                            Catch ex As Exception
                                lblStatus.Text = ex.Message.ToString
                            End Try
                        End If
                    End If
                End If
            End If
        End If
    End Sub

You may have seen that we called a function CalcDistance to determine the distance between the most recent location and the previous one. For relatively short distances the following approximation will do:

Private Function CalcDistance(ByVal fromLat As Double, ByVal fromLon As Double, ByVal toLat As Double, ByVal toLon As Double) As Double
    Dim rad As Double = 6371000 'Earth radius in m
    'Convert to radians
    Dim p1Lat As Double = fromLat / 180 * Math.PI
    Dim p1Lon As Double = fromLon / 180 * Math.PI
    Dim p2Lat As Double = toLat / 180 * Math.PI
    Dim p2Lon As Double = toLon / 180 * Math.PI

    Return Math.Acos((Math.Sin(p1Lon) * Math.Sin(p2Lon) + Math.Cos(p1Lon) * Math.Cos(p2Lon) * Math.Cos((p2Lat - p1Lat)))) * rad
End Function

Well, the difficult part is done. Let’s put some functionality behind the menus. When we start the application we want to open the connection to the GPS as well as to the local database.

    Private Sub mStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mStart.Click
        If Not gps.Opened Then
            gps.Open()
        End If

        conn.Open()
        mStart.Enabled = False
        mStop.Enabled = True
    End Sub

When we stop tracking or close the application we also want to make sure that the database-connection and the connection to the GPS is closed.

    Private Sub mStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mStop.Click
        If gps.Opened Then
            gps.Close()
        End If
        conn.Close()
        'tCheckSQLCE.Enabled = False
        lblStatus.Text = "Tracking stopped"
        mStart.Enabled = True
        mStop.Enabled = False
    End Sub
    Private Sub mExit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mExit.Click
        If gps.Opened Then
            gps.Close()
        End If
        conn.Close()
        Close()
    End Sub

And finally we add some code for our controls to set the options and the thresholds:

Private Sub mShow_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mShow.Click
    mStoreLocal.Checked = False
    mStoreRemote.Checked = False
    mShow.Checked = True
End Sub

Private Sub mStoreLocal_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mStoreLocal.Click
    mStoreLocal.Checked = True
    mStoreRemote.Checked = False
    mShow.Checked = False
End Sub

Private Sub mStoreRemote_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mStoreRemote.Click
    mStoreLocal.Checked = False
    mStoreRemote.Checked = True
    mShow.Checked = False
End Sub

Private Sub cbDistance_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
    myDistanceThreshold = cbDistance.Text
End Sub

Private Sub cbHeading_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
    myHeadingDummy = cbHeading.Text
End Sub

Private Sub cbTime_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
    myTimeThreshold = cbTime.Text
End Sub

Well, that is the first part, Let’s test the local components before we move on. From Visual Studio you can deploy the project directly to your Windows Mobile phone if it is connected to your PC and synchronized via ActiveSync or the Windows Mobile Device Centre. During the deployment all required components like the .NET Compact Framework SQL Server Compact Edition will be installed as well. The only thing that you need to do manually is to copy the data file ‘GPS.sdf’ for the SQL Server Compact Edition to the folder ‘My Documents’. You can create this database directly within the SQL Server Management Studio. For this sample we only need one table with the following columns:

image

Let’s set the time interval to a relatively short period for the test…

Mobile04

…and start with the first option to display the data.

Mobile05

Once you are sure that the GPS receives data…

Mobile06

…switch to local storage.

Mobile07

Now start the Query Analyzer to have a look at the data…

Mobile02

…and verify that the first records have been inserted.

Mobile03

The Web Application

The hard part (at lest for me) is done. Now let’s have a look at the web application. We have to consider 2 parts. Part 1 will receive data from the mobile device and insert it into the SQL Server. Part 2 will will allow us to retrieve the latest position and display it on a map.

Part 1: Receiving Data from the Mobile Phone and Inserting into the database.

Please keep in mind that this is just a quick and dirty example. I need to re-emphasize that this is not secure and should not be used in a production application.

Let’s start by creating a table in our database:

CREATE TABLE [Tracks](
    [ID] [bigint] IDENTITY(1,1) NOT NULL,
    [DevName] [nvarchar](50) NULL,
    [GPSdate] [nvarchar](50) NULL,
    [GPStime] [nvarchar](50) NULL,
    [Lat] [numeric](18, 15) NULL,
    [Long] [numeric](18, 15) NULL,
    [Alt] [numeric](5, 0) NULL,
    [Speed] [numeric](3, 0) NULL,
    [Heading] [numeric](3, 0) NULL,
 CONSTRAINT [PK_Tracks] PRIMARY KEY CLUSTERED 
    ([ID] ASC))

Next we create a connection string for our database in the web.config

  <connectionStrings>
    <add name="Tracking"
      connectionString="
        Data Source=YOUR_SERVER;
        Initial Catalog=YOUR_DATABASE;
        uid=YOUR_UID; pwd=YOUR_PASSWORD;"
      providerName="System.Data.SqlClient"/>
  </connectionStrings>

Once this is done we create our web handler. Let’s make sure that we set the culture to something that interprets a ‘.’ as a decimal separator. Then we retrieve the URL-parameters, build our SQL statement, open the database connection and insert the data. Finally we return a message which indicates if the SQL-statement has been successful.

<%@ WebHandler Language="VB" Class="Insert" %>

Imports System
Imports System.Web
Imports System.Data.SqlClient

Public Class Insert : Implements IHttpHandler
    
    Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
        'set culture to en-UK to avoid potential problems with decimal-separators
        System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-UK")
        
        'Get the URL-Parameters
        Dim myName As String = context.Request.Params("Name")
        Dim myDate As String = context.Request.Params("Date")
        Dim myTime As String = context.Request.Params("Time")
        Dim myLat As String = context.Request.Params("Lat")
        Dim myLong As String = context.Request.Params("Long")
        Dim myAlt As String = context.Request.Params("Alt")
        Dim mySpeed As String = context.Request.Params("Speed")
        Dim myHeading As String = context.Request.Params("Heading")

        'Build SQL-Statement
        Dim mySQL As String = "INSERT INTO Tracks (DevName, GPSdate, GPStime, Lat, Long, Alt, Speed, Heading) VALUES ('" + myName + "', '" + myDate + "', '" + myTime + "', " + myLat + ", " + myLong + ", " + myAlt + ", " + mySpeed + ", " + myHeading + ")"
        
        'Prepare database
        Dim settings As ConnectionStringSettings = ConfigurationManager.ConnectionStrings("Tracking")

        Dim myConn As New SqlConnection(settings.ConnectionString)
        myConn.Open()
        Dim myCMD As New SqlCommand(mySQL, myConn)
        
        Try
            myCMD.ExecuteNonQuery()
            context.Response.Write("Remote Update Successful")
        Catch ex As Exception
            context.Response.Write(ex.Message.ToString)
        End Try
    End Sub
 
    Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
        Get
            Return False
        End Get
    End Property

End Class

That’s it run your mobile application and try to store the data remotely:

Mobile08

Part 2: Display the position on a Map

In this part we need the HTML-page which embeds our Virtual Earth map, as well as a JavaScript-file for the coding and another web handler which retrieves the data from the database. Since I really want to keep this example simple I only want to retrieve the latest position from the database; so let’s start with a database view:

CREATE VIEW vTracks
AS
SELECT TOP (1) ID, DevName, GPSdate, GPStime, Lat, Long, Alt, Speed, Heading
FROM Tracks
ORDER BY ID DESC

The HTML page is very basic:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <title>Tracking</title>
    <link href="StyleSheet.css" rel="stylesheet" type="text/css" />
    <script src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6" type="text/javascript"></script>
    <script src="MyScript.js" type="text/javascript"></script>
</head>
<body>
    <div id='divMap' style="position:absolute; top:60px; left:0px; width:400px; height:400px;"></div>
</body>
</html>

We start by declaring some global events which fire when we load the page or resize the browser window. The function that is being executed when the onload-events fires is GetMap(). This function initialises the map and resizes it so that all available space in the browser window is being used. We also set an interval which fires every 5 minutes. When this happens we execute the function Track() which creates an AJAX-call to our second web handler, receives the latest position as response and shows the location on our map. For some more explanation on the database connection have a look at my previous posting.

window.onload = GetMap;
window.onresize = Resize;

//Map
var map = null;
var mapWidth = null;
var mapHeight = null;

//VEShapeLayer
var slTracks = new VEShapeLayer();

function GetMap()
{
    map = new VEMap('divMap');

    //Load and resize the map
    map.LoadMap(new VELatLong(51.461962075378054, -0.9260702133178665), 13, VEMapStyle.Shaded);
    Resize();

    //Add ShapeLayer
    map.AddShapeLayer(slTracks);
    
    //Start Tracking and Set Intervall to 5 minutes
    showtime=setInterval("Track()", 300000);
    Track();
}

//Resize map and controls whenever the size of the browser window changes
//Also load the minimap
function Resize()
{
    var mapDiv = document.getElementById("divMap");
    var windowWidth = document.body.clientWidth;
    var windowHeight = document.body.clientHeight;
    mapWidth = windowWidth;
    mapHeight = windowHeight  - 60;
    mapDiv.style.width = mapWidth + "px";
    mapDiv.style.height = mapHeight + "px";
    map.Resize(mapWidth, mapHeight);
    map.ShowMiniMap(mapWidth-205, 13, VEMiniMapSize.Large);
}

//Tracking
function Track()
{
    //Delete previous tracks
    slTracks.DeleteAllShapes();
    
    //Build the URL
    var url="./Tracking.ashx";

    //Get the appropriate XMLHTTP object for the browser
    var xmlhttp = GetXmlHttp();
    
    //if we have a valid XMLHTTP object
    if (xmlhttp)
    {
        xmlhttp.Open("GET", url, true); //varAsynx = true
        
        //set the callback
        xmlhttp.onreadystatechange = function()
        {
            if (xmlhttp.readystate ==4) //4 is a success
            {
                //server code creates JavaScript "on the fly"
                //execute using eval()
                var result = xmlhttp.responseText
                eval(result);
            }
        }
        xmlhttp.send(null);
    }
}

function GetXmlHttp()
{
    var x = null;
    try
    {
        x = new ActiveXObject("Msxml2.XMLHTTP");
    }
    catch (e)
    {
        try
        {
            x = new ActiveXObject("Microsoft.XMLHTTP");
        }
        catch (e)
        {
            x = null;
        }
    }
    if (!x && typeof XMLHttpRequest != "undefined")
    {
        x = new XMLHttpRequest();
    }
    return x;
}

All that’s left is the web handler which retrieves the data from our database and dynamically creates a JavaScript. On the map we want to show an icon which indicates the direction of the movement; so once we have the latest position retrieved from the database, we set the icon based on the heading. Finally we create a JavaScript which creates the VEShape-object and centres the map before we respond to the AJAX-call.

<%@ WebHandler Language="VB" Class="Tracking" %>

Imports System
Imports System.Web
Imports System.Data.SqlClient

Public Class Tracking : Implements IHttpHandler
    
    Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
        'set culture to en-UK to avoid potential problems with decimal-separators
        System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-UK")

        'Retrieve GPS-Positions
        Dim settings As ConnectionStringSettings = ConfigurationManager.ConnectionStrings("Tracking")
        Dim sb As StringBuilder = New StringBuilder
        Dim myPins As String = ""
        Dim myIcon As String = ""
        Dim myConn As New SqlConnection(settings.ConnectionString)
        Dim myQuery As String = "SELECT Lat, Long, DevName, GPSdate, GPStime, Speed, Heading FROM vTracks"
        Dim myCMD As New SqlCommand(myQuery, myConn)
        myConn.Open()
        Dim myReader As SqlDataReader = myCMD.ExecuteReader()
        While myReader.Read()
            'Determine the CustomIcon based on the heading and speed
            If myReader(5).ToString = "0" Then
                myIcon = "stationary.png"
            Else
                Select Case myReader(6)
                    Case 0 To 22
                        myIcon = "n.png"
                    Case 23 To 57
                        myIcon = "ne.png"
                    Case 58 To 112
                        myIcon = "e.png"
                    Case 113 To 147
                        myIcon = "se.png"
                    Case 148 To 202
                        myIcon = "s.png"
                    Case 203 To 247
                        myIcon = "sw.png"
                    Case 248 To 292
                        myIcon = "w.png"
                    Case 293 To 337
                        myIcon = "nw.png"
                    Case 338 To 360
                        myIcon = "n.png"
                End Select
            End If
                
            myPins = myPins + _
                "var " + myReader(2).ToString + "=new VEShape(VEShapeType.Pushpin, new VELatLong(" + myReader(0).ToString + ", " + myReader(1).ToString + "));" + _
                myReader(2).ToString + ".SetTitle(" + """" + myReader(2).ToString + """" + ");" + _
                myReader(2).ToString + ".SetDescription(" + """" + "Date: " + myReader(3).ToString + "<br>Time: " + myReader(4).ToString + "<br>Speed: " + myReader(5).ToString + "<br>Heading: " + myReader(6).ToString + """" + ");" + _
                myReader(2).ToString + ".SetPhotoURL(" + """" + "http://mappointemea.members.winisp.net/Tracking/Hannes.JPG" + """" + ");" + _
                myReader(2).ToString + ".SetMoreInfoURL(" + """" + "http://johanneskebeck.spaces.live.com/" + """" + ");" + _
                myReader(2).ToString + ".SetCustomIcon('" + myIcon + "');" + _
                "slTracks.AddShape(" + myReader(2).ToString + ");" + _
                "map.SetCenter(new VELatLong(" + myReader(0).ToString + ", " + myReader(1).ToString + "));"
        End While
        sb.Append(myPins)
        myReader.Close()
        myConn.Close()
        context.Response.Write(sb.ToString())
    End Sub
 
    Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
        Get
            Return False
        End Get
    End Property

End Class

Well, that’s it. Have a look at the result. The position will be updated every 5 minutes.

Tracking

The complete sample code is available here:

Advertisements
This entry was posted in Virtual Earth. Bookmark the permalink.

8 Responses to Tracking your GPS-enabled Mobile Phone

  1. Johannes says:

    In the tracking-part of the web application there is a caching issue. To avoid this caching issue make sure you set a random URL-parameter in the function Track():

    //Build the URL
    //The random URL-parameter avoids caching
    var url="./Tracking.ashx?" + Math.random();

  2. BX says:

    Hi Johannes,
     
    Excellent Example, I wanted to do something like this by myself for quite some time!
    Alas, the Code link seems to have vanished, can you provide me with a link, thanks!

  3. Johannes says:

    The embedded links to my SkyDrive are broken. I have now created a href.

  4. Sam says:

    Hi Johannes,
     
    What if I want to build a geofence and send a message to the mobile device that is being tracked when it crosses that geofence?  How do you propose I start?  Thank you kindly.

  5. Ian says:

    Hi Johannes,As you know we do something similar in our Mediaklik product however there are a few issues we have come across with WM6 and the sample GPS code you use:1) There are some bugs around lat long with negative zero values in the sample gps code – we have these fixed.  Let me know if you would like to see them,2) On WM6 there seems to be hardware issues with the GPS device – so sometimes a fix is never found, and other times the device will freeze completely (requiring a reset).  We have demonstrated this on multiple WM6 devices.  I suspect that this is to do with power management, but have not got to the bottom of it yet.- if you have any insight to that it would be great.CheersIan

  6. Mo says:

    Hi All
     
    Used likewise code in c# and works a treat at VoyageMap.com
    However I did find that when indoors the accuracy of the GPS device inside Windws Mobile 6 phone was sometimes poor. But dont think that this was because of the code as I tested out on TomTom software and it reported the same incorrect location. Also while out and about the GPS system inside Pocket PC took a while to locate position. I think this is due to the fact that integrated GPS within Mobile devices are of a poor quality. But it was great fun developing for windows mobile 6 device and capturing location – position information to a website via web service. Thanks all that helped at Microsoft with sample code keep the good work up
    regards
    Mo

  7. Chukwunonso says:

    Will it work with voyager?and LG enVim sorry i didnt read everythingbut it seem like you need phone with windows mobile runing on it

  8. Chukwunonso says:

    Visual studio expression Ediction? or standard?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s