130
Google Cast with Android How to Implement Google Cast into Android Apps +Angelo Rüggeberg @s3xy4ngyc

Implementing cast in android

Embed Size (px)

Citation preview

Page 1: Implementing cast in android

Google Cast with Android How to Implement Google Cast into Android Apps

+Angelo Rüggeberg @s3xy4ngyc

Page 2: Implementing cast in android

agenda

-  Introduction to Google Cast

-  Connecting an Android App to an

Cast App

-  Launching the Cast App

-  Interacting with the Cast App

-  using the CastCompanionLibrary

for Media

Page 3: Implementing cast in android

Introduction to Google Cast

Page 4: Implementing cast in android
Page 5: Implementing cast in android

Biggest, most beautiful screen in the house...

Page 6: Implementing cast in android

Your app on the TV!

Page 7: Implementing cast in android

Simple to get started with the SDK

Page 8: Implementing cast in android

Connecting technology

Page 9: Implementing cast in android

Start with your existing app

Page 10: Implementing cast in android

e.g. Phone app

Page 11: Implementing cast in android

e.g. Phone app

Page 12: Implementing cast in android

e.g. Phone app

Page 13: Implementing cast in android

Tablets

Page 14: Implementing cast in android

Web Apps

Page 15: Implementing cast in android

Your app is ‘The Sender’

Page 16: Implementing cast in android

Receiving device

Page 17: Implementing cast in android

Receiver app runs on Cast receiving device

Page 18: Implementing cast in android

Cast SDK app looks for Cast devices

Page 19: Implementing cast in android

Cast icon shown on discovery of Cast devices

Page 20: Implementing cast in android

Selection activates connected icon look

Page 21: Implementing cast in android

developers.google.com/cast/docs/ux_guidelines

Consistent UX fully documented

Page 22: Implementing cast in android

developers.google.com/cast/ docs/ux_guidelines

●  Selecting Cast Device ●  Pausing & Scrubbing ●  Visual Consistency

Page 23: Implementing cast in android

Sender triggers Receiver loading

Page 24: Implementing cast in android

https://…

Content loads direct from the cloud

Page 25: Implementing cast in android

https://…

Sender manages playback control

Page 26: Implementing cast in android

developers.google.com/cast/docs/receiver_apps

Page 27: Implementing cast in android

Images

Page 28: Implementing cast in android

Leader Board

1st Scotty 145

2nd Andrea 109

3rd Ralph 94

Page 29: Implementing cast in android
Page 30: Implementing cast in android

developers.google.com/cast/docs/downloads

Page 31: Implementing cast in android

Connecting an Android App to an Cast App

Page 32: Implementing cast in android

Environment: ●  Real Device

○  with Google Play Services Installed

●  Cast Device ○  e.g. Chromecast

Prequesites

Dependencies: play-services-cast

Handles Connection to Cast 'com.google.android.gms:play-services-cast:8.3.0'

support-media-router

Button to Connect to Cast 'com.android.support:mediarouter-v7:23.1.0'

Page 33: Implementing cast in android

Dependencies - build.gradle

dependencies { compile 'com.android.support:mediarouter-v7:23.1.0' compile 'com.google.android.gms:play-services-cast:8.3.0' }

Page 34: Implementing cast in android

Permissions - Manifest.xml

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

Page 35: Implementing cast in android

Adding Media Route Button via Menu

<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/media_route_menu_item" android:title="@string/media_route_menu_title" app:actionProviderClass="android.support.v7.app.MediaRouteActionProvider" app:showAsAction="always"/> </menu>

Page 36: Implementing cast in android

Adding Media Route Button via Menu

<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/media_route_menu_item" android:title="@string/media_route_menu_title" app:actionProviderClass="android.support.v7.app.MediaRouteActionProvider" app:showAsAction="always"/> </menu>

Page 37: Implementing cast in android

Adding Media Route Button to an Layout

<RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" /> <android.support.v7.app.MediaRouteButton android:id="@+id/media_route_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:mediaRouteTypes="user" /> … </RelativeLayout>

Page 38: Implementing cast in android

Adding Media Route Button to an Layout

<RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" /> <android.support.v7.app.MediaRouteButton android:id="@+id/media_route_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:mediaRouteTypes="user" /> … </RelativeLayout>

Page 39: Implementing cast in android

Adding Media Route Button to an Layout

<RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" /> <android.support.v7.app.MediaRouteButton android:id="@+id/media_route_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:mediaRouteTypes="user" /> … </RelativeLayout>

Page 40: Implementing cast in android

Fields - MainActivity.java

private MediaRouteButton mMediaRouteButton; private MediaRouter mMediaRouter; private MediaRouteSelector mMediaRouteSelector; private MediaRouter.Callback mMediaRouterCallback; private CastDevice mSelectedDevice;

Page 41: Implementing cast in android

Fields - MainActivity.java

