Google Maps Integration

A pair of latitude/longitude numbers on a Trail is useful data, but it means nothing visually to a user until it's actually drawn on a map. This lesson adds the Google Maps SDK to TrailLog and puts the last two lessons' work — a trail's saved location, and a stream of GPS points gathered while tracking a hike — onto an actual map.

Adding the SDK and an API Key

The Maps SDK is added as a Gradle dependency, same as any other library:

dependencies {
    implementation("com.google.android.gms:play-services-maps:19.0.0")
}

Beyond the dependency, Google Maps also requires an API key, obtained from the Google Cloud Console by enabling the "Maps SDK for Android" for a project and generating a credential restricted to your app. That key goes into AndroidManifest.xml, inside the <application> tag:

<meta-data
    android:name="com.google.android.geo.API_KEY"
    android:value="YOUR_API_KEY_HERE" />

In a real project this key should be kept out of source control (loaded from a local, untracked properties file at build time) rather than committed directly into the manifest — the placeholder above is only to show where the key ultimately needs to end up.

A Map in the Trail Detail Screen

TrailLog's trail-detail screen — the same one from Activities & Intents that shows a trail's notes and photo — gets a SupportMapFragment added to its layout to show where the hike took place:

<fragment
    android:id="@+id/trailMapFragment"
    android:name="com.google.android.gms.maps.SupportMapFragment"
    android:layout_width="match_parent"
    android:layout_height="220dp" />

Getting a GoogleMap Object Asynchronously

The map fragment doesn't hand you a usable GoogleMap object right away — the map's tiles and underlying SDK need a moment to initialize first. That's why it's fetched through a callback, getMapAsync { }, rather than returned synchronously:

val mapFragment = supportFragmentManager
    .findFragmentById(R.id.trailMapFragment) as SupportMapFragment

mapFragment.getMapAsync { googleMap ->
    // googleMap is now ready to use — add markers, move the camera, etc.
    showTrailOnMap(googleMap, trail)
}

Adding a Marker for a Trail's Location

Once googleMap is available, dropping a pin at the trail's saved coordinates is a single call:

private fun showTrailOnMap(googleMap: GoogleMap, trail: Trail) {
    val trailLatLng = LatLng(trail.latitude, trail.longitude)

    googleMap.addMarker(
        MarkerOptions()
            .position(trailLatLng)
            .title(trail.name)
    )
}

Drawing a Polyline for the Full Hike Route

A single marker only shows where a trail ended up being logged. The genuinely satisfying TrailLog feature is drawing the entire route — every GPS point collected by the continuous location tracking from Fused Location Provider — connected into one continuous line with Polyline:

private fun drawHikeRoute(googleMap: GoogleMap, routePoints: List<LatLng>) {
    googleMap.addPolyline(
        PolylineOptions()
            .addAll(routePoints)
            .width(8f)
            .color(Color.parseColor("#2196F3"))
    )
}

routePoints here is simply the list of LatLng values accumulated while HikeTrackingService was actively collecting location updates — the same data captured in the previous lesson, now rendered visually as the exact path the hike followed.

Focusing the Camera on a Marker

By default the map opens centered on the globe, not on the trail you actually care about. animateCamera() smoothly moves the visible viewport to focus on it:

googleMap.animateCamera(
    CameraUpdateFactory.newLatLngZoom(trailLatLng, 14f)
)

The second argument is a zoom level — higher numbers zoom in further; 14f is a reasonable default for viewing a single local trail.

Note: This XML layout and Kotlin code are correct, real Google Maps SDK usage, but this website's own project doesn't run a live Android Studio build, so nothing here executes on the page itself.

Matching the Map's Style to TrailLog's Theme

By default Google Maps renders with its own standard colors, which can clash with an app's own theme — particularly the dark mode covered in Theming & Dark Mode. Google Maps supports custom map styling through a JSON style document (generated via the Cloud Console's styling tool and loaded with MapStyleOptions), letting road colors, water, and labels be tuned to match TrailLog's own palette rather than looking like a visually separate app pasted into a screen.

Up next: A finished trail with a route and a photo is worth sharing. Sharing & Implicit Intents covers sending it out to any other app the user chooses.