Posted:


Editor’s note: Today’s guest blogger is Virginia Suliman, Vice President of Digital Design and Development, Hilton Worldwide. Read how Hilton is experimenting with Google APIs to take the guess work out of the hotel booking and room selection process. Hilton is just one of many customers sharing their story as part of our cross-country road trip, Code the Road.

No one likes surprises when they reserve hotel rooms, so it’s crucial for Hilton that people see exactly what they’ll be getting before they arrive. Currently, Hilton’s HHonors guests can use the HHonors website and app as a one-stop tool to control their on-property experience – from finding the best hotels in the right neighborhoods and booking the most suitable one, to soon, using the app as a room key.
couple_sitting.jpg

With a spirit of constant innovation, we’re always looking for new ways to enhance the guest experience. One way we’re doing so is by experimenting with the Google Maps APIs through proof of concept iPhone app functionality we built to enhance the room selection process during digital check-in. The concept tests a the Street View panoramas, part of the Google Maps SDK for iOS, letting users see on the app the exact view they’ll experience when they get to their hotel room. For example, they could virtually look out their window on the app and select the room that overlooks a park or a quiet street corner.
Businesswoman2.jpg

People care not just about the hotel they stay in, but also about the neighborhood, including what kinds of food, entertainment and amenities are nearby. So in our concept, we also tested a controlled list of businesses and points of interest from the Google Maps Places API for IOS to highlight nearby destinations via the HHonors app, like Lincoln Center in New York City, a great fish restaurant in Boston, or the Centennial Olympic Park in Atlanta.

The full potential of Google APIs sets in when you combine them. If successful, the Maps and Street View panorama concepts could one day fully integrate into our HHonors app or global web portal, which already uses Google Maps Business View to offer panoramic virtual tours of our properties to guests.

We believe that happy travelers are repeat customers who become loyalists. If you feel connected to the experience you’ve had with us, you’re more likely to return and to tell others about it. Through technology, we’re hoping to make it easier for people to find the perfect room, have an unforgettable stay and come back for another adventure.

We were delighted to participate in the Code the Road trip. We hosted the Code the Road bus at our Hilton Chicago property on June 10 and are hosting it at Hilton Headquarters in McLean, Virginia on June 22. You can also see the Hilton HHonors app window-view proof of concept demo on the bus.

Posted:
For our last developer meetup of Code the Road, we were thrilled to be in New York City. We had a great time in the Big Apple visiting with over 200 local developers at our Google New York office on June 18 as well as all of the New York passersby who stopped to take a look inside the bus. We had everyone from a 5 year old boy who was very excited to see Street View imagery of the pyramids to developers joining us for the meetup tour our bus.
C11C1911.jpg

Ankur Kotwal, Developer Advocate at Google, kicked off the night with a great talk about using Google Maps APIs in your iOS or Android App, presenting Maps Zen patterns to help your apps shine.
A043_C006_06183I.0000651.jpg

We welcomed Chase Brammer, Head of iFit Product Development, back to the stage—coming all the way from Utah to give a talk about how Icon Fitness uses the Maps APIs to make workouts more interesting. He did this all while walking on a treadmill. Pretty impressive!
A043_C020_0618YF.0000320.jpg

Aurelia Moser, Map Scientist from CartoDB, delivered a presentation titled 'Hi-Res Human Maps: Google Maps APIs via CartoDB.' She gave us interesting insights on everything from designing maps to maps mashup.
C11C2016.jpg

David McClusky, Solutions Architect, Google Maps for Work, outlined how we can be best prepared for our Maps to go viral by building in them on Google Cloud Platform.
C11C2074.jpg
Rounding out the night, Kedar Sarmalker, Mobile Engineer at TripAdvisor, gave a great talk on how TripAdvisor uses custom markers, polygons, styling and Google Maps APIs in their mobile app.
C11C2088.jpg

After the presentations we had a great time speaking with and learning from all the developers who attended the meetup.
C11C2126.jpg

We'll be sharing more about our trip over the next few days including our visit to Epcot. The bus was parked at Future World West on Friday June 26.

Posted by Ashley Smith, Developer Marketing, Google Maps APIs

Posted:


