You can customize [Cast widgets](https://developers.google.com/cast/docs/android_sender/integrate.md.txt#the_cast_ux_widgets)
by setting the colors, styling the buttons, text, and thumbnail
appearance, and by choosing the types of buttons to display.

## Customize app theme

This example creates a custom theme style `Theme.CastVideosTheme` which
can define custom colors, an introductory overlay style, a mini controller
style, and an expanded controller style.

```java
<style name="Theme.CastVideosTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Set AppCompat's color theming attrs -->
    <item name="colorPrimary">@color/primary</item>
    <item name="colorPrimaryDark">@color/primary_dark</item>
    <item name="colorAccent">@color/accent</item>
    <item name="android:textColorPrimary">@color/primary_text</item>
    <item name="android:textColorSecondary">@color/secondary_text</item>
    <item name="castIntroOverlayStyle">@style/CustomCastIntroOverlay</item>
    <item name="castMiniControllerStyle">@style/CustomCastMiniController</item>
    <item name="castExpandedControllerStyle">@style/CustomCastExpandedController</item>
</style>
```

The last three lines above enable you to define styles specific to
introductory overlay, mini controller, and expanded controller
as part of this theme. Examples are included in those sections that follow.

## Customize Cast Button

To add a custom `mediaRouteTheme` to your app's Theme:

```java
<style name="Theme.CastVideosTheme" parent="Theme.AppCompat.Light.NoActionBar">
  <!-- ... -->
  <item name="mediaRouteTheme">@style/CustomMediaRouterTheme</item>
</style>
```

Declare your custom Media Router theme and declare a custom
`mediaRouteButtonStyle`:

```java
<style name="CustomMediaRouterTheme" parent="Theme.MediaRouter">
  <item name="mediaRouteButtonStyle">@style/CustomMediaRouteButtonStyle</item>
</style>

<style name="CustomMediaRouteButtonStyle" parent="Widget.MediaRouter.Light.MediaRouteButton">
  <item name="mediaRouteButtonTint">#EEFF41</item>
</style>
```

[`setTint`](https://developer.android.com/reference/android/support/v7/mediarouter/R.attr.html#mediaRouteButtonTint)
should be used if the support library version is newer than 26.0.0. For older
support library versions, please use [`buttonTint`](https://developer.android.com/reference/android/R.attr.html#buttonTint)
instead.

## Customize Introductory Overlay Theme

The
[`IntroductoryOverlay`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/IntroductoryOverlay)
class supports various style attributes that your app can override in a custom
theme. This example shows how to override the text appearance of both the button
and title over the overlay widget:

```java
<style name="CustomCastIntroOverlay" parent="CastIntroOverlay">
    <item name="castButtonTextAppearance">@style/TextAppearance.CustomCastIntroOverlay.Button</item>
    <item name="castTitleTextAppearance">@style/TextAppearance.CustomCastIntroOverlay.Title</item>
</style>
<style name="TextAppearance.CustomCastIntroOverlay.Button" parent="android:style/TextAppearance">
    <item name="android:textColor">#FFFFFF</item>
</style>
<style name="TextAppearance.CustomCastIntroOverlay.Title"parent="android:style/TextAppearance.Large">
    <item name="android:textColor">#FFFFFF</item>
</style>
```

## Customize mini controller

### Customize theme

The
[`MiniControllerFragment`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/media/widget/MiniControllerFragment)
class supports various style attributes that your app can override in a custom
theme. This example shows how to enable the display of the thumbnail image, to
override the text appearance of both the subhead and closed caption, set
the colors, and customize the buttons:

```java
<style name="CustomCastMiniController" parent="CastMiniController">
    <item name="castShowImageThumbnail">true</item>
    <item name="castTitleTextAppearance">@style/TextAppearance.AppCompat.Subhead</item>
    <item name="castSubtitleTextAppearance">@style/TextAppearance.AppCompat.Caption</item>
    <item name="castBackground">#FFFFFF</item>
    <item name="castProgressBarColor">#FFFFFF</item>
    <item name="castPlayButtonDrawable">@drawable/cast_ic_mini_controller_play</item>
    <item name="castPauseButtonDrawable">@drawable/cast_ic_mini_controller_pause</item>
    <item name="castStopButtonDrawable">@drawable/cast_ic_mini_controller_stop</item>
    <item name="castLargePlayButtonDrawable">@drawable/cast_ic_mini_controller_play_large</item>
    <item name="castLargePauseButtonDrawable">@drawable/cast_ic_mini_controller_pause_large</item>
    <item name="castLargeStopButtonDrawable">@drawable/cast_ic_mini_controller_stop_large</item>
    <item name="castSkipPreviousButtonDrawable">@drawable/cast_ic_mini_controller_skip_prev</item>
    <item name="castSkipNextButtonDrawable">@drawable/cast_ic_mini_controller_skip_next</item>
    <item name="castRewind30ButtonDrawable">@drawable/cast_ic_mini_controller_rewind30</item>
    <item name="castForward30ButtonDrawable">@drawable/cast_ic_mini_controller_forward30</item>
    <item name="castMuteToggleButtonDrawable">@drawable/cast_ic_mini_controller_mute</item>
    <item name="castClosedCaptionsButtonDrawable">@drawable/cast_ic_mini_controller_closed_caption</item
</style>
```

### Choose buttons

A `MiniControllerFragment` has three slots that can display the album art
and two buttons, or three control buttons if the album art is not populated.

> [!NOTE]
> **Note:** If `app:castShowImageThumbnail="false"`, the album art will be hidden and slots 1, 2, and 3 will be available for control buttons. Otherwise, since the album art will be shown in slot 1, you can provide an empty button for slot 1 and control buttons for slots 2 and 3.

    SLOT  SLOT  SLOT
      1     2     3

By default the fragment shows a play/pause toggle button. Developers can use
the attribute `castControlButtons` to override which buttons to show.
The supported control buttons are defined as
[ID resources](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/media/widget/ControlButtonsContainer#getButtonTypeAt(int)):

| Button Type | Description |
|---|---|
| `@id/cast_button_type_empty` | Do not place a button in this slot |
| `@id/cast_button_type_custom` | Custom button |
| `@id/cast_button_type_play_pause_toggle` | Toggles between playback and pause |
| `@id/cast_button_type_skip_previous` | Skips to the previous item in the queue |
| `@id/cast_button_type_skip_next` | Skips to the next item in the queue |
| `@id/cast_button_type_rewind_30_seconds` | Rewinds the playback by 30 seconds |
| `@id/cast_button_type_forward_30_seconds` | Skips forward the playback by 30 seconds |
| `@id/cast_button_type_mute_toggle` | Mutes and unmutes the receiver |
| `@id/cast_button_type_closed_caption` | Opens a dialog to select text and audio tracks |

Here is an example that would use the album art, a play/pause toggle button,
and a skip forward button in that order from left to right:

```java
<array name="cast_mini_controller_control_buttons">
    <item>@id/cast_button_type_empty</item>
    <item>@id/cast_button_type_play_pause_toggle</item>
    <item>@id/cast_button_type_forward_30_seconds</item>
</array>
...
<fragment
    android:id="@+id/cast_mini_controller"
    ...
    app:castControlButtons="@array/cast_mini_controller_control_buttons"
    class="com.google.android.gms.cast.framework.media.widget.MiniControllerFragment">
```

**Warning** : This array must contain exactly three items, otherwise a runtime
exception will be thrown. If you don't want to show a button in a slot, use
`@id/cast_button_type_empty`.

### Add custom buttons

A `MiniControllerFragment` supports adding custom control buttons which are
not provided by the SDK, such as a "thumb's up" button. The steps are:

1. Specify a slot to contain a custom button using
   [`@id/cast_button_type_custom`](https://developers.google.com/android/reference/com/google/android/gms/cast/framework/media/widget/MiniControllerFragment.md.txt#configurable-control-buttons)
   in the `castControlButtons` attribute of the `MiniControllerFragment`.

2. Implement a subclass of
   [`UIController`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/media/uicontroller/UIController).
   The `UIController` contains methods that are called by the SDK when the state
   of the cast session or media session changes. Your subclass of `UIController`
   should take an
   [`ImageView`](https://developer.android.com/reference/android/widget/ImageView.html)
   as one of the parameters and update its state as needed.

3. Subclass [`MiniControllerFragment`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/media/widget/MiniControllerFragment),
   then override
   [`onCreateView`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/media/widget/MiniControllerFragment#onCreateView(android.view.LayoutInflater,%20android.view.ViewGroup,%20android.os.Bundle)) and call
   [`getButtonImageViewAt(int)`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/media/widget/MiniControllerFragment#getButtonImageViewAt(int))
   to get the
   [`ImageView`](https://developer.android.com/reference/android/widget/ImageView.html)
   for that custom button. Then call
   [`bindViewToUIController(View, UIController)`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/media/uicontroller/UIMediaController#bindViewToUIController(android.view.View,%20com.google.android.gms.cast.framework.media.uicontroller.UIController))
   to associate the view with your custom
   [`UIController`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/media/uicontroller/UIController).

4. See
   [`MediaIntentReceiver`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/media/MediaIntentReceiver)
   at [Add Custom Actions](https://developers.google.com/cast/docs/android_sender/advanced.md.txt#add_custom_actions) for how to handle the action
   from your custom button.

   Here is an example of associating a button at slot 2 to a
   [`UIController`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/media/uicontroller/UIController)
   called `MyCustomUIController`:

```java
// arrays.xml
<array name="cast_expanded_controller_control_buttons">
    <item>@id/cast_button_type_empty</item>
    <item>@id/cast_button_type_rewind_30_seconds</item>
    <item>@id/cast_button_type_custom</item>
    <item>@id/cast_button_type_empty</item>
</array>
```
Kotlin

```kotlin
// MyCustomUIController.kt
class MyCustomUIController(private val mView: View) : UIController() {
    override fun onMediaStatusUpdated() {
        // Update the state of mView based on the latest the media status.
        ...
        mView.visibility = View.INVISIBLE
        ...
    }
}

// MyMiniControllerFragment.kt
class MyMiniControllerFragment : MiniControllerFragment() {
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        super.onCreateView(inflater, container, savedInstanceState)
        val customButtonView = getButtonImageViewAt(2)
        val myCustomUiController = MyCustomUIController(customButtonView)
        uiMediaController.bindViewToUIController(customButtonView, myCustomUiController)
        ...
    }
}
```
Java

```java
// MyCustomUIController.java
class MyCustomUIController extends UIController {
    private final View mView;

    public MyCustomUIController(View view) {
            mView = view;
    }

    @Override
    public onMediaStatusUpdated() {
        // Update the state of mView based on the latest the media status.
        ...
        mView.setVisibility(View.INVISIBLE);
        ...
    }
}

// MyMiniControllerFragment.java
class MyMiniControllerFragment extends MiniControllerFragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        ImageView customButtonView = getButtonImageViewAt(2);
        MyCustomUIController myCustomUiController = new MyCustomUIController(customButtonView);
        getUIMediaController().bindViewToUIController(customButtonView, myCustomUiController);
        ...
    }
}
```

## Customize expanded controller

### Customize theme

If an expanded controller's Activity uses a dark theme toolbar, you
can set a theme on the toolbar to use light text and a light icon color:

    <style name="Theme.CastVideosTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="castExpandedControllerToolbarStyle">
            @style/ThemeOverlay.AppCompat.Dark.ActionBar
        </item>
    </style>

You can specify your own images that are used to draw the buttons on the
expanded controller:

```java
<style name="CustomCastExpandedController" parent="CastExpandedController">
    <item name="castButtonColor">@null</item>
    <item name="castPlayButtonDrawable">@drawable/cast_ic_expanded_controller_play</item>
    <item name="castPauseButtonDrawable">@drawable/cast_ic_expanded_controller_pause</item>
    <item name="castStopButtonDrawable">@drawable/cast_ic_expanded_controller_stop</item>
    <item name="castSkipPreviousButtonDrawable">@drawable/cast_ic_expanded_controller_skip_previous</item>
    <item name="castSkipNextButtonDrawable">@drawable/cast_ic_expanded_controller_skip_next</item>
    <item name="castRewind30ButtonDrawable">@drawable/cast_ic_expanded_controller_rewind30</item>
    <item name="castForward30ButtonDrawable">@drawable/cast_ic_expanded_controller_forward30</item>
</style>
```

### Choose buttons

The expanded controller's Activity has five slots to show control buttons. The middle
slot always shows a play/pause toggle button and is non-configurable. The other four
slots are configurable, from left to right, by the sender app.

    SLOT  SLOT  PLAY/PAUSE  SLOT  SLOT
      1     2     BUTTON      3     4

By default the Activity shows a closed caption button, a skip to the
previous item button, a skip to the next item button, and a mute toggle
button in these four slots, from left to right. Developers can use the
attribute `castControlButtons` to override which buttons to show in
which slots. The list of supported control buttons are defined as
ID resources identical to the
[button types for mini controller buttons](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/media/widget/ControlButtonsContainer#getButtonTypeAt(int)).

Here is an example that places a rewind button in the second slot, a skip
forward button in the third slot, and leaving the first and last slots empty:

```java
// arrays.xml
<array name="cast_expanded_controller_control_buttons">
    <item>@id/cast_button_type_empty</item>
    <item>@id/cast_button_type_rewind_30_seconds</item>
    <item>@id/cast_button_type_forward_30_seconds</item>
    <item>@id/cast_button_type_empty</item>
</array>
...
// styles.xml
<style name="Theme.MyTheme">
    <item name="castExpandedControllerStyle">
        @style/CustomCastExpandedController
    </item>
</style>
...
<style name="CustomCastExpandedController" parent="CastExpandedController">
    <item name="castControlButtons">
        @array/cast_expanded_controller_control_buttons
    </item>
</style>
```

The array must contain exactly four items, otherwise a runtime exception will
be thrown. If you don't want to show a button in a slot, use
`@id/cast_button_type_empty`. `CastContext` can manage the lifecycle and
presentation of this activity.

### Add custom buttons

An [`ExpandedControllerActivity`](https://developers.google.com/android/reference/com/google/android/gms/cast/framework/media/widget/ExpandedControllerActivity.md.txt) supports adding custom control buttons which are not provided by the SDK,
such as a "thumb's up" button. The steps are:

1. Specify a slot to contain a custom button using
   [`@id/cast_button_type_custom`](https://developers.google.com/cast/docs/android_sender/customize_ui.md.txt#choose-buttons-mini-controller)
   in the `castControlButtons` attribute of the `ExpandedControllerActivity`.
   You can then use
   [`getButtonImageViewAt(int)`](https://developers.google.com/android/reference/com/google/android/gms/cast/framework/media/widget/ExpandedControllerActivity.md.txt#getButtonImageViewAt(int))
   to obtain the
   [`ImageView`](https://developer.android.com/reference/android/widget/ImageView.html)
   for that custom button.

2. Implement a subclass of
   [`UIController`](https://developers.google.com/android/reference/com/google/android/gms/cast/framework/media/uicontroller/UIController.md.txt).
   `UIController` contains methods that are called by the SDK when the state
   of the cast session or media session changes. Your subclass of
   `UIController` should take an `ImageView` as one of the parameters,
   and update its state as needed.

3. Subclass ExpandedControllerActivity, then override
   [`onCreate`](https://developers.google.com/android/reference/com/google/android/gms/cast/framework/media/widget/ExpandedControllerActivity.md.txt#onCreate(android.os.Bundle))
   and call
   [`getButtonImageViewAt(int)`](https://developers.google.com/android/reference/com/google/android/gms/cast/framework/media/widget/ExpandedControllerActivity.md.txt#getButtonImageViewAt(int))
   to get the view object of the button. Then call
   [`bindViewToUIController(View, UIController)`](https://developers.google.com/android/reference/com/google/android/gms/cast/framework/media/uicontroller/UIMediaController.md.txt#bindViewToUIController(android.view.View,%20com.google.android.gms.cast.framework.media.uicontroller.UIController))
   to associate the view with your custom `UIController`.

4. See
   [`MediaIntentReceiver`](https://developers.google.com/android/reference/com/google/android/gms/cast/framework/media/MediaIntentReceiver.md.txt)
   at [Add Custom Actions](https://developers.google.com/cast/docs/android_sender/advanced.md.txt#add_custom_actions)
   for how to handle the action from your custom button.

Here is an example of associating a button at slot 2 to a
[`UIController`](https://developers.google.com/android/reference/com/google/android/gms/cast/framework/media/uicontroller/UIController.md.txt) called `MyCustomUIController`:

```java
// arrays.xml
<array name="cast_expanded_controller_control_buttons">
    <item>@id/cast_button_type_empty</item>
    <item>@id/cast_button_type_rewind_30_seconds</item>
    <item>@id/cast_button_type_custom</item>
    <item>@id/cast_button_type_empty</item>
</array>
```
Kotlin

```kotlin
// MyCustomUIController.kt
class MyCustomUIController(private val mView: View) : UIController() {
    override fun onMediaStatusUpdated() {
        // Update the state of mView based on the latest the media status.
        ...
        mView.visibility = View.INVISIBLE
        ...
    }
}

// MyExpandedControllerActivity.kt
internal class MyExpandedControllerActivity : ExpandedControllerActivity() {
    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val customButtonView = getButtonImageViewAt(2)
        val myCustomUiController = MyCustomUIController(customButtonView)
        uiMediaController.bindViewToUIController(customButtonView, myCustomUiController)
        ...
    }
}
```
Java

```java
// MyCustomUIController.java
class MyCustomUIController extends UIController {
    private final View mView;

    public MyCustomUIController(View view) {
        mView = view;
    }

    @Override
    public onMediaStatusUpdated() {
        // Update the state of mView based on the latest the media status.
        ...
        mView.setVisibility(View.INVISIBLE);
        ...
    }
}

// MyExpandedControllerActivity.java
class MyExpandedControllerActivity extends ExpandedControllerActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ImageView customButtonView = getButtonImageViewAt(2);
        MyCustomUIController myCustomUiController = new MyCustomUIController(customButtonView);
        getUIMediaController().bindViewToUIController(customButtonView, myCustomUiController);
        ...
    }
}
```