Google Maps

In this lecture, we learn how to incorporate Google Maps into applications - this is very cool. We have all used Google Maps on laptop browsers and smartphones but only as user up until now.

We will first learn how to create a map activity. Then through a simple demos app we get a sense of the main programming features needed to construct and control maps.

What this lecture will teach you

Demo projects

The demo code used in this lecture include:

This app will provide the necessary background to implement maps for MyRuns4.

Resources

Running the demo code

To get the existing demo code to run on your phone, you need to (1) create a Maps API key using Google Console; and (3) replace the existing Maps API key in the demo code’s google_maps_api.xml file with your new Maps API key. If you don’t do this and just run the demo code you will see a blank screen.

Here is what you have to do to get the demo code to work:

  1. In order to create your key read Maps SDK for Android Quickstart. OK now you have your Map API key.

  2. Finally, you need to replace the existing key with your new key (as shown below) to in the google_maps_api.xml file under the values directory. Note, you do not have to add this to the manifest file.


<resources>
<string name="google_maps_key" templateMergeStrategy="preserve">AIzaSyDVlNw0hUMQYRhQXdrPAScw5HkJ_bkSg74</string>
</resources>

Creating Google Maps Activity

Above we explained how to run the demo code. Here we explain how to create a new app from scratch.

The overall process of adding a Google Map to an Android application is as follows:

STEP 1: Add a Google Maps Activity to your project

  1. As shown in figures below, you can either create a Google Maps Activity project from scratch (left) or add a Google Maps Activity (right) to your existing projects (e.g, MyRuns).
  1. Have a first look of the generated MapsActivity. It extends itself from a FragmentActivity, containing a GoogleMap instance. onMapReady() will be called when GoogleMap is ready.

STEP 2: Obtain an API key for Google Maps v2.0

  1. Go to google_maps_api.xml, you will find a generated url in the comments. This url is generated using the unique SHA-1 key of your current computer and the package name of the app. We also notice that there is a placeholder ("YOUR KEY HERE") specifying the "google_maps_key". We need to get the key from the Google API Console and fill it in.
  1. Copy this link to your browser and hit Enter, you will be directed to a page on the API console as shown below:
  1. Hit "Continue" and "Create" to proceed. Follow the procedure and once it is completed, you will be presented with the page like below. Copy the API Key back to the key placeholder in the xml file.
  1. There are a number of meta-data and uses-permissions added to the Manifest file by Android Studio. Once you have the API key you added to google_maps_api.xml, you will find the meta-data for the api key in Manifest is updated as well (shown below). Now you are done with the setup for a Google Maps Activity.

Demo app

A part of this demo app is an extension of the applications we developed for the lecture on the LocationManger, where we get the current longitude and latitude of your location. So in the code examples below we snip some of the code that we have already discussed in the pervious lecture. You can look at the demo app source code to see the complete source code.

Much of the structure of the code is familiar now.

Set up Google Maps in onCreate()

The code first gets a reference to a GoogleMap using getSupportFragmentManager on a getSupportMapFragment set up in layout/activity_main.xml, as shown below in the layout file

<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MapsActivity" />

The getMap() method renders the Google Map returned from the server into the SupportMapFragment in layout. The type of map is then set to normal.

There are a number of types of maps that can be selected:

Change the type of the map in your code and look at the map rendered.

mMap.mapType = GoogleMap.MAP_TYPE_NORMAL

After the map type is set we get the current location and set a marker at that location and zooms in. The location manager sets up the time and distance parameters as well as the call back listener for location updates:

locationManager.requestLocationUpdates(provider, 0, 0f, this)

Animating the map

Upon the launch of the app, we pan the map to the user's current location, zoom in a bit, and drop a Marker at the user's location. For the animation part, we use CameraUpdateFactory to specify the target location using a LatLng object and zoom level by passing a Float number (e.g., 17f in our case). The actual animation is done by calling the animateCamera() function on the Map object with a CameraUpdate object as an argument. Dropping a Marker on the map is done by calling addMarker() on the Map object with a MarkerOptions object as an argument to specify the target location.

val cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, 17f)
mMap.animateCamera(cameraUpdate)
markerOptions.position(latLng)
mMap.addMarker(markerOptions)

Adding markers and drawing lines

Our app also allows the user to interact with the map by manually placing markers on the map. The system can automatically connect up the markers with polylines drawn on the map (see the image below). A polyline is a list of points, where line segments are drawn between consecutive points. The app detects long clicks on the map and adds a marker. To remove the lines, the user simply clicks on the map (short click).

The callbacks set up to capture the click events are shown below:

override fun onMapClick(latLng: LatLng) {
for (i in polylines.indices)
polylines[i].remove()
polylineOptions.points.clear()
}

override fun onMapLongClick(latLng: LatLng) {
markerOptions.position(latLng!!)
mMap.addMarker(markerOptions)
polylineOptions.add(latLng)
polylines.add(mMap.addPolyline(polylineOptions))
}