Editor’s Note: We are (literally) coding a mobile app on the road as part of our cross-country road trip, Code the Road. This is our fourth (and final) post in the series -- if you haven’t read our previous posts, be sure to check out Hitting the Road with the Google Maps Android API, Store Your Locations in the Cloud with Firebase, and Checking in using the Places API to get started. Follow along as we build our app on the road and read more from Dave Overstrom, Program Manager at Google.

It’s been 22 days since you last saw us jogging on ICON’s NordicTrack treadmills back in Logan, UT, and to be honest, sitting in a 1959 GM Tour Bus for that long on the road has not exactly been ideal for our legs and joints. Luckily, we have just the solution to get us back in shape—thanks to the Google Maps APIs and Android Wear.

In this post, we are going to escape the Code the Road bus for a little while and make use of the Directions API, Elevation API, and Google Maps API for Android Wear to plan the perfect bike ride. We will build upon our application to:

  1. Find the perfect bike route using the Google Directions API
  2. Determine the elevation profile of the route leveraging the Elevation API
  3. Easily display the route on our watch using the Google Maps API for Android Wear

Add Android Wear Module to Project

First, we need to add a new Android Wear module to our existing project. In Android Studio, select FileNewModule and select Android Wear Module.
Screen Shot 2015-06-09 at 2.34.30 PM.png

On the Next screen, give your module a name. In this example, we called it “Code the Road” and gave it a module name of “wear.” This name is important for our gradle build files, so more on this shortly. Note: be sure the SDK is version 21 or higher. Start with the default blank activity. We will be modifying this activity, so it is important to get started.

Once the module is added to the project, it is important that we configure the build.gradle files, so the modules compile and the final application bundles everything correctly. In the build.gradle for the “Module wear”, ensure that the following dependencies are set. It is important that you reference Google Play Services version 7.5.0 or greater to ensure the Maps API for Android is available.
dependencies {
   compile fileTree(dir: 'libs', include: ['*.jar'])
   compile 'com.google.android.support:wearable:1.2.0'
   compile 'com.google.android.gms:play-services:7.5.0'
}
Now that we have these initial configurations in place, please reference the guide to create an initial MapsActivity within your Android Wear module. This will initialize a basic Google Map within your Wear App.
dependencies {
   compile fileTree(dir: 'libs', include: ['*.jar'])
   wearApp project(':wear')
   compile 'com.google.android.gms:play-services:7.5.0'
   compile 'com.android.support:appcompat-v7:22.1.1'
   compile 'com.firebase:firebase-client-android:2.3.0+'
}
Debugging. At this point, it is important that you are able to successfully test and debug your Android Wear application. For our development, we debugged primarily using an actual Android wear device using the steps in Debugging over bluetooth. You can also debug using the emulator by following the steps in Set up and Android Wear Virtual Device. Take your time getting this setup and working correctly before continuing.

