Migrate Android Sender App from Cast SDK v2 to v3

The following procedure enables you to convert your Android sender app from Cast SDK v2 to Cast SDK v3, which is based on the CastContext singleton.

The Cast CAF Sender SDK uses CastContext to manage the GoogleAPIClient on your behalf. CastContext manages lifecycles, errors and callbacks for you, which greatly simplifies developing a Cast app.

Introduction

  • The Cast Android SDK v3 is still distributed as part of Google Play services using the Android SDK manager
  • New packages have been added that take on responsibility for complying with the Google Cast Design checklist (com.google.android.gms.cast.framework.*)
  • The Cast SDK v3 provides widgets that comply with the Cast UX requirements; v2 did not provide any UI components and required you to implement these widgets.
  • The new design is modeled on the Cast Companion Library.
  • Use of GoogleApiClient is no longer required for using the Cast API.
  • Closed captioning in v3 is similar to v2.

Dependencies

V2 and v3 have the same dependencies on the AppCompat support library, MediaRouter v7 support library and Google Play services (9.2.0 or later).

The minimum Android SDK version that the Cast SDK v3 supports is 9 (Gingerbread).

Initialization

In v3, an explicit initialization step is required for the Cast framework. This involves initializing the CastContext singleton, using an appropriate OptionsProvider to specify the receiver application ID and any other global options.

public class CastOptionsProvider implements OptionsProvider {

    @Override
    public CastOptions getCastOptions(Context context) {
        return new CastOptions.Builder()
                .setReceiverApplicationId(context.getString(R.string.app_id))
                .build();
    }

    @Override
    public List<SessionProvider> getAdditionalSessionProviders(Context context) {
        return null;
    }
}

Declare the OptionsProvider within the "application" tag of the app AndroidManifest.xml file:

<application>
...
    <meta-data
        android:name=
            "com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
        android:value="com.google.sample.cast.refplayer.CastOptionsProvider" />
</application>

Lazily initialize the CastContext in each Activity’s onCreate method:

private CastContext mCastContext;

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.video_browser);
    setupActionBar();

    mCastContext = CastContext.getSharedInstance(this);
}

These steps were not necessary in v2.

Device Discovery

In v3, the discovery process is started and stopped automatically by the framework when the app comes to the foreground and goes to the background, respectively. MediaRouteSelector and MediaRouter.Callback should not be used.

Cast Button and Cast Dialog

As in v2, these components are provided by the MediaRouter v7 support library.

The Cast button is still implemented by the MediaRouteButton and can be added to your activity (using either an ActionBar or a Toolbar), as a menu item in your menu.

<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"/>

Override the onCreateOptionMenu() method of each Activity by using CastButtonFactory to wire up the MediaRouteButton to the Cast framework:

private MenuItem mediaRouteMenuItem;

public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    getMenuInflater().inflate(R.menu.browse, menu);
    mediaRouteMenuItem =
        CastButtonFactory.setUpMediaRouteButton(getApplicationContext(),
                                                menu,
                                                R.id.media_route_menu_item);
    return true;
}

When someone taps the button, the Cast dialog is automatically presented.

Device Control

In v3, device control is largely handled by the framework. The sender application does not need to handle (and should not try to handle) connecting to the device and launching the receiver application using GoogleApiClient. Interaction between sender and receiver is now represented as a "session". The SessionManager class handles the session lifecycle and automatically starts and stops sessions in response to user gestures: a session is started when the user selects a Cast device in the Cast dialog and is ended when the user taps the "Stop Casting" button in the Cast dialog or when the sender app itself terminates. The sender application can be notified of session lifecycle events by registering a SessionManagerListener with the SessionManager. The SessionManagerListener callbacks define callback methods for all session lifecycle events.

The CastSession class represents a session with a Cast device. The class has methods for controlling the device volume and mute states, which was previously done in v2 using methods on Cast.CastApi.

In v2, the Cast.Listener callbacks provided notifications of changes to the device state, including volume, mute state, standby status, and so forth.

In v3, volume/mute state change notifications are still delivered via callback methods in the Cast.Listener; these listeners are registered with CastSession. All of the remaining device state notifications are delivered via CastStateListener callbacks; these listeners are registered with the CastSession. Make sure you still unregister listeners when the associated fragments, activities or apps go to the background.