private MediaRouteButton mMediaRouteButton; private MediaRouter mMediaRouter; private MediaRouteSelector mMediaRouteSelector; private MediaRouter.Callback mMediaRouterCallback; private CastDevice mSelectedDevice;

The Button added To the Layout

Page 42: Implementing cast in android

Fields - MainActivity.java

private MediaRouteButton mMediaRouteButton; private MediaRouter mMediaRouter; private MediaRouteSelector mMediaRouteSelector; private MediaRouter.Callback mMediaRouterCallback; private CastDevice mSelectedDevice;

The Media Router. This handles the Connection to our Cast Device

Page 43: Implementing cast in android

Fields - MainActivity.java

private MediaRouteButton mMediaRouteButton; private MediaRouter mMediaRouter; private MediaRouteSelector mMediaRouteSelector; private MediaRouter.Callback mMediaRouterCallback; private CastDevice mSelectedDevice; The Route Selector.

This is the Configuration for our Connection e.g the Device to Interact with

Page 44: Implementing cast in android

Fields - MainActivity.java

private MediaRouteButton mMediaRouteButton; private MediaRouter mMediaRouter; private MediaRouteSelector mMediaRouteSelector; private MediaRouter.Callback mMediaRouterCallback; private CastDevice mSelectedDevice;

The Router Callbacks. These Callbacks are used to Notify the Application on Select and Deselction of an Device Route and enables us to react to these events e.g by printing the Connected Device to the User.

Page 45: Implementing cast in android

Fields - MainActivity.java

private MediaRouteButton mMediaRouteButton; private MediaRouter mMediaRouter; private MediaRouteSelector mMediaRouteSelector; private MediaRouter.Callback mMediaRouterCallback; private CastDevice mSelectedDevice;

The Cast Device we are Connected to. It contains Informations like Device Name, Model, Capabilities, etc.

Page 46: Implementing cast in android

Initializing - MainActivity.java

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); mConnectionStatus = (TextView) findViewById(R.id.text_connection); mMediaRouteButton = (MediaRouteButton) findViewById(R.id.media_route_button); initCast(); }

Page 47: Implementing cast in android

Initializing - MainActivity.java

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); mConnectionStatus = (TextView) findViewById(R.id.text_connection); mMediaRouteButton = (MediaRouteButton) findViewById(R.id.media_route_button); initCast(); }

Page 48: Implementing cast in android

Initializing - MainActivity.java

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); mConnectionStatus = (TextView) findViewById(R.id.text_connection); mMediaRouteButton = (MediaRouteButton) findViewById(R.id.media_route_button); initCast(); }

Page 49: Implementing cast in android

Initializing - MainActivity.java

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); mConnectionStatus = (TextView) findViewById(R.id.text_connection); mMediaRouteButton = (MediaRouteButton) findViewById(R.id.media_route_button); initCast(); }

Page 50: Implementing cast in android

Initializing - MainActivity.java private void initCast() { // Configure Cast device discovery mMediaRouter = MediaRouter.getInstance(getApplicationContext()); }

Page 51: Implementing cast in android

Initializing - MainActivity.java private void initCast() { // Configure Cast device discovery mMediaRouter = MediaRouter.getInstance(getApplicationContext()); mMediaRouteSelector = new MediaRouteSelector.Builder() .addControlCategory( CastMediaControlIntent.categoryForCast(getResources().getString(R.string.app_id))) .build(); }

Page 52: Implementing cast in android

Initializing - MainActivity.java private void initCast() { // Configure Cast device discovery mMediaRouter = MediaRouter.getInstance(getApplicationContext()); mMediaRouteSelector = new MediaRouteSelector.Builder() .addControlCategory( CastMediaControlIntent.categoryForCast(getResources().getString(R.string.app_id))) .build(); } The Cast Application ID.

E.g “794B7BBF” (Cast Sample Helloworld)

Page 53: Implementing cast in android

Initializing - MainActivity.java private void initCast() { // Configure Cast device discovery mMediaRouter = MediaRouter.getInstance(getApplicationContext()); mMediaRouteSelector = new MediaRouteSelector.Builder() .addControlCategory(CastMediaControlIntent.categoryForCast(getResources() .getString(R.string.app_id))) .build(); // Set the MediaRouteButton selector for device discovery. mMediaRouteButton.setRouteSelector(mMediaRouteSelector); }

Page 54: Implementing cast in android

Initializing - MainActivity.java @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item); MediaRouteActionProvider mediaRouteActionProvider = (MediaRouteActionProvider) MenuItemCompat .getActionProvider(mediaRouteMenuItem); // Set the MediaRouteActionProvider selector for device discovery. mediaRouteActionProvider.setRouteSelector(mMediaRouteSelector); return true; }

Page 55: Implementing cast in android

Initializing - MainActivity.java @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item); MediaRouteActionProvider mediaRouteActionProvider = (MediaRouteActionProvider) MenuItemCompat .getActionProvider(mediaRouteMenuItem); // Set the MediaRouteActionProvider selector for device discovery. mediaRouteActionProvider.setRouteSelector(mMediaRouteSelector); return true; }

Page 56: Implementing cast in android

Initializing - MainActivity.java @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item); MediaRouteActionProvider mediaRouteActionProvider = (MediaRouteActionProvider) MenuItemCompat .getActionProvider(mediaRouteMenuItem); // Set the MediaRouteActionProvider selector for device discovery. mediaRouteActionProvider.setRouteSelector(mMediaRouteSelector); return true; }

Page 57: Implementing cast in android

Initializing - MainActivity.java @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item); MediaRouteActionProvider mediaRouteActionProvider = (MediaRouteActionProvider) MenuItemCompat .getActionProvider(mediaRouteMenuItem); // Set the MediaRouteActionProvider selector for device discovery. mediaRouteActionProvider.setRouteSelector(mMediaRouteSelector); return true; }