Set the start and end location
Now that we have our basic Google Map setup on the Android Wear module, let’s jump back to the mobile application code. The first thing we want to do is get the start and stop locations for our planned bike route. To do this, we add an OnMapClickListener to the map and capture the start and stop locations on the map.
// Setup onclick event listener for the map
mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {

   @Override
   public void onMapClick(LatLng point) {

       // Logic to add markers to the map on click.
       … 

       LatLng origin = (LatLng) bikeMarkerList.get(0).getPosition();
       LatLng dest = (LatLng) bikeMarkerList.get(1).getPosition();

       // Get URLs for the Directions API
       String url = getDirectionsUrl(origin, dest);

       // Create an AsyncTask to fetch JSON data from Directions API
       DirectionsDownloadTask downloadTask = new DirectionsDownloadTask();

       downloadTask.execute(url);
   }
});
Construct the request to the Directions API
Ultimately, we want to draw a polyline to demonstrate the route for a “biking mode” between our start to end locations. But first, we need to send a request to the Directions API in order to retrieve the route for our trip. We construct a URL to the Directions API web service:
// Building the url to the Directions API web service
private String getDirectionsUrl(LatLng origin,LatLng dest){

// String for the origin of the route
String str_origin = "origin="+origin.latitude+","+origin.longitude;

// String for the destination of the route
String str_dest = "destination="+dest.latitude+","+dest.longitude;

// Enable bicycling mode
String mode = "mode=bicycling";

// We build the parameters for our URL string
String parameters = str_origin+"&"+str_dest+"&"+mode;

// Construction of the entire URL to the Directions API. 
// IMPORTANT: Notice how we proxy the requests through a web server to
// protect your API key.
String url = "https://<YOUR_PROXY_SERVER>/directions?"+parameters;

return url;
}
Parse the Directions API JSON response
Within the onPostExecute function of our DirectionsDownloadTask (see AsyncTask), we created a helper class to parse the JSON response and grab the overview_polyline value. We then “decode” this polyline and store the lat / lng result to a global List variable (more on this later). Note: For your application, you may choose to traverse all the routes and legs to capture every lat / lngs pair. For demo purposes, we just used the overview_polyline.
protected void onPostExecute(String directionsJSON) {
   super.onPostExecute(directionsJSON);

   try {
       JSONObject jObject = new JSONObject(directionsJSON);
       DirectionsJSONParser parser = new DirectionsJSONParser();

       // Parse the data. directionsResult is a List of decoded poly
       directionsResult = parser.parse(jObject);

       // This is the encoded polyline to pass on the Elevation API call
       String overviewPolyline = parser.getEncodedPoly(jObject);

       //Now that we have route, we need to get the Elevation data.
       ElevationDownloadTask elevationDownloadTask = new
  ElevationDownloadTask();
       String url = getElevationUrl(overviewPolyline);

       elevationDownloadTask.execute(url);

   } catch (Exception ex) {
       ex.printStackTrace();
   }
}

Construct the Request to the Elevation API

Now that we have the route for the trip, we can make a call to the Elevation API using the encoded polyline to get the corresponding elevations for each lat / lng pair. Similar to the Directions API logic, we make an Elevation API call using an AsyncTask. Below is an example of how we construct the URL.
private String getElevationUrl(String encodedPolyline) {
   // Build parameters to the web service
   String parameters = "locations=enc:" + encodedPolyline;
   // Build URL to the web service
   String url = "https://<YOUR_PROXY_SERVER>/elevation?" + parameters;
   return url;
}
Parse the Elevation API JSON response and draw on map
We were planning to render the polyline with a corresponding elevation chart below the map. Although this would be very useful, we wanted to display elevation information on a much smaller interface like a watch. With less screen real estate, we decided to color the polyline segments on the map based on elevation change, where green equals downward elevation and red equals upward elevation. To accomplish this, we added the following logic to our ElevationDownloadTask:
  1. First, we parse the JSON and add the corresponding elevations to a global List elevation result.
  2. Second, we iterate through all the route segments (directionsResult) and to get the lat / lng pairs and elevation difference.
  3. Using a helper function, we calculate the color of the segment based on elevation change (green → red or red → green)
  4. Finally, we add the polyline to the map and pass the polyline information over to the Wearable device using the PutDataMapRequest.
protected void onPostExecute(String elevationJSON) {
   super.onPostExecute(elevationJSON);

   try {
       JSONObject jObject = new JSONObject(elevationJSON);
       ElevationJSONParser parser = new ElevationJSONParser();

       // Start parsing data
       elevationResult = parser.parse(jObject);

       // We use later send this to the Wearable device to recreate poly.
       String routeForWearable = "";

       // Go through all segments
       for (int i = 1; i < directionsResult.size(); i++) {
           LatLng prevPosition = directionsResult.get(i - 1);
           LatLng position = directionsResult.get(i);
           double prevElevation = Double.valueOf(elevationResult.get(i - 1));
           double elevation = Double.valueOf(elevationResult.get(i));

           double elevationDiff = elevation - prevElevation;

           // Get color based on elevation change.
           // Green --> Red (and vice versa) gradient logic.
           int color = getColorByElevChange(elevationDiff);

           // Create the polyline segment.
           PolylineOptions polyOptions = new PolylineOptions()
                   .add(prevPosition, position)
                   .color(color)
                   .width(8);

           // Draw polyline for segment
           mMap.addPolyline(polyOptions);

           // We maintain this String variable to pass over via the DataApi to
      the Wearable
           // app. From there we parse the response and also create the polyline
      there.
           routeForWearable += prevPosition.latitude + "," + 
      prevPosition.longitude + ":"
                   + position.latitude + "," + position.longitude + ":"
                   + color + "|";
       }

       // Here we send over the polyline string to the Wearable device.
       PutDataMapRequest putDataMapReq = PutDataMapRequest.create("/route");
       putDataMapReq.getDataMap().putString(ROUTE_TAG, routeForWearable);
       PutDataRequest putDataReq = putDataMapReq.asPutDataRequest();
       PendingResult pendingResult =
               Wearable.DataApi.putDataItem(mGoogleApiClient, putDataReq);
   } catch (Exception e) {
       e.printStackTrace();
   }
}
code-the-road-elevation.jpg