Reconnection Logic

As with v2, the v3 framework attempts to re-establish network connections that are lost due to temporary WiFi signal loss or other network errors. This is now done at the session level; a session can enter a "suspended" state when the connection is lost, and will transition back to a "connected" state when connectivity is restored. The framework takes care of reconnecting to the receiver application and reconnecting any Cast channels as part of this process.

In addition, v3 also adds automatic session resumption which is enabled by default (and can be deactivated via CastOptions). If the sender application is sent to the background or is terminated (by swiping-away or because of a crash) while a Cast session is in progress, the framework will attempt to resume that session when the sender application returns to the foreground or is relaunched; this is handled automatically by the SessionManager, which will issue the appropriate callbacks on any registered SessionManagerListener instances.

Custom Channel Registration

In v2, custom channels (implemented using Cast.MessageReceivedCallback) are registered with the Cast.CastApi. In v3, custom channels are instead registered with the CastSession instance. The registration can be done in the SessionManagerListener.onSessionStarted callback method. For media applications, it is no longer necessary to explicitly register the media control channel via Cast.CastApi.setMessageReceivedCallbacks; see the following section for more details.

Media Control

The v2 class RemoteMediaPlayer is deprecated and should not be used. In v3, it is superseded by the new RemoteMediaClient class, which provides equivalent functionality in a more convenient API. It is not necessary to explicitly initialize or register this object; the framework will automatically instantiate the object and register the underlying media channel at session start time if the receiver application being connected to supports the media namespace.

The RemoteMediaClient can be accessed as the getRemoteMediaClient method of the CastSession object.

In v2, all media requests issued on the RemoteMediaPlayer would return a RemoteMediaPlayer.MediaChannelResult via a PendingResult callback.

In v3, all media requests issued on the RemoteMediaClient return a RemoteMediaClient.MediaChannelResult via a PendingResult callback which can be used to track the progress and eventual outcome of the request.

The v2 RemoteMediaPlayer would send notifications about changes in the media player state on the receiver via the RemoteMediaPlayer.OnStatusUpdatedListener.

In v3, the RemoteMediaClient provides equivalent callbacks via its RemoteMediaClient.Listener interface. Any number of listeners can be registered with the RemoteMediaClient, which allows multiple sender components to share the single instance of RemoteMediaClient that is associated with the session.

In v2, the sender application had to take on the burden of keeping the user interface in sync with the media player state on the receiver.

In v3, the class UIMediaController takes on most of this responsibility.

Introductory Overlay

V2 does not provide an introductory overlay UI.

V3 provides a custom view IntroductoryOverlay to highlight the Cast button when it is first shown to users.

Mini Controller

In v2, you need to implement a mini controller from scratch in the sender app.

In v3, the SDK provides a custom view, MiniControllerFragment, which you can add to the app layout file of the activities in which you want to show the mini controller.

Notification and Lock Screen

In v2, controllers for notification and lock screen are not provided by the SDK. For that SDK, you need to build these features into your sender app using the Android framework APIs.

In v3, the SDK provides a NotificationsOptions.Builder to help you build media controls for the notification and lock screen into the sender app. The notification and lock screen controls can be enabled with the CastOptions when initializing the CastContext.

public CastOptions getCastOptions(Context context) {
    NotificationOptions notificationOptions = new NotificationOptions.Builder()
            .setTargetActivityClassName(VideoBrowserActivity.class.getName())
            .build();
    CastMediaOptions mediaOptions = new CastMediaOptions.Builder()
            .setNotificationOptions(notificationOptions)
            .build();

    return new CastOptions.Builder()
            .setReceiverApplicationId(context.getString(R.string.app_id))
            .setCastMediaOptions(mediaOptions)
            .build();
}

Expanded Controller

In v2, you need to implement an expanded controller from scratch in the sender app.

V3.0 provides a UIMediaController helper class that makes it easy for you to build your own expanded controller.

V3.1 adds a pre-built expanded controller widget ExpandedControllerActivity which you can simply add to your app. You no longer need to implement a custom expanded controller using UIMediaController.

Audio Focus

In v2, you need to use MediaSessionCompat to manage audio focus.

In v3, audio focus is managed automatically.

Debug Logging

In v3 there are no logging options.

Sample Apps

We have codelab tutorials and sample apps that use Cast SDK v3.