MAPS AND LOCATION APIS FOR WINDOWS PHONE Jukka Silvennoinen Chief Engineer Nokia Developer Offering
Jan 12, 2015
MAPS AND LOCATION APIS FOR WINDOWS PHONE Jukka Silvennoinen Chief Engineer Nokia Developer Offering
CONTENT.
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
• Location API usages • Maps API briefly • Some workarounds • Examples available
LOCATION API USAGES
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
LOCATION API GENERAL INFO
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
• Geolocator API is new for WP8 offers following features: • Accessible from managed and native code • Allows application to specify the desired accuracy of the location as well as maximum time
allowed for acquiring one shot location result • Applications can request location updates after a specified time interval or a distance
threshold is crossed • Convergent with Windows 8 with only minor differences. Most code should be reusable on
both platforms • GeoCoordinateWatcher API still available in Windows Phone 8. • Location tracking applications can be enabled to run in the
background • To enable location features add the capability: ID_CAP_LOCATION to
the manifest file (WMAppManifest.xml)
USING THE GEOCOORDINATEWATCHER API
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
geolocator = new GeoCoordinateWatcher(GeoPositionAccuracy.Default); geolocator.MovementThreshold = 20; // 20 meters geolocator.PositionChanged += geolocator_PositionChanged; … private void Button_Click_1(object sender, RoutedEventArgs e) { if (!tracking){ geolocator.Start(); tracking = true; StarStopBut.Content = "Stop tracking"; } else { geolocator.Stop(); tracking = false; StarStopBut.Content = "Start tracking"; } } … void geolocator_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> args) { latitudeBox.Text = args.Position.Location.Latitude.ToString("0.00"); longitudeBox.Text = args.Position.Location.Longitude.ToString("0.00"); }
USING THE GEOLOCATOR API
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
private void TrackLocation_Click(object sender, RoutedEventArgs e) {
if (!tracking) { geolocator = new Geolocator(); geolocator.DesiredAccuracy = PositionAccuracy.High; geolocator.MovementThreshold = 100; // The units are meters. geolocator.PositionChanged += geolocator_PositionChanged; tracking = true; TrackLocationButton.Content = "stop tracking";
} else { geolocator.PositionChanged -= geolocator_PositionChanged; geolocator = null; tracking = false; TrackLocationButton.Content = "track location"; StatusTextBlock.Text = "stopped";
} } void geolocator_PositionChanged(Geolocator sender, PositionChangedEventArgs args){
Dispatcher.BeginInvoke(() => { LatitudeTextBlock.Text = args.Position.Coordinate.Latitude.ToString("0.00"); LongitudeTextBlock.Text = args.Position.Coordinate.Longitude.ToString("0.00");
}); }
WP8
NOTE THE DIFFERENCE
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
System.Device.Location.GeoCoordinate: http://bit.ly/Yg9rIb • Used by GeoCoordinateWatcher Windows.Devices.Geolocation.Geocoordinate: http://bit.ly/Yg9wvq • used by Geolocator, as well as Maps API in general MyCoord = new System.Device.Location.GeoCoordinate(Position.Coordinate.Latitude, Position.Coordinate.Longitude);
REGISTER FOR BACKGROUND TRACKING
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
In WMAppManifest.xml
In App.xaml:
<shell:PhoneApplicationService Launching="Application_Launching" Closing="Application_Closing" Activated="Application_Activated" Deactivated="Application_Deactivated" RunningInBackground="Application_RunningInBackground"/>
<DefaultTask Name="_default" NavigationPage="MainPage.xaml"> <BackgroundExecution>
<ExecutionType Name="LocationTracking" /> </BackgroundExecution>
</DefaultTask>
WP8
TRACK IF APP IS RUNNING IN BG
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
In App.xaml.cs
// raised when the user navigates away from your app while it is actively // tracking location and your app begins to run in the background private void Application_RunningInBackground(object sender, RunningInBackgroundEventArgs args) {
MyGlobalObject.RunningInBackground = true; // Suspend all unnecessary processing such as UI updates
}
private void Application_Activated(object sender, ActivatedEventArgs e) {
MyGlobalObject.RunningInBackground = false; }
WP8
DEACTIVATION OF APPS RUNNING IN THE BACKGROUND
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
• Event handlers for the PositionChanged and StatusChanged events of the Geolocator are removed.
• GeoCoordinateWatcher.Stop(). • Battery Saver is active. • Device memory is low. • The user disables Location Services on the phone. • Another app begins running in the background. • The app has run in the background for 4 hours without
user interaction..
WP8
MAP API USAGES
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
MAP API GENERAL INFO
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
• New Maps API introduced with Windows Phone 8 • Bing Maps are now deprecated, but will continue to work • Use Bing Maps only when upgrading from WP7.5 • To enable location features add the capability:
ID_CAP_MAP (and maybe also ID_CAP_LOCATION) to the manifest file (WMAppManifest.xml)
• Maps data is shared, and if downloaded before (by any app) you can use it offline.
WP8
ADDING MAP TO THE APP
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
xmlns:maps="clr-namespace:Microsoft.Phone.Maps.Controls;assembly=Microsoft.Phone.Maps" ... <maps:Map
Name="map1" Center="47.6097, -122.3331" ZoomLevel="10" Heading="90" Pitch="45" CartographicMode="Hybrid" ColorMode="Dark" PedestrianFeaturesEnabled="true" HorizontalAlignment="Stretch“ VerticalAlignment="Stretch">
</maps:Map>
WP8
SUPPORTED FUNCTIONALITY
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
Add content • Markers (MapOverlay) • Polylines, polygons (MapElement) • Route
Change settings • animation modes (parabolic, linear, none) • heading, pitch & zoom levels • map color (light/dark) modes • map types (road, Arial, hybrid, terrain) • pedestrian features & landmarks on/off’
Full list of APIs: http://bit.ly/WkUacZ
WP8
User services • Geocoding (convert address to location) • Reverse geocoding (convert location to address) • Routing
ADDING ‘MARKER’
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
Rectangle rect = new Rectangle();
rect.Fill = new SolidColorBrush(Colors.Red);
rect.Height = 15;
rect.Width = 15;
MapOverlay overlay = new MapOverlay();
overlay.Content = rect;
overlay.GeoCoordinate = new GeoCoordinate(47.6097, -122.3331);
overlay.PositionOrigin = new Point(0.5, 0.5);
MapLayer layer = new MapLayer();
layer.Add(overlay);
MyMapControl.Layers.Add(layer);
WP8
ADDING POLYGON
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
WP8
GeoCoordinateCollection RectLocations = CreateRectangle(new GeoCoordinate(60.35, 24.60), new GeoCoordinate(60.25, 24.80)); //Set the polygon properties PolyRect.Path = RectLocations; PolyRect.FillColor = Color.FromArgb(0x55, 0x00, 0x00, 0x00); PolyRect.StrokeColor = Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF); PolyRect.StrokeThickness = 4; map1.MapElements.Add(PolyRect); public static GeoCoordinateCollection CreateRectangle(GeoCoordinate topLeft, GeoCoordinate bottomRight) { var locations = new GeoCoordinateCollection(); locations.Add(new GeoCoordinate(topLeft.Latitude, topLeft.Longitude)); locations.Add(new GeoCoordinate(topLeft.Latitude, bottomRight.Longitude)); locations.Add(new GeoCoordinate(bottomRight.Latitude, bottomRight.Longitude)); locations.Add(new GeoCoordinate(bottomRight.Latitude, topLeft.Longitude)); return locations; }
ROUTE
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
List<GeoCoordinate> points = new List<GeoCoordinate>();
points.Add(new GeoCoordinate(47.603848, -122.029953));
points.Add(new GeoCoordinate(47.669444, -122.123889));
RouteQuery query = new RouteQuery();
query.Waypoints = points;
query.QueryCompleted += MyQuery_QueryCompleted;
query.QueryAsync();
void MyQuery_QueryCompleted(object sender, QueryCompletedEventArgs<Route> e)
{
Route route = e.Result;
MapRoute mapRoute = new MapRoute(route);
MyMapControl.AddRoute(mapRoute);
foreach (RouteLeg leg in MyRoute.Legs)
{
foreach (RouteManeuver maneuver in leg.Maneuvers)
maneuver.InstructionText;
}
}
WP8
REVERSEGEOCODING
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
ReverseGeocodeQuery geoQ = new ReverseGeocodeQuery(); geoQ.QueryCompleted += geoQ_QueryCompleted; geoQ.GeoCoordinate = map1.Center; geoQ.QueryAsync(); void geoQ_QueryCompleted(object sender, QueryCompletedEventArgs<IList<MapLocation>> e) { if (e.Result.Count() > 0) { string showString = e.Result[0].Information.Name; showString = showString + "\nAddress: "; showString = showString + "\n" + e.Result[0].Information.Address.HouseNumber; showString = showString + "\n" + e.Result[0].Information.Address.Street; showString = showString + "\n" + e.Result[0].Information.Address.PostalCode; showString = showString + "\n" + e.Result[0].Information.Address.City; showString = showString + "\n" + e.Result[0].Information.Address.Country; showString = showString + "\n" + e.Result[0].Information.Address.CountryCode; showString = showString + "\nDescription: "; showString = showString + "\n" + e.Result[0].Information.Description.ToString(); MessageBox.Show(showString); } }
WP8
SOME LIMITATIONS AND WORKAROUNDS
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
NO DIRECT WAY FOR FITTING CONTENT(1/2)
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
WP8
LocationRectangle setRect = null; setRect = LocationRectangle.CreateBoundingRectangle(myPolyGon.Path); map1.SetView(setRect);
LocationRectangle setRect = null; GeoCoordinate[] geoArr = new GeoCoordinate[markerLayer.Count()]; for (var p = 0; p < markerLayer.Count(); p++) { geoArr[p] = markerLayer[p].GeoCoordinate; } setRect = LocationRectangle.CreateBoundingRectangle(geoArr); map1.SetView(setRect);
NO DIRECT WAY FOR FITTING CONTENT´(2/2)
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
double north = 0; double west = 0; double south = 0; double east = 0; north = south = polyline.Path[0].Latitude; west = east = polyline.Path[0].Longitude; foreach (var p in polyline.Path.Skip(1)) { if (north < p.Latitude) north = p.Latitude; if (west > p.Longitude) west = p.Longitude; if (south > p.Latitude) south = p.Latitude; if (east < p.Longitude) east = p.Longitude; } setRect = new LocationRectangle(north, west, south, east); map1.SetView(setRect);
WP8
HIDING CONTENT
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
if (markerLayer != null){ for (var i = 0; i < markerLayer.Count(); i++){ Ellipse markker = (markerLayer[i].Content as Ellipse); if (markker != null){ if (markker.Visibility == System.Windows.Visibility.Visible){ markker.Visibility = System.Windows.Visibility.Collapsed; }else{ markker.Visibility = System.Windows.Visibility.Visible; } } } }
if (poly.StrokeColor == Color.FromArgb(0xFF, 0x00, 0x00, 0xFF)){ poly.FillColor = Color.FromArgb(0x00, 0x00, 0xFF, 0x00); poly.StrokeColor = Color.FromArgb(0x00, 0x00, 0x00, 0xFF); }else{ poly.FillColor = Color.FromArgb(0x55, 0x00, 0xFF, 0x00); poly.StrokeColor = Color.FromArgb(0xFF, 0x00, 0x00, 0xFF); }
WP8
MAKING DRAGGABLE MARKERS (1/2)
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
Add event handled for the touch events: System.Windows.Input.Touch.FrameReported += Touch_FrameReported;
Add internal boolean variable draggingNow to indicate dragging status and set it to dragging inside mouse handler set for the marker. Also disable the map while we do dragging
void marker_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)) { if (oneMarker != null){ draggingNow = true; map1.IsEnabled = false; } }
WP8
MAKING DRAGGABLE MARKERS (2/2)
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
In Touch_FrameReported move the marker with touch events, and stop dragging with TouchAction.Up: void Touch_FrameReported(object sender, TouchFrameEventArgs e){ if (draggingNow == true) { TouchPoint tp = e.GetPrimaryTouchPoint(map1); if (tp.Action == TouchAction.Move){ if (oneMarker != null) { oneMarker.GeoCoordinate = map1.ConvertViewportPointToGeoCoordinate(tp.Position); } }else if (tp.Action == TouchAction.Up){ draggingNow = false; map1.IsEnabled = true; } } }
WP8
SAVE/SHARE MAP IMAGE
private void SaveButton_Click(object sender, EventArgs e) { WriteableBitmap wb = new WriteableBitmap(mapControl, null); wb.Render(mapControl, null); MemoryStream memoryStream = new MemoryStream(); wb.SaveJpeg(memoryStream, wb.PixelWidth, wb.PixelHeight, 0, 80); MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("SavedMap_" + DateTime.Now.ToString() + ".jpg", memoryStream.GetBuffer()); }
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
EXAMPLES
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
ALL IN ONE PLACE
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
Nokia project: http://projects.developer.nokia.com/WP8MapsExamples
WP8
1. Hello Map 2. Map events 3. Map interaction 4. Simple Map content 5. More Map content 6. Draggable Marker 7. Map markers 8. Dynamic polyline 9. My Location 10. Geo Coding 11. Reverse Geo coding
12. Routing 13. Advanced Routing 14. Location Selector 15. Area Selector 16. LaunchDirectionsTask 17. LaunchMapSearchTask 18. LaunchMapTask 19. GetMyGeoposition 20. TrackMyPosition And TrackMyPositionTwo 21. TrackMeInBackground
4/18/2013 © 2012 Nokia. All rights reserved. © 2012 Microsoft. All rights reserved.
Thank you!