Display the Route on Our Watch

Setup WearableListenerService. The final step of the app is to create a WearableListnerService on the Wearable app to grab the polyline information passed in the previous step. Within this listener service, we have an onDataChanged function to capture the routeForWearable string and use that information to create a similar polyline on the Wearable application.
public void onDataChanged(DataEventBuffer dataEvents) {

… // Initialization logic

for (DataEvent event : dataEvents) {
   if (event.getType() == DataEvent.TYPE_CHANGED) {
       // DataItem changed
       DataItem item = event.getDataItem();
       if (item.getUri().getPath().compareTo("/route") == 0) {
           DataMap dataMap = DataMapItem.fromDataItem(item).getDataMap();
           String routeFromMobile = dataMap.getString(ROUTE_TAG);

           // Go back to main UI thread and draw polyline
           // Broadcast message to wearable activity for display
           Intent messageIntent = new Intent();
           messageIntent.setAction(Intent.ACTION_SEND);
           messageIntent.putExtra(ROUTE_TAG, routeFromMobile);
           LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent);

       }
   } else if (event.getType() == DataEvent.TYPE_DELETED) {
       // DataItem deleted
   }
}
}
It is important to note that we need to use the LocalBroadcastManager in order to pass control from the WearableListenerService back to the main UI thread in order to render the polylines. To accomplish this, we setup the following nested class in our MapsActivity on the Wearable app.
public class MessageReceiver extends BroadcastReceiver {
   @Override
   public void onReceive(Context context, Intent intent) {
       String routeFromMobile = intent.getStringExtra(ROUTE_TAG);
       // Draw the elevation polyline based on parsing the String.
       drawElevationPolyline(routeFromMobile);
   }
}

It's Been a Long Trip

This is our fourth and final blog post in our Code the Road App blog series—thank you for reading and following along! Now that you have a working Android application, you can continue to extend it with new features like creating an interactive chart showing elevation that allows users to hover over the chart to see the corresponding map location or allowing location sharing with friends. You can also build a web app to retrieve your location and check-in history from Firebase. This is only the start of what you can do with the Google Maps APIs, so use your imagination and build some amazing applications!

Posted:
Code the Road Full Bus No Text.png

We’re pulling into the last Code the Road stop on Friday, June 26 where we’ll be visiting Epcot to celebrate our ten year anniversary and to demonstrate how technology brings the guest experience at Walt Disney World Resort to life.
Day1_Select5.JPG

Epcot guests will be able to visit the bus, located in in Future World West near Innoventions between 9am and 9pm to see how our customers, like Walt Disney World Resort, are using Google Maps APIs to build engaging, location-rich applications for their users and customers.
Disney.jpg

While there, we will be hosting an invitation-only event with the Disney team for 40 girls from Tech Sassy Girlz, an Orlando-based non-profit program designed to provide girls in grades 6 through 12 exposure and access to STEM fields and careers.
DSC_0819-2.jpg

While at Epcot, the girls will experience a full day of learning and adventure including engaging talks from the Disney and Google teams in the morning and educational sessions in the afternoon. The event will demonstrate how technology and engineering create engaging, memorable experiences, like navigating the Walt Disney World Resort with the My Disney Experience app.

If you’re planning to be at Epcot on Friday, stop by to see us at the bus.

Posted by Ashley Smith, Developer Marketing, Google Maps APIs

Posted:
After meeting with developers in Chicago last week, we paid a visit to the Chicago Department of Transportation who is currently using the Google Maps APIs to coordinate their public projects. We parked our bus in front of their building in downtown Chicago to let all passersby come into the bus and look at how the DOT is executing the great infrastructure changes happening in their city.
C11C1345.jpg

