Extending your Android app display

Document created by SergioSolis Employee on Mar 23, 2015Last modified by SergioSolis Employee on Mar 31, 2015
Version 1Show Document
  • View in full screen mode

One of the features that many users have asked about but still is a work in progress for android, is the extended desktop capabilities. Currently android allows you to mirror your desktop in two displays, but you are still unable to extend your desktop like you would with any other OS like Linux or Windows.

This tutorial is intended to show you how to use a special object that allows you to control what should appear on a secondary or external display, replacing the screen mirroring.

 

So how do we do this?


A presentation is a container to display a user interface, in the form of a view hierarchy on an external display. This is pretty much like a Dialog since it displays its UI separated from its activity, but the difference is that the presentation shows in an external display while the dialog displays it in the primary screen. Now, because of this, the resources that are to be used by the UI on an external display are different then the resources used in the primary screen, the context of the presentation is NOT the activity.

 

How do we choose where to send this presentation?

 

The easiest way to do this is to use the MediaRouter API. What the mediarouter does is it keeps track of which audio and video routes are available on the system. The MediaRouter sends notifications whenever routes are selected or unselected. An application can simple watch for these notifications and show or dismiss a presentation on the preferred presentation display automatically.

 

The preferred presentation display is the display that the mediarouter recommends that the application should use if it wants to show content on the secondary display. IF there is not a preferred presentation display, the application should show its content locally without using a presentation.

 

Using the Mediarouter

 

The MediaRouter is a system service obtained by calling getSystemService() and asking for the MEDIA_ROUTER_SERVICE.

 

We should use the mediarouter to create and show a presentation on the preferred presentation display:

 

 

 


MediaRouter mediaRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
MediaRouter.RouteInfo route = mediaRouter.getSelectedRoute();
if (route != null) {
Display presentationDisplay = route.getPresentationDisplay();
if (presentationDisplay != null) {
Presentation presentation = new MyPresentation(context, presentationDisplay);
presentation
.show();
}
}



In order to use this framework in your app, you need to get an instance of the MediaRouter framework object and attach a MediaRouter.Callback object to listen for event in available media routes.

 

The android apps that implement the media router API need to include a Cast button to allow users to select a media route to play media on a secondary output device. The recommended way to implement the Cast button  is to extend your activity from ActionBarActivity() and use the onCreateOptionMenu() method to add an options menu. The Cast button must use the MediaRouteActionProvider class as its action:

 


<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
>

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


 

 

The media router framework communicates with an app through a callback object that you attach to the mediarouter framework object.  Its necessary to extend the callback object in order to receive messages when a media route is connected.

 

Once your callback is defined for the media router,  you need to attach it to the media router object.  The following sample demonstrates how to use the lifecycle methos to appropriately add and remove your app’s media router callback object. You need to add and remove it because it needs to be free for whenever you close the app or have it in the background so other apps use it if necessary.

 

 


public class MediaRouterPlaybackActivity extends ActionBarActivity {
private MediaRouter mMediaRouter;
private MediaRouteSelector mSelector;
private Callback mMediaRouterCallback;

// your app works with so the framework can discover them.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView
(R.layout.activity_main);

// Get the media router service.
mMediaRouter
= MediaRouter.getInstance(this);
...
}

// Add the callback on start to tell the media router what kinds of routes
// your app works with so the framework can discover them.
@Override
public void onStart() {
mMediaRouter
.addCallback(mSelector, mMediaRouterCallback,
MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
super.onStart();
}

// Remove the selector on stop to tell the media router that it no longer
// needs to discover routes for your app.
@Override
public void onStop() {
mMediaRouter
.removeCallback(mMediaRouterCallback);
super.onStop();
}
...
}


Remote playback

 

This approach sends control commands to a secondary device to initiate playback and to control the playback that is in progress (play, stop, fast-forward, rewind, etc). When your app supports this type of media route, you must need to create a RemotePlaybackClient boject using a remote playback MediaRoute.RouteInfo object received through your app’s MediaRouter.Callback object.

 

The following sample code demonstrates a controller method that creates a new remote playback cliente and sends it a video for playback.

 

 


private void updateRemotePlayer(RouteInfo route) {
// Changed route: tear down previous client
if (mRoute != null && mRemotePlaybackClient != null) {
mRemotePlaybackClient
.release();
mRemotePlaybackClient
= null;
}

// Save new route
mRoute
= route;

// Attach new playback client
mRemotePlaybackClient
= new RemotePlaybackClient(this, mRoute);

// Send file for playback
mRemotePlaybackClient
.play(Uri.parse(
"http://archive.org/download/Sintel/sintel-2048-stereo_512kb.mp4"),
"video/mp4", null, 0, null, new ItemActionCallback() {

@Override
public void onResult(Bundle data, String sessionId,
MediaSessionStatus sessionStatus,
String itemId, MediaItemStatus itemStatus) {
logStatus
("play: succeeded for item " + itemId);
}

@Override
public void onError(String error, int code, Bundle data) {
logStatus
("play: failed - error:"+ code +" - "+ error);
}
});
}
}


 

 

For more information on how to use the media router, you can visit developer.android.com

Attachments

    Outcomes