Hi everyone, and welcome to this quick video about our new TV Reference App.
I’m Ian Clifton, and I work on the Developer Relations team at Google.
With Google TV, both app quality and app integrations are more important than ever.
We’ve done a lot of work to update our documentation,
but we know many developers learn best
when they can look at an actual implementation and start taking it apart.
With that in mind, we’ve built a completely new Reference App.
The Reference App is available today in our public GitHub repository.
So you can go to github.com/android/tv-samples
and check it out.
It’s written in Kotlin, so not surprisingly, if the directory is Reference App Kotlin.
Hopefully also not surprising is that we've included a detailed readme
that covers the various integrations and some of our thought process
behind how we implemented them.
Don’t worry. I won’t read the whole file now.
Instead, we're going to do an overview of the Reference App.
Here’s an Android TV device that has the Reference App installed.
This device is not running the Google TV experience
so that I can easily show you the home screen channel the app creates.
This home screen channel is created
when the system sends the initialized program’s broadcast
which you can send directly to the receiver via ADB,
and I’ll give more details about that in a bit.
The app just creates a single channel and picks content at random to populate it.
Selecting a title here goes into playback but let's launch the app via the banner.
When launched via the banner, you will see this warning screen
that basically tells you Firebase has not configured.
You can still access the videos and most of the features
but some Firebase-dependent functionality is not enabled.
For example, the sample includes code support for Google account linking
but that requires you to set up a Firebase instance.
We have a lot of details in the readme, so let’s continue on to the next screen.
This is the main browse screen
where we have the videos split into rows using a BrowseSupportFragment.
We have two rows of clips which are Developer Relations videos.
Then we have one row for Beverly Hillbillies and one for movies with Charlie Chaplin.
I will select one of the movies to start playback.
Playback uses a VideoSupportFragment to handle the bulk of the UI.
We have a very simple state machine to communicate events
like pause to the different pieces of code that care about them.
The actual playback is handled via ExoPlayer, and it includes support for MediaSession
via MediaSessionConnector.
The MediaSession integration allows for controlling playback
with a remote control, Bluetooth headset or even voice.
You can press the Assistant and say “skip forward five minutes,”
and it skips forward five minutes.
It also supports all kinds of other commands that you'd expect, like pause and play
and even asking what's currently playing.
I'll completely back out of the app now to show one more thing.
Back on the Android TV home screen, there’s a feature called Watch Next.
This feature can be labeled as Play Next or Continue Watching depending on the version
but the idea is the same.
This lets users quickly jump back into the content they were previously watching.
For example, you can see the Charlie Chaplin movie we were watching show up here.
This feature also works for TV episodes, but it should not be used with clips,
which is why we organized the video content in the app the way that we have.
If I select content from Keep Watching, it deep links directly into playback
right where the user left off.
And if I press Back, it returns to the main browse screen.
That's pretty much it from the app experience side of things.
So let's take a quick look at the source code.
Features are organized into packages.
For example, if you wanna see all the code related to home screen channels,
all the relevant files are in the homescreenchannels package.
There are some files that don't really belong to a feature
such as the data models, so those are under the shared package.
You might also notice there’s a package for castconnect, which I didn’t demonstrate.
Cast Connect allows an Android TV app to can act as a Cast Receiver.
You can trigger a playback from another device such as a phone,
but it’s actually the Android TV app that's playing the content.
We have a specific readme for Cast Connect in the repository
that goes over the feature in much more detail
and also walks through the steps of creating a sender
so that you can use the Reference App as a receiver.
I want to highlight just a few things in the source code.
First, in the resources directory, we have a raw JSON file that tells the app
about all the metadata for our videos.
It’s nicely formatted, so you can easily modify it yourself
in case you want to test something out.
We also included a scripts folder
that has an atv-csv-to-json Python script
so you can always provide your own CSV if you want to bulk change all of this data.
I mentioned homescreenchannels earlier.
That package contains the receiver that triggers the initial building of the channel.
You can look at that file or the main readme file
to see the exact ADB command you use to trigger the receiver.
The receiver only exists to get that broadcast
and tell the WorkManager about new work to do.
The worker contains the high-level code like if a channel doesn’t exist, create one.
The helper contains all the lower-level logic
like how to query for which programs have been added to a given home screen channel.
The watchnext code follows a similar pattern of a worker with high-level code
and helper with low-level details.
One difference is that the watchnext code
is triggered by a listener, which brings us to playback.
Playback has more files in it, but the important ones
are PlaybackFragment, PlaybackViewModel,
and PlaybackStateMachine.
Starting with the StateMachine,
it defines a simple interface to receive state changes
and a sealed class that has all the states like Load, Prepare, Play, etc.
The ViewModel provides an implementation of the state machine that uses a list
of PlaybackStateListeners and informs them of the changes.
State machines can get complicated
so we also created a state machine readme that has more details.
The overall idea is that different parts of unrelated code care about the states.
For example, the WatchNextListener
wants to know when playback is paused or ends
so it can update the Watch Next row using the worker I mentioned.
There's also a completely separate WatchProgressListener
that cares about similar events
because it triggers updates to a SQLite database via Room.
That way future playback events can start from the correct position.
These listeners are completely independent, which keeps the code much cleaner.
On top of that, the PlaybackFragment doesn’t actually know anything about these listeners
because they have nothing to do with the user interface.
That's it for our quick look at the TV Reference App.
If you don’t have a physical Android TV device,
you can run it via the Android TV emulator.
So be sure to check out the repository and let us know what you think.