We had the pleasure of meeting with William Cheaks, First Deputy Commissioner, Chicago Department of Transportation and Larry Olszak, Director of IT, Chicago Department of Transportation, to talk to us about how they use Google Maps APIs to help manage the city of Chicago’s infrastructure projects.
C11C1475.jpg


A032_C019_0611QJ.0000577.jpg

We also had a great surprise at the event—our friends at grubHub stopped by to bring the crew some delicious donuts. It was sweet treat to brighten everyone’s day. Even better, they used the Google Maps APIs delivered to us!
A033_C001_06115A_S000.0001783.jpg

We’re looking forward to seeing you at one of our future stops. Join us in McLean, Virginia at Hilton Worldwide Headquarters on June 22 from 7am to 10am for a tour of the bus.

Posted by Hena Haines, Associate Product Marketing Manager, Google Maps APIs

Posted:
After an amazing day with Harley-Davidson riders in Milwaukee, we made it to Chicago for our second developer meetup. We had a blast showing the developers the Code the Road bus in the middle of downtown Chicago. We hope all who attended had a fantastic time.
C11C0094.jpg

Before the event even started we hitched a ride with a few maps developers taking Lyfts into the Chicago office. We spoke to their drivers about topics ranging from the future of maps to who they wish they could carpool with in a Lyft. Once at the event, attendees had the opportunity to explore the bus, pick up pegman stickers (complete with the Lyft mustache), and meet other developers before heading up to hear four technical talks.
C11C0126.jpg

I was up first (traveling all the way from Sydney) to discuss using Google Maps APIs in Android apps. I outlined ways to use custom markers, colors, and animations to make maps more focused and easier for users to navigate.
C11C0173.jpg

Next up was Ed Boiling, Google Maps for Work Solution Architect, who demonstrated how to use Google Cloud Platform to manage, serve, visualize , and analyze location data.
C11C0270.jpg

We, then, welcomed Patrick Skoglund Geospatial Lead from SADA Systems. He outlined how using the Google Maps toolset can help large companies solve complex problems.
C11C0191.jpg

We ended the night hearing from Kyle Madsen, Android developer at Lyft. Kyle gave a great overview of his experience with Google Maps APIs at Lyft. He described how the ease of implementation using Google Maps APIs helped them to focus on their core Lyft application while relying on Google Maps for the navigation components.
C11C0252.jpg

Next up, we’re on our way to New York to meet with Sesame Street and a few of our youngest fans. We’ll also be hosting our last developer meetup on June 18, so sign-up to join us in New York.

We look forward to seeing you in New York or one of our future stops on the road!

Posted by Florian Bertele, Product Manager, Google Maps APIs

Posted:


Editor’s Note: We are (literally) coding a mobile app on the road as part of our cross-country road trip, Code the Road. If you haven’t read our previous posts in the series, be sure to check out Hitting the Road with the Google Maps Android API and Store Your Locations in the Cloud with Firebase to get started. Follow along as we build our app on the road and read more from David McClusky, Maps Solutions Architect at Google.

We’re now in the third week of our Code the Road journey and we’ve had a great time meeting with developers and customers across the country. In this third post in our app blog series we will extend the capabilities of our mobile application by adding the ability to ‘check-in’ to places we visit along the way using the Google Places API for Android. If you haven’t read our earlier posts, checkout our posts on building a mobile map with the Google Maps Android API and connecting it to the cloud.

Our Code the Road bus is now visiting New York City, so we thought it would be useful to update our app and add the capability to view nearby places, select places and check-in, and then store those locations in the cloud for future reference. To do this we’ll integrate the Google Places API for Android.

We’ll start by utilizing the Place Picker—an out-of-the-box user interface that allows your app to quickly connect to Google’s database of hundreds of millions points of interest.

Prerequisites

Before you get started, make sure you have the latest version of Android Studio installed and your project includes the Google Play services component. In addition, you must have an API Key for Google Places configured with your app’s digital certificate. For more information on creating a Places API key read the documentation. You should have also completed the first two steps in our blog series, as we’ll be utilizing our existing connection to Firebase to store our check-ins in the cloud.

Adding the Place Picker to Your Application

