[MUSIC PLAYING]
BENJAMIN BAXTER: Hey, everyone.
I'm Benjamin Baxter, developer
advocate for Android TV.
Today we're going to talk about
building a great Android TV
app.
So before we dig in the details,
let's talk about the ecosystem.
We continue to see two
times year over year growth.
We're investing more in
smart TVs, set-top boxes,
pay TV operators.
The ecosystem's
been pretty strong.
But we're all developers.
What's get into how can
you make a good TV app.
So before we talk about what
the innards of your app are,
we'll just think
about what is the TV.
Why is it so important?
We have entire living rooms
or other rooms dedicated
and focused around a TV.
It's a pretty key
point for users.
It's the focus of
an entire room.
Just think about
that for a second.
So your app matters.
The content really matters.
So if we try to think about what
is the foundation for an app,
the biggest piece
is your content.
That's your value
prop to your user.
If we add onto that,
usability-- how
do you make your app
easier for users to use?
Now you have great content.
How can they discover more of
your content inside your app?
And if you want to get
that little cherry on top,
think about the experience.
How can you layer in
all these extra things
to build a suite experience
for users no matter
where they are in your app?
We'll dive into each
of these concepts.
And I'll call them out later on.
But the key takeaway is
they come for your content.
But they stay for your app.
So now let's talk about how
do you build a great TV app.
There's really three
things to think about--
playing, because content's
important, discovering--
making sure they can see other
content in your app easily--
and distributing.
Making your content
easy to find should
be as easy as making
your app easy to find.
So let's talk about the player.
Playback can make
or break an app.
Let's take a look
at this review.
Feel free to read.
So the key takeaway for me
is that it constantly stalls.
This app is completely
frustrating.
They ended up with just a
one star review just because
of their player.
And reviews matter.
There's whole other
talks about Google Play
and how to improve your reviews.
But the player was
the key point here
as to why their app was
not as good as it could be.
So it's very clear to users
that the playback is important.
They don't want to have
stutters and stalls.
They want to be able
to watch the content.
And even in that
review they talked
about commercials and ads.
And they were OK with it.
They just didn't like
that they stalled.
So even showing
things that may be
annoying, such as commercials--
as long as they play fine,
users are OK with it.
So the player-- we have many
options to build a good player.
Media Player is a
great tool, comes out
of the box in the framework.
You give it a data source.
It's able to chug along on play.
And you can build a great
experience with MediaPlayer.
If you have more advanced
things you want to do,
ExoPlayer's another great tool.
We've worked really hard to
make it highly customizable.
There's a bunch of extensions.
If you're using
Leanback, there's
an extension that hooks in
to the Leanback transport
controller.
If you're doing ads,
there's a whole bunch
of ad stitching support.
But let's talk more about ads.
Ads are important.
Your app's going to make
money from showing ads.
So in a sense, ads are just as
important as the content shown
and displayed to the user.
So focus on ads.
Make sure that ad
stitching works.
Whether you should do a
server side or client side,
these are real considerations
you should make for your app.
So there's many
options for players--
MediaPlayer, Exoplayer,
build a custom player.
But having a player
is a good start.
But there's things
you can layer in.
That top part of the pyramid--
the experience--
there's things you
can do to build an
experience around the player
to make it even better.
So we talked about
this at I/O this year--
playback controls.
Everyone's phones
should be ready.
Here we go.
OK.
Google.
Skip five minutes.
OK.
Google.
Pause.
OK.
Google.
Play.
These types of
transport controls
can be commands
through the assistant.
Adding this extra
little feature--
this little nice
nugget of delight--
helps build that
experience for your app.
This all works
with MediaSession.
So if you implement
MediaSession Callback,
you get all of these
features for free.
And since I talked
about this at I/O
and there's been other
talks about MediaSession
from other people, I'm going
to just jam through this fast.
Pay attention.
Here we go.
Boom.
Beautiful-- 6
wonderful methods--
pause, play, stop, seek,
next, and previous.
But in reality
like that's a lot.
It's a lot to think about--
all these different cases.
But if you use Exoplayer,
this can be done for you.
So they've made
an extension that
manages MediaSession for you.
All you have to do is connect
the player to the MediaSession.
And it all works for
you out of the box.
Make an immediate session
is also pretty simple.
And there's tons
of documentation
that talks about MediaSession.
I'm not going to go
too deep into it.
But you just need to make
sure that you set the media
session to be active.
Set the controller.
Set anything else in the set.
Set the current state.
Are you currently playing?
What position are you in?
Set up your MediaSession to
be what you need it to be.
And once you have a MediaSession
and you have an ExoPlayer
instance, connect them.
So there is an extension
library MediaSession Connector
for Exoplayer.
Here you just add in
MediaSession as a constructor
parameter to the
MediaSession Connector.
And then you set the player
to your Exoplayer instance.
This MediaSession
Connector understands
how to set up the callback, all
the edge cases around playing
and seeking.
Now you don't want to go
past the end of the video.
You don't want to rewind
before the video starts.
It handles all those
edge cases for you.
In this example, we are saying
set player, player then null.
You can set a custom
playback prepare.
There's other customizations
you can do, as well.
So if you're a music app and
you have a custom playlist
and you want to set a different
order for how the songs go
through the queue, you can set
a custom queueing mechanism
on the extension.
That's it.
Three wonderful lines of code
and assistance already taken
care for you.
All the default behavior
you expect, done.
So having a great
player is great.
That was just one example of
how to layer in that experience
to make a player even better.
We're going to skip ahead
to discovering content.
So the whole point
of discovering
is you want users
to stay in your app.
And you want them to discover
and watch content faster.
So let's look at this review.
I love the first sentence.
They "love love love"-- so
many loves-- "this app."
So the key takeaway here is
it was a five star review.
And they loved all of
the content was there.
Easy to find.
They can do whatever they
need to do inside that app
and watch what
they want to watch.
Funny story, that's the same app
that got the one star review.
So even though they
had a bad player,
they worked on discoverability.
And they're still able to have
a good review in the Play Store.
So how can we make
content discoverable?
Everything kind of
happens in threes.
And that's like a rule comedy.
It's a really good rule in life.
In this case, discoverability
also happens in threes.
You can work on in-app browsing,
search with the assistant,
and the home screen.
We'll start with
in-app browsing.
There's a beautiful
library, LeanBack.
If you've done TV development,
you're very familiar with it.
It's a templated UI system,
free to just plug-in data,
and it works on
building the UI for you.
So you don't have to worry about
all the focus handling and all
the user input.
You can just apply, hey,
here's the content we have,
and it will show for you.
It's not just how to
browse content, though.
LeanBack also works
and shows details.
So there's a whole bunch of
information about content.
You have duration, content
rating, the Rotten Tomatoes
score, the album, artist.
And I can keep going on
for the rest of the 30
minutes of this talk but
I think you get the point.
There's tons of information.
The cool thing about it is you
can show it using LeanBack,
but you can also show
it multiple other places
on the home screen and search.
And by showing all this
information sooner,
it lets users make these
micro decisions much faster.
And they don't have to go in and
out, in and out to figure out
what they want to watch.
So make your users' lives easier
by showing them all this data
sooner.
Let's look at another
example, search.
Again, we talked
about this at I/O.
And there's tons of
documentation on this.
So I want to kind of breeze
through some of these things
quickly.
Search is all supplied
with the content provider.
Now, content providers
are pretty simple.
They return a cursor.
You're able to do
whatever you want
in the background with
this content provider.
So, boom, magic
content provider.
You perform a search
and it returns results.
If this did a network
call, maybe you
have a bunch of POJOs.
If this was a database call,
you're going to have a cursor.
And that's fine.
The trick for the
search provider
is that it needs to return
results that match the Search
Manager's criteria.
So Search Manager
is just a strict way
of saying, hey, this cursor
has a bunch of columns
with these names.
And then the Assistant's able
to pull in from that cursor
and say, oh, here's the
title, here's the duration,
and is able to figure
out what content's where.
Super simple to do
with Matrix Cursor.
And we'll dive into this
a little bit closer.
You just need to take each of
your results, add them as a row
into the Matrix Cursor, and
then return the Matrix Cursor.
The Matrix Cursor is really
just like a mock cursor.
It's a 2D array, essentially,
under the covers.
So if you don't have
to go about how do I
store all these in a database
with these column names,
you can just mock it out at
the very end of your search.
So, mapping.
This is where the
hard work happens.
You have a matrix cursor and
it takes in a query projection.
This query projection
is going to have
all of the columns defined
that match the Search Manager.
So here we have Suggest
Column Text 1, typically
is the title of the content,
an action, a data ID.
The ID is what's unique to
your content inside the app.
And then when you go to convert
your content into this row,
you just supply an array,
an array of objects--
here's the ID, here's the name--
and they correspond to the order
in which that query projection
was.
So the ID, the
title, the action,
et cetera, all the fields
you have you can return back.
So with Search Manager and with
searching with the Assistant,
you don't have to do
all this extra work.
You can use Matrix Cursor
to make that return
result much faster.
Home screen.
We've talked about the Home
Screen for the past two I/Os.
So I'm not going to
talk about the old.
I'm just going to
briefly cover it.
And then we'll talk about
some of the new stuff that's
happening.
The Home Screen has
three key parts.
Your app can have a channel.
Your app can interact
with the Play Next row.
And for video apps, you
can have Video Previews.
We've seen up to 2x
increase in engagement
when apps have video previews.
They look wonderful.
They can be as simple
as a trailer for a movie
or a recap for a TV show.
But they take a little bit
more work because it probably
requires a content team to
make that content for you.
I'm not going to talk about
Play Next or Video Previews
since we talked about before,
but let's dive into channels.
So just to recap,
building a channel
is just inserting into
a content provider.
We have a channel.
We get a builder.
We set the type to Type Preview.
We give it a name, a
description, a deep link
so when they open
up your channel
it's able to open into your app.
And you set an
internal provider ID.
This is an ID that your
app wants to keep track of
and knows about.
Then, you just get a content
resolver, you call Insert,
you give it content values,
and you're good to go.
Once you've stored your channel,
you parse out a channel ID,
you do some stuff-- maybe you
want to keep track of that
channel ID for synchronization--
and then you set a logo.
So channel really consists
of a name, a description,
a deep link, an internal
provider ID, and a logo.
Those are really the
key pieces of a channel.
So what just happened?
We created a channel.
We inserted it.
And we stored a logo.
So we really did two things
with the Home Screen,
insert the channel,
store the logo.
So as of AndroidX 1.0.0,
we have a new API.
This API looks very
similar, small differences.
We have a Preview
Channel Helper class.
It takes in a context and then
it does a bunch of lookups
to get the Content
Resolver for you.
So you don't have to do
context.contentresolver.insert.
It does all this work for you.
It makes a channel.
So you have your builder.
You set the name, the
description, the app link,
and the intent provider URL.
And you think you
should set the type.
But this class knows that
it is a preview channel.
So it already knows the
type is type preview.
And you don't have
to set the type.
Instead, you can set the logo.
Now all this stuff is
contained in one unit.
And you can just call the
helper.publishedchannel,
give it the channel, it figures
out all of the work for you.
And you get the channel ID back.
So what it does
under the covers,
it inserts the channel
into the provider
and then it goes to add a logo.
If the channel isn't able
to be inserted-- maybe
you have bad data
and you're hitting
an error or something-- it'll
return an error back to you.
If it is able to
insert the channel,
it tries to store the
logo on that channel.
If the logo cannot be persisted,
it throws an exception,
wraps it all up, unwinds,
adding the channel so that you
don't end up with half a
channel on the home screen.
It essentially treats
everything as an atomic unit.
Pretty convenient.
It doesn't just
published channels.
It does everything CRUD does.
So we've already talked
about publishing a channel.
You can read all the channels.
You can even get
individual channels.
You're able to update a channel
and you can delete them.
And I'm only talking
about channels.
But all this also happens
for preview programs.
And there's also support for
the Play Next row in this class.
But there's two
options to do it.
Which one's better?
You could say I just want
to use content providers.
I'm able to fine
tune the performance.
I can do batch inserts,
bulk operations.
I can get lower level control.
I don't need an entire program
with all that metadata.
Maybe I just want the
title and duration.
And now I can slow down
that query projection
and have faster results.
And, it's based out
of the framework.
You don't have to do all
this extra work to access it.
You get it out of the
box from the framework.
But, if you want
to use AndroidX,
you get more convenience.
You don't have to worry about
all the nuances of a content
provider.
It's a one-liner, for
all intents and purposes.
And you get all the
fun benefits of having
the AndroidX in your app.
So discovering content is great.
There are three ways to
go about it, in your app,
searching with the Assistant,
and on the Home Screen
with channels.
But how do you make your app
discoverable, the third thing?
The App Store on TV
is a bit different.
It filters out a
bunch of content.
It wants to make sure only
apps that are designed for TV
will be shown.
So when the user opens
up the App Store,
they're only looking at apps
that can be played on TV
or can be installed on TV.
Trying to navigate the
Play Store make and make
your app stick up can be hard.
But there's three
simple things you
can do to have your app
appear on the Play Store.
First thing is to
declare features.
And that slide says,
even if you don't use it.
There's a giant asterisk.
Don't start declaring like
Bluetooth just for fun,
or location just for fun.
There's two features
that really matter.
So the first one is touchscreen.
You want to declare
that as false.
It's not required to
have a touch screen.
This isn't a phone.
This isn't a TV from
way back in the day.
These are smart TVs.
You don't need
touchscreen support.
The second thing is to
declare LeanBack is true.
This tells the Play
Store, hey, this app
is designed and ready
to be deployed on a TV.
But if you have all of your
code in a single code base
and you're making
a single APK that
deploys on both mobile and
TV, set LeanBack to false.
This still tells
the Play Store, hey,
this APK is compatible
on both mobile and TV.
The second thing
you should do is try
to be visible in the launcher.
Now if you're a headless
app like a screen
saver or a keyboard, just
go away for two minutes
and I'll see you then.
So to make your app
visible on the Home Screen,
you need to supply a banner.
You can define a
banner in Application,
or you can set it
in your Activity.
The launcher will go in
through the manifest,
find this resource,
and this is what
it uses to show your
icon on the launcher.
But once the user
selects your icon,
it needs to launch something.
So the launcher fires an intent.
And you need to have an activity
that accepts this intent.
It's called the
LeanBack Launcher
Intent, really cleverly
named, does exactly that.
So from the launcher,
it will trigger off
your LeanBack experience.
So there's three things
you need to have.
One, declare the two
features so your app will
be found on the Play Store.
Two, have a banner so your
app shows up on the launcher.
And three, have the
LeanBack intent so
that your app launches when the
user wants to enter your app.
And that's it.
You're ready to go
in the Play Store.
This talk is done.
All right.
But in a sense, that's kind
of the minimal viable product.
You're able to have
a strong player.
You're able to have
easy to find content.
And you're able to
distribute on the Play Store.
That's just a good app.
You know, how do
you make it great?
To start with this, you
should look at your users.
Imagine all of your
users on a spectrum.
They start from one
side of the spectrum.
Hey, I bought a TV
because it's cool.
Everyone's doing it.
I want to be cool.
Sits in my closet,
but I have a TV.
The next spot of the
spectrum, I love watching TV.
Every week, I watch this show.
This is great.
You go a bit further
down, oh man, I
love "How to Get
Away with Murder."
Viola Davis is awesome.
Hey, maybe I should
watch "Suicide Squad."
She's also in that.
Then the far extreme,
you know, maybe this--
a better example is for sports.
Hey, I'm watching
the sports ballgame.
Here's a fantasy team.
Here's a jersey of
the player I like.
And I just want to keep
going and going into it.
This side on that
side, the left,
is what's called
the lean back user.
They're just going to be
sitting back watching TV.
That's all they want to do.
The side highlighted,
this is what
you can call the lean in user.
They're sitting on the
edge of their seat.
Oh man, this is awesome.
Who are these
people in this show?
And they're going
deeper into the content.
Everything we've talked
about up till now--
having a good player,
making your app usable--
this is more for the lean back,
the right side of the screen.
But if we think
about it, how can we
tap into that lean in user?
Here we have another living
room, a very beautiful living
room.
I wish it was mine but it's not.
But if we look closer, you'll
see a camera, microphone,
tablet, phone.
And then as you start
to think about it,
the TV is the centerpiece
of a living room.
There are so many
devices around.
You know, you don't have
to just do stuff on TV.
You can tap into everything
around the living room.
That's why I love Android TV.
It's like the focal point of
everything that's happening.
So, in concept-- again, we're
going to do this in threes
because threes are great--
in concept, if we want to tap
into these other surfaces,
what should we look to do?
First step is just
controlling media.
The playback controls we talked
about earlier is a great step.
It's going a little
bit farther advanced.
You're delivering an
experience around your app.
Maybe, for another option,
is to have notifications.
Hey, the big game's about
to start in five minutes.
Do you want to watch on your TV?
Second pillar is more about
going deeper into content.
Who is the cast and crew?
What are the behind the
scenes of this production?
Are there extra
sponsored content
that I want to know more about?
And then the third pillar
is about reducing friction.
How do I install your app?
OK, it's installed.
How do I sign into your app?
I want to make a payment.
How do I authenticate
that payment
in a secure way outside the TV?
So, let's look at an example.
You may or may not know
it, but everyone here
who has set up an
Android TV has already
done that third step, that
frictionless interaction.
Android TV setup actually
does this for you.
During the flow,
they say, hey, do you
want to set up on the phone?
They give you a
strong UX indicator.
You're going to
pull out your phone.
You get a notification.
You say, hey, yeah, this is me.
This is my account.
And the TV takes over
from that information.
And it was really frictionless.
But how did they do that?
It's not magic, I promise you.
It's something you can do today.
You can use Nearby.
So the Nearby API has
been out for a while.
But it's really interesting
when you try to use it
on TV what you can do.
The way it works is,
you're going to set up
the TV to be the advertiser.
And then the phone is going to
come out and try to discover,
hey, there's the TV.
You do all the work you
want to do on the phone
and then send it back to the TV.
Nearby is going to set up an
offline, peer-to-peer wireless
connection that's encrypted.
And you don't have to
worry about a lot of things
because you're going to have
this intimate connection
between the phone and the TV.
Let's dive a little bit deeper.
So getting started with this--
let's start on the TV side
because I'm on Android TV,
so I'm a bit biased--
we're going to
start on TV first.
TV is going to
start advertising.
The way you do this is you set
up Nearby Docket Connections
client.
Nearby is just a nice
singleton helper class
from the Nearby API that
has all these things to help
you get started.
You call Start Advertising.
You're going to give it
a name, a service ID--
package name is perfectly fine.
You're going to give it a
Connection Lifecycle Callback.
And you're going
to set a strategy.
Cluster's a really
good strategy.
If you notice, there is also a
P2P, point-to-point strategy.
And you might be, yeah, it's one
TV, one phone, point-to-point,
this sounds great.
But if you try to do
like multi-device setup--
I have a TV in my living
room, one of my bedroom,
one of my bathroom--
all of a sudden, that
point-to-point breaks down.
So to make a more
robust app, you
should think about
using Cluster.
You also set success
and failure listeners.
Now these listeners aren't
saying, oh, I've been found.
I've advertised
and now I'm found.
These listeners say, you are
able to start advertising.
So they're great for
debugging and adding
extra information
inside your app.
The big elephant on
this slide, though,
is the Connection
Lifecycle Callback.
This callback talks about
how the devices will
talk to each other.
You know, what's going
to be said is later,
but how are they
going to say it now
is handled in the Connection
Lifecycle Callback.
Simple, three methods, on
initiated-- or on initialized,
results, and disconnected.
They're pretty straightforward.
But let's dive in
a little bit more.
So when a connection's
initialized,
that means the phone
requested a connection.
You're going to
prompt for security
and do a couple of things.
But eventually, you're going to
say, nearby docket connections
client, accept connection.
Once the connection
has been accepted,
you'll receive a result.
Based on that result--
was that OK, continue on,
was it rejected, maybe
ask for another retry--
but based on that result, you
should handle appropriately.
And the last one, on
disconnected, is pretty simple.
Just clean up any metadata you
may have started collecting.
The big line here is, the
Connections Client Accept
Connections.
And here you pass in
a payload callback.
This payload callback
is going to be
what the devices communicate.
So you should have a
contract on your phone
and on your TV for what they're
going to say to each other.
Hey phone, we want to do this.
Hey TV, we're going to do this.
This is all handled inside
the payload callback.
So here are a couple tips.
What you're going to communicate
is very specific to your app.
But here's some tips.
The Payload Received and
Payload Transfer Update
are the only two
methods you get.
They're pretty succinct,
pretty good methods, though.
On Payload Receive,
if you want to send
an acknowledgment back--
hey, thanks for
telling us this, phone,
we're going to send back an
acknowledgment so you know
the message has been received--
it's really easy.
You just call, Send Payload.
You give it the endpoint ID that
you receive the payload from,
and some body, in this case, it
would say ack, or acknowledge.
If you want to disconnect--
hey, I received
this payload, I want
to disconnect the connection
and then close this session--
you should do that in
the Transfer Update.
In the Transfer
Update, you should
check to see if it's
in progress or not.
If you're sending small
messages like ack and send,
those are pretty fast.
But if you're sending
something big like a file,
that could take a while.
And you want to check to
make sure all the bytes have
been sent.
Once all the bytes
have been sent,
then you can call
Disconnect from Endpoint.
So to summarize
the TV side, you're
going to advertise,
hey, I'm a TV.
You're going to
accept the connection.
And then you're
going to communicate.
But on the phone, what
happens on the phone side?
It's going to look very similar.
You're going to discover
the TV this time.
You're going to
request the connection.
And then everything
after that is
going to look like the
slides I just showed you.
So to discover the TV, you have
the nearby connection client
again.
This time, you call
Start Discovery.
Mind blown.
You're going to give
it a service ID.
Now this time, I'm
using the constant.
And there's a reason
for the service
ID, depending on your app,
should either be the package
name or the constant.
If you have a
package name that's
the same for both your TV
app and your mobile app,
it's going to work great.
But if you have something
like com.mycompany.android,
or com.mycompany.androidtv
as your two package names,
imagine they're kind of
on their own channels.
And so the Nearby
Connections library
won't be able to find
the phone and the TV.
So having a service ID
that's used by both sides
is a good practice.
Then you're going to give
it a mobile end point
discovery call back, because
I love really big words.
And then you're going
to set a strategy.
This strategy should
be symmetric to what
you set on TV.
So I urge you to use
Cluster for this use case.
You get listeners, again.
These listeners are
pretty important.
These say you are able
to start discovery.
This does require
location permission
because it's going to use
Bluetooth LEE, than default
to other ways to
find nearby people.
So if you get a failure
listener-- you know,
maybe it's like, oh, permission
for location hasn't been
enabled--
so these are great for
debugging and trying to urge
the user down the correct path.
So, the second part,
accept the connection.
Really simple.
You have that mobile end
point discovery callback.
And it has two methods.
You either found an endpoint
or you lost an endpoint.
Pretty simple.
If you find an endpoint, go
ahead and request a connection.
This will trigger the on
connection initialized
on the TV that we saw earlier.
If you lost an endpoint-- maybe
the user walked too far away
from the TV and is
now no longer nearby,
or maybe they gave up and just
closed the app and said forget
it, hopefully it's the first
for you, not the second--
you just clean up
whatever metadata
you had collected already.
Everything after
this is identical.
You're going to have a
connections lifecycle
callback that handles
how they communicate.
Then you're going to have a
payload callback that says what
are they going to communicate.
And that's it.
That's pretty much
Nearby in a nutshell.
But Nearby is a cool tool.
It's nice to have in your tool
box of kits for how to add
more experience to your TV app.
So let's go down Payments.
Let's look at one more example.
Payments, I think,
it's kind of cool.
It adds this family
friendly idea.
Imagine you're at work
and your kid is at home
and they want to buy the
next season of a TV show.
You get a push notification.
Hey, are you sure you want
to purchase this TV show?
And you say, ah man, my
kid's at home buying stuff.
No.
Or, oh man, my kid's at home.
Yeah, they're bored.
Let me use my fingerprint or
face ID or anything, anything
from the phone to
authenticate yourself.
And all of a sudden, you just
enabled a purchase at home
from your office.
I'd argue that's not Nearby.
If there was an API,
it'd be called Far Away.
Right?
And "Shrek" might have been as
close to far away as I've seen,
but I have not seen
that in Android.
So, in this case, Nearby
is not a good fit.
It's a good tool in the toolbox
but it's not necessarily
the best fit.
Maybe there's another good fit.
Let's talk about that
example one more time.
You get a push notification.
And it says, watch
on TV or watch here.
This is the big game.
You want to watch it,
watch it on a small phone?
Eh.
Watch it on a big TV?
Awesome.
You could use Nearby to
figure out proximity.
Yes, they're close to the TV.
We should show the
Watch on TV up button.
That's a great use for Nearby.
Receiving the
notification, hm, this
is a great example
of content immersion.
As soon as you said, watch
on TV, the background lit up.
You're in this immersive view.
Here's the schedule
for the game.
Here's some highlights.
Here's the score.
And then, whenever
the user wants,
they can just put the
phone to the side.
It's very non-intrusive.
And they can focus on the game.
So in a sense, this was kind of
kicked off from a notification.
And in a way, you'd say, hey,
that was more of a push model.
Nearby feels more
like a pulling.
I'm pulling a conversation
between the two devices.
Whereas in this
case, you're more
of pushing that
information to the user.
And there's a talk about
Firebase Cloud Messaging
after this.
And I won't step on
their toes too much.
But we'll just talk
about it for fun.
What's the worst
that can happen?
You set up a Firebase
Messaging Service.
You receive a message.
Based on that message, you
should have some action.
Here's what to do when
you receive that message.
If that action happens to
be, hey, watch this movie
or watch this game,
start watching.
And you're good to go.
Start watching literally
should launch an activity.
This is the Android Dev Summit.
I'm assuming everyone has
launched an activity before.
But just in case,
we set up an intent.
We give it some extras like,
hey, here's the video to watch.
And we start an activity.
Beautiful.
The question really comes
down to what happens
when the TV screen is off?
You know, I'm at home.
I get a push notification.
Oh, man.
The game's about to start.
I have to hit
power on my remote.
I have to tune to the channel.
Man, this is First World
problems at its finest.
But you can solve those.
We have that fragment
activity that's your player.
When you set up everything,
all you have to do
is just call, set Turn
On screen to True.
Now, this is a really
cool API on Activity.
This is actually
introduced in OMR-1.
So if you're on API 27 or
higher, you should do a check.
Hey, turn on screen to True.
Otherwise, you can
just add the flag.
So to summarize how to
build a great TV app,
start with your player.
Your content is king.
So really focus on the player.
Whether it's an ad or
whether it's actual content,
make sure your player is solid.
Next thing, how do you
make your app more usable?
How do you get that
lean back experience
so that users can quickly
find other content to watch?
The third pillar
is distribution.
Is my app set up to be deployed
on the Play Store correctly?
When you have all
three of these,
you end up with happy users.
And who doesn't
want happy users?
But if you want to take
your app even further,
evaluate your users and layer
in these lean in experiences.
How do you do payments?
Having that push notification
for the media control.
How do you add that
immersive content?
Here's the details of the game.
So thank you, everyone.
Go build great TV apps.
[MUSIC PLAYING]
