Google Play Services: Google Cast v3 and Media

Google Cast is a technology that allows users to send online content to a device, such as a Chromecast or Android TV, connected to a television. Once the content is available on the television, users can control it from their mobile device or computer.

In this tutorial, you will learn how to create a basic Cast-enabled application for Android using the Cast SDK v3, which was announced during the 2016 Google I/O conference.

Cast Console Setup

Google Cast is built around two components: the receiver, which is essentially a webpage that is displayed on a casting device with your content, and the sender, which is the client program that requests media and controls playback.

Before you can create your sender application, you will need to register an account on the Google Cast Developer Console, and then create and configure a new receiver application. In order to register an account, you will need to pay a one-time $5 fee. Once your account is created, you can click on the red ADD NEW APPLICATION button to create a new receiver application.

Next, you will have three options: Custom Receiver, Styled Media Receiver, and Remote Display Receiver. For simplicity, in this tutorial you will use a Styled Media Receiver.

On the next screen, you will be able to select some basic settings for your receiver, such as the application name, an optional URL for a CSS style sheet to customize the look of the receiver, and the ability to enable guest mode and audio-only casting.

Once you hit the blue Save button, you will be presented with a screen that shows you the basic details of your new receiver app. You'll notice that this screen also contains your new Application ID. You will need to use this value in your Android application.

It's worth noting that even though your receiver app is created, it may take a few hours to be discoverable by your sender application.

In order to test, you will need to white-list at least one casting device. You can do this from the Google Cast Developer Console by clicking on the red ADD NEW DEVICE button. On the screen that comes up, you can enter your device's serial number and a description to white-list it for testing with your receiver application.

At this point, you should have a receiver created and a test device white-listed, so you're all set to start building an Android sender app. When you have created and published your application on the Play Store, you will want to return to the Cast Developer Console to publish your receiver, allowing any casting device to be used with your sender app.

Android Setup

The first thing you'll need to do in your Android app is include the Cast Framework and Media Router libraries under the dependencies node in your build.gradle file.

Next, you will want to store the application ID that you were given when creating your receiver in your strings.xml file.

<string name="cast_app_id">(your ID goes here)</string>

The final step in the setup process is including the Internet permission for your application. Open AndroidManifest.xml and include the following line before your application node.

<uses-permission android:name="android.permission.INTERNET" />

Now that your setup is done, you can move on to including the media route button in your application.

Displaying a Routing Button and Connecting to Cast Devices

The routing button is the icon in an application's toolbar that generally signifies that an app supports casting for the user.

In order to get this button to appear in your application's Toolbar, the easiest way is to include it in the menu XML file for your Activity (it's also recommended that this go into every Activity in your app).

Once your media route button is initialized, you will want to add state listeners to your application for casting.

Available Listeners

While there are multiple listeners available, there are three worth discussing as you start to use the Google Cast framework.

CastStateListener: This listener monitors the current casting state of an app. It is triggered when the app has switched to CONNECTING, CONNECTED, NOT_CONNECTED, or NO_DEVICES_AVAILABLE.

AppVisibilityListener: This listener has two methods: onAppEnteredForeground and onAppEnteredBackground. These methods are called when your app has been backgrounded by your user, or when the user has reopened your application, respectively.

SessionManagerListener: The final listener we'll go over is also the most verbose. A Session is the lifecycle of user interaction with a casting device, starting when the user has connected to a device, maintained through casting, and ending when the user has disconnected. The Google Cast Android framework interacts with the Session through the SessionManager object.

These three listeners can be associated with the Google Cast framework like so, where this in this example is the Activity that has implemented each of the above interfaces.

You may have also noticed that you access the SessionManager and Cast framework using CastContext.getSharedInstance(Context). This is because the CastContext, the main interaction point between your app and the Cast framework, is lazily initialized for improved app performance.

When your Activity is no longer active, you will need to remember to remove these listeners.

Creating an OptionsProvider

In order to do anything with the Cast framework, you will need to create a new class that extends OptionsProvider. This class will be where you can configure various options for your sender app.

We'll keep this simple for now and just return a CastOptions object from the getCastOptions method, which will enable resuming saved sessions and reconnecting to sessions that are already in progress (though both of these are already enabled by default, they are provided here as examples).

The CastOptions object is also where your receiver app ID is associated with your sender. Although the method getAdditionalSessionProviders must be declared in this class, we can safely ignore it for our purposes.

At this point, your application should be able to find any white-listed casting devices and connect to them through your application.

Routing Dialog Styling

Depending on the theme that you are using in your app (such as Theme.AppCompat.Light.NoActionBar), you may have noticed some weird behaviors with colors in the casting device dialog, such as white font and icons on a white background.

You may also decide that you want to customize how the dialog appears to fit with your application. You can do this by overriding the two styles used for the Cast dialog: Theme.MediaRouter.Light.DarkControlPanel and Theme.MediaRouter.LightControlPanel. For example, if you are running into white font on a white background, you can include the following code in your styles.xml file to change the icons and font color to be black on the white background.

Casting Content

Once you've connected to a casting device, you'll probably want to let your users cast content to it. Luckily, the Cast SDK makes this incredibly easy to do. In your app, you will want to determine if your user has connected to a device, which can be done by ensuring that the SessionManager has a current Session and that the current Session has a RemoteMediaClient object associated with it.