The Place Picker provides a UI dialog that displays an interactive map and a list of nearby places. When you activate the Place Picker, it attempts to identify the your current location, and will also provide a list of alternative suggestions. We’ll add some code to our app so when we select a place, we’ll add a marker to the map and store the location in the cloud.
It’s very easy to add the Place Picker to your application, as Google handles all of the user interface elements for you.

The first thing we’ll do is add a button to our app on the action bar to launch the place picker. View the documentation for adding an action button.

To launch the Place Picker from our action button, we will construct an intent in the onOptionsItemSelected() function:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
 // Handle presses on the action bar items
 switch (item.getItemId()) {
   case R.id.action_search:
     try {
        PlacePicker.IntentBuilder intentBuilder = new PlacePicker.IntentBuilder();
        Intent intent = intentBuilder.build(this);

        // Start the Intent by requesting a result, identified by a request code.
        startActivityForResult(intent, REQUEST_PLACE_PICKER);

     } catch (GooglePlayServicesRepairableException e) {
       GooglePlayServicesUtil.getErrorDialog(e.getConnectionStatusCode(), 
       this, 0);
     } catch (GooglePlayServicesNotAvailableException e) {
       Toast.makeText(this, "Google Play Services is not available.",
Toast.LENGTH_LONG).show();
     }
     return true;

  default:
    return super.onOptionsItemSelected(item);
  }
}
After we select a place, we’ll need to identify which location was selected and display a marker on the map. First we will capture the result by creating the onActivityResult() function. We first obtain a reference to the place selected:
final Place place = PlacePicker.getPlace(data, this);
And then extract the various details about the place:
final CharSequence name = place.getName();
final CharSequence address = place.getAddress();
final CharSequence phone = place.getPhoneNumber();
Finally we can add a marker to the map:
mMap.addMarker(new MarkerOptions()
                   .position(place.getLatLng())
                   .title(name.toString())
Here is what the complete function in our app looks like:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {

 if (requestCode == REQUEST_PLACE_PICKER) {
    // This result is from the PlacePicker dialog.

    if (resultCode == Activity.RESULT_OK) {
       /* User has picked a place, extract data.
          Data is extracted from the returned intent by retrieving a Place 
          object from the PlacePicker.
         */
         final Place place = PlacePicker.getPlace(data, this);

         /* A Place object contains details about that place, such as its name, 
         address and phone number. Extract the name, address, phone number, 
         place ID and place types.
          */
         final CharSequence name = place.getName();
         final CharSequence address = place.getAddress();
         final CharSequence phone = place.getPhoneNumber();
         final String placeId = place.getId();
         String attribution = PlacePicker.getAttributions(data);
         if(attribution == null){
            attribution = "";
         }

         // Update data on map
         mMap.addMarker(new MarkerOptions()
            .position(place.getLatLng())
            .title(name.toString())
           );

         // Print data to debug log
         Log.d(TAG, "Place selected: " + placeId + " (" + name.toString() + ")");


       }
   } else {
       super.onActivityResult(requestCode, resultCode, data);
   }
   // END_INCLUDE(activity_result)
}

After the marker is added to the map, we can easily trigger turn-by-turn navigation by selecting the navigation icon in the bottom-right of the map to launch directions in Google Maps mobile.

Save the Location to the Cloud

Checking in to the places we’ve visited becomes even more useful if we are able to store those check-ins for future reference. Since we’ve already connected our app to the cloud using Firebase, it will be very easy to use that same connection to store our check-ins. After adding the marker to the map, we simply add the following lines of code to our function above to also save the location and id of the place to Firebase.
Map mLocation = new HashMap();
mLocation.put("timestamp", mLastUpdateTime);

Map  mCoordinate = new HashMap();
mCoordinate.put(“latitude”, place.getLatLng().latitude);
mCoordinate.put(“longitude”, place.getLatLng().longitude);
mLocation.put("location", mCoordinate); 

mLocation.put("place_id", place.getId());
myFirebaseRef.push().setValue(mLocation);

That’s all there is to it! We now have an app that, in addition to storing our location history in the cloud, also lets us record a list of all the places we’ve visited while on the road. Stay tuned for future blog posts where we will continue to extend our app’s functionality with features such as directions and support for wearable devices.