[MUSIC PLAYING] [APPLAUSE] BRETT MORGAN: Good
afternoon, all. And for those following along on
YouTube, at home, good morning, good afternoon, good evening. I'm Brett Morgan. I work on the Developer
Relations Team for Google Maps based
in Sydney, Australia. That means that I do things
like write sample apps, write tutorials, codelabs,
and all that sort of thing. As I said, I look
after Google Maps APIs. Google Maps API is the oldest
API surface that Google has, over 10 years old. We have a lot of APIs. We have a lot of
interesting functionality that you can use in
your applications. One of the things that we hear
from developers, like yourself, is that it's great, you've
got all these APIs, got this wonderful documentation,
tells what the arguments are, tells what the result is. But how do I, as a developer,
take all these APIs, glue them together to
create something that solves a problem? So the GO developers API-- GO Developer Relations
Team in Sydney came up with an idea
of making solutions that show you end to end
how to solve a problem. So I just want to give you a
little bit of history here. Every year we have an
annual developer conference called Google I/O.
And a couple of years ago, we decided to move
from downtown San Francisco where it had been at Moscone
for quite a few years into Google's backyard at
Shoreline Amphitheater. Now, this was
great, bigger venue, means we can do bigger things. We can have more
people come along. But how do you take 7,000
people from a bunch of hotels all over Southbay and get
them into this one event? Well, there's a pretty
easy answer to that. You rent a fleet of buses and
move people around with them. But this raised an interesting
opportunity for those of us on our GO Developer
Relations Team. How can we best utilize Google
Maps APIs to show people where their buses
are and how long it's going to take them to get
between different points? So Steve down the front
row here and myself and a bunch of
others put together a solution that actually
did this, showed attendees at Google I/O the real-time
location of their buses and also showed them
timetables of how long the bus is going to take to
get them back to their hotel. So what I'm going
to do this afternoon is walk you through
that solution. But a quick little
note here, what we're building is
actually an asset tracker, and that one is specifically
called out in our terms. So before you go ahead and
implement an asset tracker, please have a chat to our
sales staff about the premium plan because you're
going to need it. Let's have an overview of the
Transport Tracker solution. So here's the architecture. For those of you who attended
the Fletcher and Firebase talk yesterday, this probably
looks a little bit familiar. Turns out Firebase
encourages you to actually build in this way,
and it does a very good job. So what do we have here? Well, the first
part of the problem is we have 30-odd buses
running around Southbay, and we want to know
where they are. So what we did is we
put an Android phone on each bus with a
little suction cup holder to keep the phone out of the way
of the driver and a USB power adapter, and that had a
custom application on it which was then turning around
and publishing to Firebase the location of the bus. Firebase is wonderful. It turns around and-- when you push some new
information into it, it turns around and
notifies anything that's listening on that path. Whoops, wrong button. That button. OK, so following
on from that, we have a Node.js process running
in a Google Compute Engine server in the cloud
actually being notified that these buses
move from here to here. That process then
cleans up that data and writes the
cleaned-up location of the bus along with
timetable information, various other things
back into Firebase in a different location, which
then turns around and changes the display. So at Google I/O we had big
60-inch LCD monitors that had, as you saw previously, the
real-time location of the buses and timetable information. So this is the overview
of the solution I'm presenting this afternoon. So let's dive in. Let's start with
the first component. These are the Android phones. How do we get the accurate
location of the phone? Using Android APIs. Well, thanks to Steve's
codelab, which some of you probably had a go at
yesterday afternoon-- but if you're following
me along on YouTube or you didn't, I'll have
links at the end of the talk that actually link
you to the real-time codelab. But this-- I just
want to show you the core component of that
codelab that drives the ability to track the location. So what we're
going to start with is configuring a
location request. We're being reasonably
aggressive here. We're asking for high fidelity,
high accuracy of the phone, and we're asking to do
it every 10 seconds. This means the phone's going to
be really active, the circuit-- the radio circuitry is
always going to be on. So this is going to have
battery implications, which is why I mentioned before
that when we installed the phones in the buses,
we connected them up to USB by phone chargers. So this is an explicit
design consideration. When you turn around and
do this sort of thing, you need to be aware of,
is this phone permanently connected to power or not. Another thing we implemented
to deal with this was monitoring software. So we had the phones actually
writing their battery level into another part of Firebase
that we had an admin user interface so we could
see all of our phones, the current location, and most
importantly their power status, because occasionally a bus
driver would get into his bus and go, what's this
phone doing here? And unplug it and plug his own
phone in, and we'd go damn it. Go and find the bus and
get him to plug it back in. So we configured how we're
going to get locations. The next point is that we then
use the Fused Location Provider API. This gives us-- fuses together
cellular tower data, GPS data, and Wi-Fi data to give us a more
accurate prediction as to where this phone actually is. We then configure
whereabouts in Firebase. We're going to write this
location information. And finally, we
create a call-back to hand to the Fused
Location Provider API that we can actually then
turn around and write the results into Firebase. And with this 10
lines of code, we are now tracking this
phone in real-time. So we've dealt with
the first component. Now we move to the
heart of the system, the Firebase real-time database. The Firebase real-time
database is a very powerful real-time communication tool. For me while I was
developing the system, it was absolutely
insanely powerful because traditionally when
you're developing a distributed system, the main pain point
you have is understanding what the whole system is doing. Now, because I've got 30 phones
wandering around Southbay, I'd like to know where they
are, what they're doing. And in this console I
can see what each of them is doing in real-time. During development, we can
also turn around and not have that component,
and I can sit it here and through this
console turn around and make changes to
the data structures and see what the downstream
components do when faced with certain edge cases. This allows you to effectively
have real-time development in a distributed system. You can see what
it's doing, you can change what it's doing all in a
nice web browser-based console. So I told you about
the Android phones. They put their location
information into Firebase. Firebase then notifies
our Node.js process running on Compute Engine. So this component has a
couple of things that it does, has a list of responsibilities. But I'm going to go
through two this afternoon. The first one is that while
we are running simulations, we like to move
things around the map. To do that, we need to
actually generate the pause that the buses
are going to take. They start at a hotel,
go to another hotel, and then wind up at Google
I/O. We need to then track out the path going around all
the roads, the roundabouts, over the bridges and
all that sort of thing that that bus is going to take,
so that our simulation looks realistic. The second piece of code
I'm going to show you is what this server does with
the phone location information to tidy up the fact that GPS
data tends to be a bit noisy. So the first code snippet. Here's where we're
generating a path. Trip Points is
where we are going to take all the points of the
path, put them into a list, and then do things
with it later. So this is effectively
just an accumulator. For every stop, I
actually have a database of all the information
of all the trips, and so what we're going
to do is get the stops that this trip is going to
make out of that database. Here's where we create a
Directions API request. At its simplest, a
directions request has a starting point
and an ending point, in this case origin
and destination. But in the case where
we have multiple hotels that this bus is
going to, we have waypoints which are the
hotels in between the origin and the destination. This is the line
where we use a client library to turn around and make
a request to the Directions API. I just want to stop
here for a second. We actually have four
client libraries. One, as you can see here, in
Node.js, one Go, one for Java, one for Python. And these client libraries
take the web service APIs that we have, like
Directions API, Roads API, so on and so forth, and give
you language-appropriate help. So for Java and for
Go, we expose to you what the result types are
going to be, so you get-- if your browser or editor
gives you intellisense, you'll turn around and
get type completion, all that sort of thing. Now that we've made that
request using the power of a way to turn what's basically
an asynchronous operation into something that
looks synchronous, now we look at the response. Did it actually work? And if it did, now we actually
interrogate the response structure. So a Directions response
consists of a set of routes, and I'm just going to
take the first one here because I don't really care. Well, I do care. The first route is going to
be the best route, right? For each route, we
have a set of legs. This traditionally shows up as
different transport modalities, and in each leg there
are a set of steps, and finally within a
step we have a polyline. So a polyline is
an encoded format for a list of lat
longs, location points. And so I decode
this encoded string. I've got the points
for this step. And then I turn around and
glue them all together, put them in trip points,
and then I use it later for actually rendering the buses
going around in simulation. So the second code snippet-- this is where I'm going
to deal with the bus. So the bus is walking around-- well, walking--
driving, rolling around. So we have a bus, and it's
moving around Southbay. It's checking in every 10
seconds through Firebase and telling us where it is. So on the server side,
I collect a history of the location of the bus. A couple of minutes
in this case. And I take that history,
and I send it off to our snap to road API. So this is part of
our Roads API service. So Roads API knows
where all the roads are, and I can turn
around and give it a couple of minutes of history
of the bus moving around, and Roads API will
then take those points, do some mathematics, and make
the best guess as to which road you were actually driving down. So it effectively eliminates
the noise from the GPS track. So then we-- because
we're actually interested in the current
location of the bus, we take the list
of returned points and take the very last one. It's worth noting here
that if you're plotting out a path of something on
a map, that you can also ask Roads API to insert
additional points because as I said, it knows where
things like roundabouts are and curved roads. So you can have Roads API
insert additional points in the snap to road result,
such that when you plot it, it's a nice line that actually
follows the roads as opposed to just the points that
you sampled using, say, Fused Location Provider. In this case, we're only
interested in the point. We're not plotting anything. So I didn't do that. I'm just taking the
most recent point. And of course, there's
error recovery. So now we're on to the
final part of the system. This is where we put the buses
and the timetable on the map. So you might have seen the map
that I showed you, doesn't look like a standard Google map. What's the code look like? Looks like this. We have a description
language that allows you to define the set
of rules that tells our mapping engine how to render a map. I don't know about
you, but I don't really want to turn around
and configure how a map brain is using this. I'd much rather use a what you
see is what you get wizard. So what I'd like
to show you now is how to use our wizard to
actually come up with a map-- sorry, come up with a map style. So I'll just pray that the
demo gods are actually working. OK, this is our wizard. I'd like to create a style. Sydney, Australia. Can't tell where this
was written, right? Let's go to Cracow. OK, this is the stock
standard Google Maps styling. But I'm creating an application,
and I don't want this style. I want something that
speaks more to Cracow. Should we go with
something that's completely saturated, or
respecting Cracow's history, should we go
something a bit retro? I think I like this. But it's got a bunch
of visual noise on it that's not talking to me with
the application I'm designing. So I can then turn around and-- yeah, that's better. I've calmed down the map. Maybe I want to take
off the landmarks. Let's zoom it a bit. And a bit more. How does that look? I'm happy with that. OK, if you wanted
to dive in deeper and actually make
more modifications, we have a deeper
level here that you can turn around and play
with the individual settings and see the results
in real-time. But I'm happy with
this map as it is. So we give you two
ways of using this map that you've just configured. The first one here
is the JSON language that I was showing you before. This map styling information
is useful in obviously Google Maps for web, so using
the JavaScript API. But it also works the exact same
language on Android and iOS. So this way you can configure
your map once and use it across all of your applications. We also give you our
static maps information. So if you just want to put a
map on a page and configure it, style it in some
way, you can do this, and this saves you from having
to load the JavaScript Maps API. It's a much lighter
response if you know that you don't want your
users interacting with the map. Back to the presentation. Now I've styled the map. We're off to the final
part of the journey where we've had the information,
start on the Android phone, we cleaned it up
in Compute Engine. Now we're going to
display it on a map. There's no types here. We must be back in
JavaScript land. We go to Firebase database that
we're taking a reference on. Now we're listening to a
different path in Firebase. So this is where the
Compute Engine hosted Node.js processes writing
the cleaned-up location of the buses. So what I've done here is that
under this location in Firebase I'm writing an
entry for each bus, so thus I can look up all
the buses all at once. I look at each bus, and
I've got a routine here to figure out what colored
marker to put out for this bus, depending on which route that
bus is actually servicing. Then we create a marker. The marker goes on a map. Realistically you actually
need a bit more complexity here to deal with reusing
markers because if you just kept creating new markers,
then you'd wind up with a screen full of markers. You actually want to
move the marker around, and you want to delete it when
the bus goes out of service. I hear people out in
the audience screaming, the web is great, but I want
to put it on mobile as well. How can we do this? Well, it just so happens we
have the same code for Java. We've got types here. We're back in Java land. We have a database reference. We turn around and
create a child listener to add to the Firebase to
notify us when things change. This time around I'm just
tracking a single bus. I'm not turning around
and mapping all of them. I've added the Firebase. I've got the lat. So that's the latitude of the
bus, longitude, and the bus route. So now I have enough information
to turn around and configure a marker on the map. Same logic applies here. You probably want to hold on to
the marker once you create it and just move it around. Simple enough. So just to go over at a high
level what we've just covered. We started out in Android using
Fused Location Provider to get the location of an asset. We published that location
every 10 seconds into Firebase. Firebase notified a
Google Compute Engine hosted Node.js process
to clean up that data and deal with the vagaries
of GPS location data. That updated information
was written back into Firebase, which it
controlled a front-end Google map hosted dashboard
that was shown to all the attendees at Google
I/O. I've also shown you how to do this with mobile. So where next? For starters, if you
would like to see the documentation for
the Google Maps Solutions that we're publishing, it's all
up on developers.google.com. If you'd like to have
a look at our client libraries and other open
source code, like the samples-- sorry, like the solutions,
it's all up on GitHub. And finally, the code
that you saw in this talk is actually lifted
out of three codelabs. The first codelab was
the one that Steve and I hosted yesterday, which was
the real-time asset tracking codelab. The code for the Node.js process
was lifted out of the Transport Tracker Backend codelab. And finally, the code that
I showed at the very-- well, almost at the very end of
putting markers on a big Google map was taken out of the
Transport Tracker map. And with that, I thank
you for your attention, and I invite you to
give us feedback. Thank you very much. [APPLAUSE] [MUSIC PLAYING]