Once you know that the application is associated with a RemoteMediaClient, you will want to create a MediaInfo object that contains a link to the remote content you want to play, as well as the streaming and content types for your media. When MediaInfo is created and populated, you can call the load method on the RemoteMediaClient to start casting the content. For example, the following code will cast a video file to the television.

Metadata

The receiver and UI components in the Cast SDK use a MediaMetadata object for storing and referencing information about the media that is currently being played. You can add values to this object using keys provided by the class, and you can add image URLs using the addImage method.

UI Components

While the Cast SDK handles the logic for connecting and casting content to the television, it also provides multiple UI components that help developers meet the Casting UI design guidelines.

Introductory Overlay

When your user first opens your application, it's recommended that you let them know that you support Google Cast. You can do this by including an IntroductoryOverlay, which will highlight the cast button as it becomes available for the first time.

To include the IntroductoryOverlay, the first thing you will want to do is add it as a member variable at the top of your main activity.

private IntroductoryOverlay mIntroductoryOverlay;

Once you have a common object for the overlay, you can create a method that will check to see if the media router button is shown, and if shown, will display the overlay.

This component is fleshed out using a simple builder pattern that will accept a String for the text, a color resource ID, and a few other customization attributes. More often than not, you will also want to make sure that you call setSingleTime(), so that the overlay is only ever shown once for the user.

Now that you have a method created to display the overlay, you will simply need to call it. There are two points where you should add this method: in onCreateOptionsMenu, and in onCastStateChanged from your CastStateListener when the state is not NO_DEVICES_AVAILABLE. This will handle both contingencies of when the routing button could appear.

At this point, you should be able to start up your app and see the overlay, as shown in the next figure. If you need to see it again for testing purposes, you can clear your application's data and reopen.

Expanded Controls

While casting, you'll want to be able to provide an easy UI widget for controlling content on the user's television. Google has made this easy by providing the ExpandedControllerActivity class within the Cast SDK.

To use this, create a new Java class and extend ExpandedControllerActivity. This tutorial will create one called ExpandedControlsActivity. Once your activity is created, update onCreateOptionsMenu to include the casting routing button within the toolbar.

Next, open your OptionsProvider class. You will want to go into the getCastOptions method and create a CastMediaOptions object that ties in to your ExpandedControllerActivity. Once your CastMediaOptions object is created, you can associate it with the CastOptions item that is returned by the method.

You should notice that the activity node has a theme property set. This style is used to optionally customize the ExpandedControllerActivity and the buttons that are displayed.

The controller consists of four customizable button slots, with a play/pause toggle in the middle. Using a new style and an array resources, you can customize which buttons appear. In arrays.xml, I have added a new array that sets slot 1 to empty, slot 2 to the 30-second rewind button, slot 3 (first item to the right of the play/pause toggle) to fast forward 30 seconds, and the last slot to host a mute toggle.

At this point, you should be able to click on the image in your router dialog for casted media to open your new controller Activity, or launch it yourself from within your application with a simple startActivity call.

startActivity(new Intent(this, ExpandedControlsActivity.class));

Notification/Lock Screen Controls

When a user is casting content to their TV, there's a good chance that they won't keep your app in the foreground or their phone unlocked. When they navigate away from your app, you will want to provide an easy way for them to control the content of your app. You can do this by adding a notification to your app when it is not in the foreground for Lollipop and above devices, and the Cast SDK will handle creating a lock screen RemoteControlClient for KitKat and earlier devices.

Adding notification/lock screen controls is rather straightforward, as it is all handled in the getCastOptions method of your OptionsProvider (CastOptionsProvider.java for this tutorial).

First, you will need to create an ArrayList of strings that will contain the buttons that you want for your controls. Next, you can create an int array that will contain the indices of the buttons that you will want to display when the notification is in compact mode.

Once you have your two arrays created, you will create a NotificationOptions object that binds the actions to the new notification and assign an Activity to be opened when the notification is selected. For this example, we will simply use the ExpandedControlsActivity that we created in the last section.

Now, when your users cast content to their televisions and lock the screen or navigate away from your app, a notification will appear that allows them to control the content on the big screen while they continue to interact with their phone. Clicking on the notification outside of the controls will bring your app back to the forefront with the ExpandedControlsActivity, giving your users more fine-grained control of their viewing experience.

Mini Controller

The last UI widget you will learn about in this tutorial is the MiniControllerFragment. This item can be placed in your activity layout files, and when your app is casting content, it will automatically become visible and provide an easily accessed controller for your users as they browse your app. Although this is the last component that we will discuss, it is also by far the easiest to implement. You simply need to include it in your layout files, like so.

When you click on this item anywhere outside of the play/pause toggle, your ExtendedControllerActivity will be brought up, giving your users easy access to the content on their television.

Conclusion

In this tutorial you have learned a lot about the new Google Cast SDK for Android, the UI components that are provided within it, and how to create a basic styled receiver application for casting. What you've covered here will help you build the most common types of casting applications, though Google also provides features that will let you quickly create Cast-enabled games and custom receiver applications.