Page 58: Implementing cast in android

Adding Callbacks - MainActivity.java private void initCast() { // Configure Cast device discovery mMediaRouter = MediaRouter.getInstance(getApplicationContext()); mMediaRouteSelector = new MediaRouteSelector.Builder() .addControlCategory(CastMediaControlIntent.categoryForCast(getResources() .getString(R.string.app_id))) .build(); // Set the MediaRouteButton selector for device discovery. mMediaRouteButton.setRouteSelector(mMediaRouteSelector); mMediaRouterCallback = new MyMediaRouterCallback(); }

Page 59: Implementing cast in android

Adding Callbacks - MainActivity.java private class MyMediaRouterCallback extends MediaRouter.Callback { @Override public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) { // Handle the user route selection. mSelectedDevice = CastDevice.getFromBundle(info.getExtras()); mConnectionStatus.setText("Connected to: " + mSelectedDevice.getFriendlyName()); } @Override public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) { mSelectedDevice = null; mConnectionStatus.setText("Not Connected"); } }

Page 60: Implementing cast in android

Adding Callbacks - MainActivity.java private class MyMediaRouterCallback extends MediaRouter.Callback { @Override public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) { // Handle the user route selection. mSelectedDevice = CastDevice.getFromBundle(info.getExtras()); mConnectionStatus.setText("Connected to: " + mSelectedDevice.getFriendlyName()); } @Override public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) { mSelectedDevice = null; mConnectionStatus.setText("Not Connected"); } }

Page 61: Implementing cast in android

Adding Callbacks - MainActivity.java private class MyMediaRouterCallback extends MediaRouter.Callback { @Override public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) { // Handle the user route selection. mSelectedDevice = CastDevice.getFromBundle(info.getExtras()); mConnectionStatus.setText("Connected to: " + mSelectedDevice.getFriendlyName()); } @Override public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) { mSelectedDevice = null; mConnectionStatus.setText("Not Connected"); } }

Called after we Selected an Cast Device we want to Connect with. This does not mean we are Connected to the Cast Application yet!

Page 62: Implementing cast in android

Adding Callbacks - MainActivity.java private class MyMediaRouterCallback extends MediaRouter.Callback { @Override public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) { // Handle the user route selection. mSelectedDevice = CastDevice.getFromBundle(info.getExtras()); mConnectionStatus.setText("Connected to: " + mSelectedDevice.getFriendlyName()); } @Override public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) { mSelectedDevice = null; mConnectionStatus.setText("Not Connected"); } }

Called after we Decided to Disconnect from an Cast Device. This does not mean we are Disconnected from the Application yet!

Page 63: Implementing cast in android

Adding Callbacks - MainActivity.java private class MyMediaRouterCallback extends MediaRouter.Callback { @Override public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) { // Handle the user route selection. mSelectedDevice = CastDevice.getFromBundle(info.getExtras()); mConnectionStatus.setText("Connected to: " + mSelectedDevice.getFriendlyName()); } @Override public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) { mSelectedDevice = null; mConnectionStatus.setText("Not Connected"); } }

Page 64: Implementing cast in android

Adding Callbacks - MainActivity.java private class MyMediaRouterCallback extends MediaRouter.Callback { @Override public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) { // Handle the user route selection. mSelectedDevice = CastDevice.getFromBundle(info.getExtras()); mConnectionStatus.setText("Connected to: " + mSelectedDevice.getFriendlyName()); } @Override public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) { mSelectedDevice = null; mConnectionStatus.setText("Not Connected"); } }

Page 65: Implementing cast in android

Adding Callbacks - MainActivity.java private class MyMediaRouterCallback extends MediaRouter.Callback { @Override public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) { // Handle the user route selection. mSelectedDevice = CastDevice.getFromBundle(info.getExtras()); mConnectionStatus.setText("Connected to: " + mSelectedDevice.getFriendlyName()); } @Override public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) { mSelectedDevice = null; mConnectionStatus.setText("Not Connected"); } }

Page 66: Implementing cast in android

Starting Discovery - MainActivity.java @Override protected void onStart() { super.onStart(); // Start media router discovery mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); } @Override protected void onStop() { // End media router discovery mMediaRouter.removeCallback(mMediaRouterCallback); super.onStop(); }

Page 67: Implementing cast in android

Starting Discovery - MainActivity.java @Override protected void onStart() { super.onStart(); // Start media router discovery mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); } @Override protected void onStop() { // End media router discovery mMediaRouter.removeCallback(mMediaRouterCallback); super.onStop(); }

Page 68: Implementing cast in android

Starting Discovery - MainActivity.java @Override protected void onStart() { super.onStart(); // Start media router discovery mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); } @Override protected void onStop() { // End media router discovery mMediaRouter.removeCallback(mMediaRouterCallback); super.onStop(); }

Page 69: Implementing cast in android

Demo

Page 70: Implementing cast in android

Launching the Cast Application

Page 71: Implementing cast in android

New Fields - MainActivity.java

private GoogleApiClient mApiClient; private Cast.Listener mCastListener; private ConnectionCallbacks mConnectionCallbacks; private ConnectionFailedListener mConnectionFailedListener; private boolean mApplicationStarted; private boolean mWaitingForReconnect; private String mSessionId;

Page 72: Implementing cast in android

New Fields - MainActivity.java

private GoogleApiClient mApiClient; private Cast.Listener mCastListener; private ConnectionCallbacks mConnectionCallbacks; private ConnectionFailedListener mConnectionFailedListener; private boolean mApplicationStarted; private boolean mWaitingForReconnect; private String mSessionId;

The Api Client is used to Interact with The Chromecast e.g. Sending Messages

Page 73: Implementing cast in android

New Fields - MainActivity.java

private GoogleApiClient mApiClient; private Cast.Listener mCastListener; private ConnectionCallbacks mConnectionCallbacks; private ConnectionFailedListener mConnectionFailedListener; private boolean mApplicationStarted; private boolean mWaitingForReconnect; private String mSessionId;

Our Callbacks to Notify us about Connection Events e.g. disconnection

Page 74: Implementing cast in android

New Fields - MainActivity.java

private GoogleApiClient mApiClient; private Cast.Listener mCastListener; private ConnectionCallbacks mConnectionCallbacks; private ConnectionFailedListener mConnectionFailedListener; private boolean mApplicationStarted; private boolean mWaitingForReconnect; private String mSessionId;

The Connection Callbacks. e.G. we get disconnected due to application errors

Page 75: Implementing cast in android

New Fields - MainActivity.java

private GoogleApiClient mApiClient; private Cast.Listener mCastListener; private ConnectionCallbacks mConnectionCallbacks; private ConnectionFailedListener mConnectionFailedListener; private boolean mApplicationStarted; private boolean mWaitingForReconnect; private String mSessionId;

Our Callback if the connection Fails

Page 76: Implementing cast in android

New Fields - MainActivity.java

private GoogleApiClient mApiClient; private Cast.Listener mCastListener; private ConnectionCallbacks mConnectionCallbacks; private ConnectionFailedListener mConnectionFailedListener; private boolean mApplicationStarted; private boolean mWaitingForReconnect; private String mSessionId;

We keep Some Information for our Application stored in these Fields

Page 77: Implementing cast in android

Launching the Cast Application - MainActivity.java

private void launchReceiver() { mCastListener = new Cast.Listener() { @Override public void onApplicationDisconnected(int errorCode) { Log.d(TAG, "application has stopped"); teardown(true); } }; }

Page 78: Implementing cast in android

Launching the Cast Application - MainActivity.java

private void launchReceiver() { mCastListener = new Cast.Listener() { … }; mConnectionCallbacks = new ConnectionCallbacks(); mConnectionFailedListener = new ConnectionFailedListener(); }

Page 79: Implementing cast in android

Launching the Cast Application - MainActivity.java

private void launchReceiver() { mCastListener = new Cast.Listener() { … }; mConnectionCallbacks = new ConnectionCallbacks(); mConnectionFailedListener = new ConnectionFailedListener(); Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions .builder(mSelectedDevice, mCastListener); }

Page 80: Implementing cast in android

Launching the Cast Application - MainActivity.java

private void launchReceiver() { mCastListener = new Cast.Listener() { … }; mConnectionCallbacks = new ConnectionCallbacks(); mConnectionFailedListener = new ConnectionFailedListener(); Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions .builder(mSelectedDevice, mCastListener); }

Page 81: Implementing cast in android

Launching the Cast Application - MainActivity.java

private void launchReceiver() { mCastListener = new Cast.Listener() { … }; mConnectionCallbacks = new ConnectionCallbacks(); mConnectionFailedListener = new ConnectionFailedListener(); Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions .builder(mSelectedDevice, mCastListener); mApiClient = new GoogleApiClient.Builder(this) .addApi(Cast.API, apiOptionsBuilder.build()) .addConnectionCallbacks(mConnectionCallbacks) .addOnConnectionFailedListener(mConnectionFailedListener) .build(); }

Page 82: Implementing cast in android

Launching the Cast Application - MainActivity.java

private void launchReceiver() { mCastListener = new Cast.Listener() { … }; mConnectionCallbacks = new ConnectionCallbacks(); mConnectionFailedListener = new ConnectionFailedListener(); Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions .builder(mSelectedDevice, mCastListener); mApiClient = new GoogleApiClient.Builder(this) .addApi(Cast.API, apiOptionsBuilder.build()) .addConnectionCallbacks(mConnectionCallbacks) .addOnConnectionFailedListener(mConnectionFailedListener) .build(); }

Page 83: Implementing cast in android

Launching the Cast Application - MainActivity.java

private void launchReceiver() { mCastListener = new Cast.Listener() { … }; mConnectionCallbacks = new ConnectionCallbacks(); mConnectionFailedListener = new ConnectionFailedListener(); Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions .builder(mSelectedDevice, mCastListener); mApiClient = new GoogleApiClient.Builder(this) .addApi(Cast.API, apiOptionsBuilder.build()) .addConnectionCallbacks(mConnectionCallbacks) .addOnConnectionFailedListener(mConnectionFailedListener) .build(); }

Page 84: Implementing cast in android

Launching the Cast Application - MainActivity.java

private void launchReceiver() { mCastListener = new Cast.Listener() { … }; mConnectionCallbacks = new ConnectionCallbacks(); mConnectionFailedListener = new ConnectionFailedListener(); Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions .builder(mSelectedDevice, mCastListener); mApiClient = new GoogleApiClient.Builder(this) .addApi(Cast.API, apiOptionsBuilder.build()) .addConnectionCallbacks(mConnectionCallbacks) .addOnConnectionFailedListener(mConnectionFailedListener) .build(); mApiClient.connect(); }

Page 85: Implementing cast in android

Launching the Cast Application - MainActivity.java

private class ConnectionCallbacks implements GoogleApiClient.ConnectionCallbacks { @Override public void onConnected(Bundle connectionHint) { ... // Launch the receiver app Cast.CastApi.launchApplication(mApiClient, getString(R.string.app_id), false) .setResultCallback( new ResultCallback<Cast.ApplicationConnectionResult>() { @Override public void onResult(Cast.ApplicationConnectionResult result) {

… } }

Page 86: Implementing cast in android

Launching the Cast Application - MainActivity.java

private class ConnectionCallbacks implements GoogleApiClient.ConnectionCallbacks { @Override public void onConnected(Bundle connectionHint) { ... // Launch the receiver app Cast.CastApi.launchApplication(mApiClient, getString(R.string.app_id), false) .setResultCallback( new ResultCallback<Cast.ApplicationConnectionResult>() { @Override public void onResult(Cast.ApplicationConnectionResult result) {

… } }

Page 87: Implementing cast in android

Launching the Cast Application - MainActivity.java

Status status = result.getStatus(); if (status.isSuccess()) { ApplicationMetadata applicationMetadata = result .getApplicationMetadata(); mSessionId = result.getSessionId(); mApplicationStarted = true; } else { Log.e(TAG, "application could not launch"); teardown(true); }

Page 88: Implementing cast in android

Launching the Cast Application - MainActivity.java

Status status = result.getStatus(); if (status.isSuccess()) { ApplicationMetadata applicationMetadata = result .getApplicationMetadata(); mSessionId = result.getSessionId(); mApplicationStarted = true; } else { Log.e(TAG, "application could not launch"); teardown(true); }

Page 89: Implementing cast in android

Launching the Cast Application - MainActivity.java

Status status = result.getStatus(); if (status.isSuccess()) { ApplicationMetadata applicationMetadata = result .getApplicationMetadata(); mSessionId = result.getSessionId(); mApplicationStarted = true; } else { Log.e(TAG, "application could not launch"); teardown(true); }

Page 90: Implementing cast in android

Launching the Cast Application - MainActivity.java

Status status = result.getStatus(); if (status.isSuccess()) { ApplicationMetadata applicationMetadata = result .getApplicationMetadata(); mSessionId = result.getSessionId(); mApplicationStarted = true; } else { Log.e(TAG, "application could not launch"); teardown(true); }

Page 91: Implementing cast in android

Launching the Cast Application - MainActivity.java

private void teardown(boolean selectDefaultRoute) { if (mApiClient != null) { if (mApplicationStarted) { if (mApiClient.isConnected() || mApiClient.isConnecting()) { Cast.CastApi.stopApplication(mApiClient, mSessionId); mApiClient.disconnect(); } mApplicationStarted = false; } mApiClient = null; } mSelectedDevice = null; mWaitingForReconnect = false; mSessionId = null; }

Page 92: Implementing cast in android

Launching the Cast Application - MainActivity.java

private void teardown(boolean selectDefaultRoute) { if (mApiClient != null) { if (mApplicationStarted) { if (mApiClient.isConnected() || mApiClient.isConnecting()) { Cast.CastApi.stopApplication(mApiClient, mSessionId); mApiClient.disconnect(); } mApplicationStarted = false; } mApiClient = null; } mSelectedDevice = null; mWaitingForReconnect = false; mSessionId = null; }

Page 93: Implementing cast in android

Launching the Cast Application - MainActivity.java

private void teardown(boolean selectDefaultRoute) { if (mApiClient != null) { if (mApplicationStarted) { if (mApiClient.isConnected() || mApiClient.isConnecting()) { Cast.CastApi.stopApplication(mApiClient, mSessionId); mApiClient.disconnect(); } mApplicationStarted = false; } mApiClient = null; } mSelectedDevice = null; mWaitingForReconnect = false; mSessionId = null; }

Page 94: Implementing cast in android

Launching the Cast Application - MainActivity.java

private void teardown(boolean selectDefaultRoute) { if (mApiClient != null) { if (mApplicationStarted) { if (mApiClient.isConnected() || mApiClient.isConnecting()) { Cast.CastApi.stopApplication(mApiClient, mSessionId); mApiClient.disconnect(); } mApplicationStarted = false; } mApiClient = null; } mSelectedDevice = null; mWaitingForReconnect = false; mSessionId = null; }

Page 95: Implementing cast in android

Demo

Page 96: Implementing cast in android

Interacting with the Cast Application

Page 97: Implementing cast in android

Sending Messages - MainActivity.java

class HelloWorldChannel implements Cast.MessageReceivedCallback { public String getNamespace() { return getString(R.string.namespace); } @Override public void onMessageReceived(CastDevice castDevice, String namespace, String message) { } }

Page 98: Implementing cast in android

Sending Messages - MainActivity.java

class HelloWorldChannel implements Cast.MessageReceivedCallback { public String getNamespace() { return getString(R.string.namespace); } @Override public void onMessageReceived(CastDevice castDevice, String namespace, String message) { } }

Page 99: Implementing cast in android

Sending Messages - MainActivity.java

class HelloWorldChannel implements Cast.MessageReceivedCallback { public String getNamespace() { return getString(R.string.namespace); } @Override public void onMessageReceived(CastDevice castDevice, String namespace, String message) { } }

Our Custom Namespace. This is defined in our reciever app. e.g. urn:x-cast:com.google.cast.sample.helloworld

Page 100: Implementing cast in android

Sending Messages - MainActivity.java

class HelloWorldChannel implements Cast.MessageReceivedCallback { public String getNamespace() { return getString(R.string.namespace); } @Override public void onMessageReceived(CastDevice castDevice, String namespace, String message) { } } This gets Triggered when the Reciever Sends Data

To our Client. e.g. Updated Scores on Games

Page 101: Implementing cast in android

Sending Messages - MainActivity.java

// Launch the receiver app Cast.CastApi.launchApplication(mApiClient, getString(R.string.app_id), false) …. // Create the custom message // channel mHelloWorldChannel = new HelloWorldChannel(); try { Cast.CastApi.setMessageReceivedCallbacks( mApiClient, mHelloWorldChannel.getNamespace(), mHelloWorldChannel); } catch (IOException e) { Log.e(TAG, "Exception while creating channel", e); }

Page 102: Implementing cast in android

Sending Messages - MainActivity.java

// Launch the receiver app Cast.CastApi.launchApplication(mApiClient, getString(R.string.app_id), false) …. // Create the custom message // channel mHelloWorldChannel = new HelloWorldChannel(); try { Cast.CastApi.setMessageReceivedCallbacks( mApiClient, mHelloWorldChannel.getNamespace(), mHelloWorldChannel); } catch (IOException e) { Log.e(TAG, "Exception while creating channel", e); }

Page 103: Implementing cast in android

Sending Messages - MainActivity.java

// Launch the receiver app Cast.CastApi.launchApplication(mApiClient, getString(R.string.app_id), false) …. // Create the custom message // channel mHelloWorldChannel = new HelloWorldChannel(); try { Cast.CastApi.setMessageReceivedCallbacks( mApiClient, mHelloWorldChannel.getNamespace(), mHelloWorldChannel); } catch (IOException e) { Log.e(TAG, "Exception while creating channel", e); }

Page 104: Implementing cast in android

Sending Messages - MainActivity.java

// Launch the receiver app Cast.CastApi.launchApplication(mApiClient, getString(R.string.app_id), false) …. // Create the custom message // channel mHelloWorldChannel = new HelloWorldChannel(); try { Cast.CastApi.setMessageReceivedCallbacks( mApiClient, mHelloWorldChannel.getNamespace(), mHelloWorldChannel); } catch (IOException e) { Log.e(TAG, "Exception while creating channel", e); }

Page 105: Implementing cast in android

Sending Messages - MainActivity.java

private void sendMessage(String message) { if (mApiClient != null && mHelloWorldChannel != null) { try { Cast.CastApi.sendMessage(mApiClient, mHelloWorldChannel.getNamespace(), message).setResultCallback( new ResultCallback<Status>() { @Override public void onResult(Status result) { if (!result.isSuccess()) { Log.e(TAG, "Sending message failed"); } } }); } catch (Exception e) { Log.e(TAG, "Exception while sending message", e); } }

Page 106: Implementing cast in android

Sending Messages - MainActivity.java

private void sendMessage(String message) { if (mApiClient != null && mHelloWorldChannel != null) { try { Cast.CastApi.sendMessage(mApiClient, mHelloWorldChannel.getNamespace(), message).setResultCallback( new ResultCallback<Status>() { @Override public void onResult(Status result) { if (!result.isSuccess()) { Log.e(TAG, "Sending message failed"); } } }); } catch (Exception e) { Log.e(TAG, "Exception while sending message", e); } }

Page 107: Implementing cast in android

Sending Messages - MainActivity.java

private void sendMessage(String message) { if (mApiClient != null && mHelloWorldChannel != null) { try { Cast.CastApi.sendMessage(mApiClient, mHelloWorldChannel.getNamespace(), message).setResultCallback( new ResultCallback<Status>() { @Override public void onResult(Status result) { if (!result.isSuccess()) { Log.e(TAG, "Sending message failed"); } } }); } catch (Exception e) { Log.e(TAG, "Exception while sending message", e); } }

Page 108: Implementing cast in android

Sending Messages - MainActivity.java

private void sendMessage(String message) { if (mApiClient != null && mHelloWorldChannel != null) { try { Cast.CastApi.sendMessage(mApiClient, mHelloWorldChannel.getNamespace(), message).setResultCallback( new ResultCallback<Status>() { @Override public void onResult(Status result) { if (!result.isSuccess()) { Log.e(TAG, "Sending message failed"); } } }); } catch (Exception e) { Log.e(TAG, "Exception while sending message", e); } }

Page 109: Implementing cast in android

Sending Messages - MainActivity.java

mSendButton = (Button) findViewById(R.id.button_send); mSendButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { sendMessage(mTextInput.getText().toString()); } });

Page 110: Implementing cast in android

Sending Messages - MainActivity.java

mSendButton = (Button) findViewById(R.id.button_send); mSendButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { sendMessage(mTextInput.getText().toString()); } });

Page 111: Implementing cast in android

Demo

Page 112: Implementing cast in android

Wrap up

Page 113: Implementing cast in android

Wrap up

●  Initialize via MediaRouter ●  Select Device via MediaRouteSelector ●  Connect via GoogleApiClient ●  Setup Message Bus ●  Send Messages via CastApi through ApiClient

Page 114: Implementing cast in android

Using the CastCompanionLibrary for Media Streaming

Page 115: Implementing cast in android

Getting Started

●  Checkout CastCompanionLibrary from Github ○  https://github.com/googlecast/CastCompanionLibrary-android

●  Compile AAR file

○  ./gradlew build

●  copy compiled AAR to Project ○  rename to CastCompanionLibrary-2.6.aar ○  add repository flat dir to build.gradle ○  compile 'com.google.sample.castcompanionlibrary:CastCompanionLibrary:2.6@aar'

Page 116: Implementing cast in android

Cast Companion - build.gradle

repositories { flatDir { dirs 'libs' } } dependencies { ... compile 'com.android.support:mediarouter-v7:23.1.0' compile 'com.google.android.gms:play-services-cast:8.3.0' companionCompile 'com.google.sample.castcompanionlibrary:CastCompanionLibrary:2.6@aar' }

Page 117: Implementing cast in android

Cast Companion - AndroidManifest.xml

<activity android:name="com.google.android.libraries.cast.companionlibrary.cast.player.VideoCastControllerActivity" android:theme="@style/AppTheme.NoActionBar" />

Page 118: Implementing cast in android

Cast Companion - MainActivity.java

private VideoCastManager mCastManager; private VideoCastConsumer mCastConsumer = new VideoCastConsumerImpl() {};

Page 119: Implementing cast in android

Cast Companion - MainActivity.java

@Override protected void onResume() { Log.d(TAG, "onResume() was called"); mCastManager = VideoCastManager.getInstance(); mCastManager.addVideoCastConsumer(mCastConsumer); mCastManager.incrementUiCounter(); super.onResume(); }

Page 120: Implementing cast in android

Cast Companion - MainActivity.java

private void initCast() { // initialize VideoCastManager VideoCastManager. initialize(this, getString(R.string.app_id), VideoCastControllerActivity.class, null). setVolumeStep(VOLUME_INCREMENT). enableFeatures(VideoCastManager.FEATURE_NOTIFICATION | VideoCastManager.FEATURE_LOCKSCREEN | VideoCastManager.FEATURE_WIFI_RECONNECT | VideoCastManager.FEATURE_AUTO_RECONNECT | VideoCastManager.FEATURE_CAPTIONS_PREFERENCE | VideoCastManager.FEATURE_DEBUGGING); }

Page 121: Implementing cast in android

Cast Companion - MainActivity.java

private void initCast() { // initialize VideoCastManager VideoCastManager. initialize(this, getString(R.string.app_id), VideoCastControllerActivity.class, null). setVolumeStep(VOLUME_INCREMENT). enableFeatures(VideoCastManager.FEATURE_NOTIFICATION | VideoCastManager.FEATURE_LOCKSCREEN | VideoCastManager.FEATURE_WIFI_RECONNECT | VideoCastManager.FEATURE_AUTO_RECONNECT | VideoCastManager.FEATURE_CAPTIONS_PREFERENCE | VideoCastManager.FEATURE_DEBUGGING); }

The Cast Controller Activity. Provided By Cast Companion Library

Page 122: Implementing cast in android

Cast Companion - MainActivity.java

private void initCast() { // initialize VideoCastManager VideoCastManager. initialize(this, getString(R.string.app_id), VideoCastControllerActivity.class, null). setVolumeStep(VOLUME_INCREMENT). enableFeatures(VideoCastManager.FEATURE_NOTIFICATION | VideoCastManager.FEATURE_LOCKSCREEN | VideoCastManager.FEATURE_WIFI_RECONNECT | VideoCastManager.FEATURE_AUTO_RECONNECT | VideoCastManager.FEATURE_CAPTIONS_PREFERENCE | VideoCastManager.FEATURE_DEBUGGING); }

Custom Namespace Like Message Channel from Previous Example

Page 123: Implementing cast in android

Cast Companion - MainActivity.java

private void initCast() { // initialize VideoCastManager VideoCastManager. initialize(this, getString(R.string.app_id), VideoCastControllerActivity.class, null). setVolumeStep(VOLUME_INCREMENT). enableFeatures(VideoCastManager.FEATURE_NOTIFICATION | VideoCastManager.FEATURE_LOCKSCREEN | VideoCastManager.FEATURE_WIFI_RECONNECT | VideoCastManager.FEATURE_AUTO_RECONNECT | VideoCastManager.FEATURE_CAPTIONS_PREFERENCE | VideoCastManager.FEATURE_DEBUGGING); }

Page 124: Implementing cast in android

Cast Companion - MainActivity.java

@Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); mCastManager.addMediaRouterButton(menu, R.id.media_route_menu_item); return true; }

Page 125: Implementing cast in android

Cast Companion - MainActivity.java

@Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); mCastManager.addMediaRouterButton(menu, R.id.media_route_menu_item); return true; }

Page 126: Implementing cast in android

Cast Companion - MainActivity.java

private void loadRemoteMedia(int position, MediaInfo media, boolean autoPlay) { mCastManager.startVideoCastControllerActivity(this, media, position, autoPlay); }

Page 127: Implementing cast in android

Cast Companion - MainActivity.java

mCastButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { MediaMetadata metadata = new MediaMetadata(); MediaInfo media = new MediaInfo .Builder(mTextVideoUrl.getText().toString()) .setContentType("video/mp4") .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) .setMetadata(metadata) .setStreamDuration(596) .build(); loadRemoteMedia(0, media, true); } });

Page 128: Implementing cast in android

Cast Companion - MainActivity.java

mCastButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { MediaMetadata metadata = new MediaMetadata(); MediaInfo media = new MediaInfo .Builder(mTextVideoUrl.getText().toString()) .setContentType("video/mp4") .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) .setMetadata(metadata) .setStreamDuration(596) .build(); loadRemoteMedia(0, media, true); } });

The Url to our Video e.g. .mp4 file

Page 129: Implementing cast in android

Cast Companion - MainActivity.java

mCastButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { MediaMetadata metadata = new MediaMetadata(); MediaInfo media = new MediaInfo .Builder(mTextVideoUrl.getText().toString()) .setContentType("video/mp4") .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) .setMetadata(metadata) .setStreamDuration(596) .build(); loadRemoteMedia(0, media, true); } });

Required. Contains Metadata like Studio, Production Year, etc.

Page 130: Implementing cast in android

Cast Companion - MainActivity.java

mCastButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { MediaMetadata metadata = new MediaMetadata(); MediaInfo media = new MediaInfo .Builder(mTextVideoUrl.getText().toString()) .setContentType("video/mp4") .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) .setMetadata(metadata) .setStreamDuration(596) .build(); loadRemoteMedia(0, media, true); } });