The following procedure enables you to convert your Android sender app from Cast
SDK v2 to CAF Sender, which is based on the
[CastContext](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/CastContext)
singleton.

> [!WARNING]
> **Warning**: If you're building a CAF sender app or migrating to CAF, you should be using CastContext and not GoogleAPIClient for accessing the Cast API. It is proper to use GoogleAPIClient for accessing other Google Play services APIs.

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

- CAF Sender 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.*`)
- CAF Sender provides widgets that comply with the Cast UX requirements; v2 did not provide any UI components and required you to implement these widgets.
- Use of GoogleApiClient is no longer required for using the Cast API.
- Closed captioning in CAF Sender is similar to v2.

## Dependencies

V2 and CAF have the same dependencies on the support libraries and Google Play
services (9.2.0 or later) as described at the [Support Library Features
Guide](https://developer.android.com/topic/libraries/support-library/features)

The minimum Android SDK version that CAF supports is 9 (Gingerbread).

## Initialization

In CAF, an explicit initialization step is required for the Cast framework. This
involves initializing the
`CastContext`
singleton, using an appropriate
`OptionsProvider`
to specify the Web 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 CAF, 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 support
library](https://developers.google.com/cast/docs/migrate_v2/android_sender#dependencies).

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 CAF, 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 Web Receiver application using
`GoogleApiClient`. Interaction between sender and Web Receiver is now represented
as a "session". The
[`SessionManager`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/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`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/SessionManagerListener)
with the `SessionManager`. The `SessionManagerListener` callbacks define
callback methods for all session lifecycle events.

The
[`CastSession`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/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`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/Cast.Listener)
callbacks provided notifications of changes to the device state, including
volume, mute state, standby status, and so forth.

In CAF, volume/mute state change notifications are still delivered via callback
methods in the `Cast.Listener`; these listeners are registered with
[`CastSession`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/CastSession).
All of the remaining device state notifications are delivered via
[`CastStateListener`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/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, CAF 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
Web Receiver application and reconnecting any Cast channels as part of this process.

In addition, CAF also adds automatic session resumption which is enabled by
default (and can be deactivated via
[`CastOptions`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/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`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/SessionManager), which will issue the appropriate callbacks on any registered
`SessionManagerListener` instances.

## Custom channel registration

In v2, custom channels (implemented using
[`Cast.MessageReceivedCallback`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/Cast.MessageReceivedCallback))
are registered with the `Cast.CastApi`. In CAF, custom channels are instead registered with the
`CastSession` instance. The registration can be done in the
[`SessionManagerListener.onSessionStarted`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/SessionManagerListener#onSessionStarted(T,%20java.lang.String))
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`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/RemoteMediaPlayer)
is deprecated and should not be used. In CAF, it is superseded by the new
[`RemoteMediaClient`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/media/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 Web Receiver application being connected to
supports the media namespace.

The `RemoteMediaClient` can be accessed as the
[`getRemoteMediaClient`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/CastSession#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 CAF, all media requests issued on the `RemoteMediaClient` return a
[`RemoteMediaClient.MediaChannelResult`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/media/RemoteMediaClient.MediaChannelResult)
via a
[`PendingResult`](https://developers.google.com/android/reference/com/google/android/gms/common/api/PendingResult.md.txt)
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 Web Receiver via the
`RemoteMediaPlayer.OnStatusUpdatedListener`.

In CAF, the `RemoteMediaClient` provides equivalent callbacks via its
[`RemoteMediaClient.Listener`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/media/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 Web Receiver.

In CAF, the class
[`UIMediaController`](https://developers.google.com/android/reference/com/google/android/gms/cast/framework/media/uicontroller/UIMediaController.md.txt)
takes on most of this responsibility.

## Introductory overlay

V2 does not provide an introductory overlay UI.

CAF provides a custom view
[`IntroductoryOverlay`](https://developers.google.com/android/reference/com/google/android/gms/cast/framework/IntroductoryOverlay.md.txt)
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 CAF, the SDK provides a custom view,
[`MiniControllerFragment`](https://developers.google.com/android/reference/com/google/android/gms/cast/framework/media/widget/MiniControllerFragment.md.txt),
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 CAF, the SDK provides a
[`NotificationsOptions.Builder`](https://www.google.com/url?q=/android/reference/com/google/android/gms/cast/framework/media/NotificationOptions.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`](https://developers.google.com/android/reference/com/google/android/gms/cast/framework/CastOptions.md.txt)
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.

CAF provides a
[`UIMediaController`](https://developers.google.com/android/reference/com/google/android/gms/cast/framework/media/uicontroller/UIMediaController.md.txt)
helper class that makes it easy for you to build your own expanded
controller.

CAF adds a pre-built expanded controller widget
[`ExpandedControllerActivity`](https://developers.google.com/cast/docs/android_sender_integrate#add_an_expanded_controller)
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 CAF, audio focus is managed automatically.

## Debug logging

In CAF there are no logging options.

## Sample apps

We have
[codelab tutorials](https://codelabs.developers.google.com/codelabs/cast-videos-android/)
and
[sample apps](https://github.com/googlecast/CastVideos-android)
that use CAF.

> [!WARNING]
> **Warning:** If you have migrated your app to CAF and it is still using GoogleAPIClient to access the Cast API, you need to remove GoogleAPIClient and follow the [Initialization](https://developers.google.com/cast/docs/migrate_v2/android_sender.md.txt#initialization) procedure to use CastContext.