Add custom actions
A sender app can extend
MediaIntentReceiver
to handle custom actions or override its behavior. If you have implemented your
own MediaIntentReceiver
, you need to add it to the manifest, and also set its
name in the CastMediaOptions
. This example provides custom actions that
override toggle remote media playback, pressing the media button and other types
of actions.
// In AndroidManifest.xml
<receiver android:name="com.example.MyMediaIntentReceiver" />
// In your OptionsProvider
CastMediaOptions mediaOptions = new CastMediaOptions.Builder()
.setMediaIntentReceiverClassName(MyMediaIntentReceiver.class.getName())
.build();
// Implementation of MyMediaIntentReceiver
class MyMediaIntentReceiver extends MediaIntentReceiver {
@Override
protected void onReceiveActionTogglePlayback(Session currentSession) {
}
@Override
protected void onReceiveActionMediaButton(Session currentSession,
KeyEvent keyEvent) {
}
@Override
protected void onReceiveOtherAction(String action, Intent intent) {
}
}
Add a custom channel
For the sender app to communicate with the receiver app, your app needs to
create a custom channel. The sender can use the custom channel to send string
messages to the receiver. Each custom channel is defined by a unique
namespace and must start with the prefix urn:x-cast:
, for example,
urn:x-cast:com.example.custom
. It is possible to have multiple custom
channels, each with a unique namespace. The receiver app can also
send and receive messages
using the same namespace.
The custom channel is implemented with the
Cast.MessageReceivedCallback
interface:
class HelloWorldChannel implements Cast.MessageReceivedCallback {
public String getNamespace() {
return "urn:x-cast:com.example.custom";
}
@Override
public void onMessageReceived(CastDevice castDevice, String namespace,
String message) {
Log.d(TAG, "onMessageReceived: " + message);
}
}
Once the sender app is connected to the receiver app, the custom channel can
be created using the
setMessageReceivedCallbacks
method:
try {
myCastSession.setMessageReceivedCallbacks(
mHelloWorldChannel.getNamespace(),
mHelloWorldChannel);
} catch (IOException e) {
Log.e(TAG, "Exception while creating channel", e);
}
Once the custom channel is created, the sender can use the
sendMessage
method to send string messages to the receiver over that channel:
private void sendMessage(String message) {
if (mHelloWorldChannel != null) {
try {
myCastSession.sendMessage(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);
}
}
}
Supporting autoplay
See the section Autoplay & Queueing APIs.
Override image selection for UX widgets
Various components of the framework (namely the Cast dialog, the mini
controller, and the UIMediaController, if so configured) will display artwork
for the currently casting media. The URLs to the image artwork are typically
included in the MediaMetadata
for the media, but the sender app may have an
alternate source for the URLs.
The
ImagePicker
class defines a means for selecting an appropriate image from the list of images
in a MediaMetadata
, based on the use of the image, for example, notification
thumbnail or full screen background. The default ImagePicker
implementation
always chooses the first image, or returns null if no image is available in the
MediaMetadata
. Your app can subclass ImagePicker
and override the
onPickImage(MediaMetadata, ImageHints)
method to provide an alternate implementation, and then select that subclass
with the
setImagePicker
method of CastMediaOptions.Builder
.
ImageHints
provides hints to an ImagePicker
about the type and size of an image to be
selected for display in the UI.
Customizing Cast dialogs
SessionManager
is the central place for managing session lifecycle. SessionManager
listens
to Android
MediaRouter
route selection state changes to start, resume and end sessions. When a route is
selected, SessionManager
will create a
Session
object and tries to start or resume it. When a route is unselected,
SessionManager
will end the current session.
Therefore, to ensure SessionManager
manages session lifecycles properly, you
must make sure that:
- In the route selector dialog,
call
MediaRouter.selectRoute(MediaRouter.RouteInfo)
when a user selects a device. - In the route controller dialog (either in connected
state or
casting
state),
call
MediaRouter.unselect(int)
when the user stops casting.
Depending on how you create the Cast dialogs, additional actions may need to be done:
- If you create Cast dialogs using
MediaRouteChooserDialog
andMediaRouteControllerDialog
, then these dialogs will update route selection inMediaRouter
automatically, so nothing needs to be done. - If you set up your Cast button using
CastButtonFactory.setUpMediaRouteButton(Context, Menu, int)
orCastButtonFactory.setUpMediaRouteButton(Context, MediaRouteButton)
, then the dialogs are actually created usingMediaRouteChooserDialog
andMediaRouteControllerDialog
, so nothing needs to be done, too. - For other cases, you will be creating custom Cast dialogs, so you need to
follow the above instructions to update the route selection state in
MediaRouter
.
Next steps
This concludes the features that you can add to your Android Sender app. You can now build a sender app for another platform (iOS or Chrome), or build a Web Receiver app.