Customize Android Sender UI

You can customize Cast 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.

 < 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:

 < 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 :

 < 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 should be used if the support library version is newer than 26.0.0. For older support library versions, please use buttonTint instead.

Customize Introductory Overlay Theme

The 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:

 < 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 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:

 < 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.

 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 :

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:

 < 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 in the castControlButtons attribute of the MiniControllerFragment .

  2. Implement a subclass of 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 as one of the parameters and update its state as needed.

  3. Subclass MiniControllerFragment , then override onCreateView and call getButtonImageViewAt(int) to get the ImageView for that custom button. Then call bindViewToUIController(View, UIController) to associate the view with your custom UIController .

  4. See MediaIntentReceiver at 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 called MyCustomUIController :

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

 < 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 .

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:

  // 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 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 in the castControlButtons attribute of the ExpandedControllerActivity . You can then use getButtonImageViewAt(int) to obtain the ImageView for that custom button.

  2. Implement a subclass of UIController . 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 and call getButtonImageViewAt(int) to get the view object of the button. Then call bindViewToUIController(View, UIController) to associate the view with your custom UIController .

  4. See MediaIntentReceiver at 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 called MyCustomUIController :

  // 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
 // 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
 // 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 
 ); 
  
 ... 
  
 } 
 } 
Create a Mobile Website
View Site in Mobile | Classic
Share by: