Multiple Displays

Multiple Displays – Part 2

In the previous article we put together a simple utility which shows the display characteristics, and showed this working on various devices. However the main point of this series is to cover the use of multiple displays, os in this part we’ll begin looking at that functionality.

The first thing worth looking at is some tools that are available to assist us in developing for multiple displays. One of the problems that I considered when planning this series was how to get screen captures from the HDMI out port of the Nexus 10. Moreover, a bigger concern when developing an external display which behaves differently from the default display is how will it render to, for example, a 720p display vs. a 1080p one? Fortunately for us, there are some developer tools built in to the OS which allow us to test this. Under Settings|Developer Options|Drawing|Simulate secondary displays we can configure a secondary display.

As an aside, if you cannot find Developer Options on your 4.2 device, you need to go to Settings|About [tablet|phone] and click on Build number repeatedly until you see a toast informing you that you are now a developer. If only becoming an Android developer were that easy!

When we configure a secondary display in this manner, it displays a small, transparent popup within the main device display. If we run our existing code on the Nexus 10 with a 1280×720 tvdpi secondary display configures, we’ll see the following:

We can see the exact same information is being shown in the popup as the main display. As we said previously, this is because at present the output to the external deice will be a precise mirror of what is being being shown on the main device display. As we continue, we will see how this information changes once we start controlling the displays independently.

In order to configure the external display separately, we need to use the DisplayManager service that was introduced in Jelly Bean 4.2. We can obtain a DisplayManager instance in much the same way as other system services:

[java] DisplayManager dm = (DisplayManager) getSystemService(DISPLAY_SERVICE);
[/java]

We can then get an array of the currently operational displays by calling getDisplays() on DisplayManager. We can whittle this list down by specifying Presentation category (which will exclude the main device display):

[java] Display[] displays = dm.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION);
[/java]

We can then iterate through this list and create a new android.app.Presentation object for each:

[java] for (Display display : displays)
{
mPresentation = new MyPresentation(this, display);
mPresentation.show();
}
[/java]

Presentation extends Dialog, so we need to call show() to display it. One word of warning here: using Fragments within your Presentation can be problematic. At the time of writing I don’t know why this is, but it could be related to mixing Fragment life cycles.

All that remains is to declare MyPresentation:

[java] public class MyPresentation extends Presentation
{
public MyPresentation(Context outerContext,
Display display)
{
super(outerContext, display);
}

@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
populate(findViewById(R.id.main), getDisplay());
}
}
[/java]

All we are doing here is using the exact same layout as we did in the Activity, and then calling the populate method that we defined earlier. Because we need access to this method, MyPresentation needs to be an inner class of the activity.

It is worth pointing out that we don’t have to use the same layout here. We can create a Presentation that is completely different to the main Activity, but we’re using this example to prove that the same layout is being inflated an populated independently for mutliple displays.

So if we put this all together we get the following:

[java] public class MainActivity extends Activity
{
private MyPresentation mPresentation = null;

/*
* This code is not production ready. Do not use
* for anything other than test projects.
*/

@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
populate(findViewById(R.id.main), getWindowManager()
.getDefaultDisplay());
multiInit();
}

@Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}

private static void populate(View v, Display display)
{
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
float density = metrics.density;
TextView actual =
(TextView) v.findViewById(R.id.actual);
if (actual != null)
{
actual.setText(String.format("%dx%d",
metrics.widthPixels,
metrics.heightPixels));
}
TextView df =
(TextView) v.findViewById(R.id.density_factor);
if (df != null)
{
df.setText(String.format("%f", density));
}
TextView dp =
(TextView) v.findViewById(R.id.device_pixels);
if (dp != null)
{
dp.setText(String.format("%dx%d",
((int)((float) metrics.widthPixels / density)),
((int)((float) metrics.heightPixels / density))));
}
}

private void multiInit()
{
DisplayManager dm =
(DisplayManager) getSystemService(DISPLAY_SERVICE);
if (dm != null)
{
Display[] displays =
dm.getDisplays(
DisplayManager.DISPLAY_CATEGORY_PRESENTATION);
for (Display display : displays)
{
mPresentation = new MyPresentation(this, display);
mPresentation.show();
}
}
}

public class MyPresentation extends Presentation
{

public MyPresentation(Context outerContext,
Display display)
{
super(outerContext, display);
}

@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
populate(findViewById(R.id.main),
getDisplay());
}
}
}
[/java]

The problem that we now have is that it won’t compile with a minSdk set to4 because we are using API calls that are specific to SDK 17. We’ll temporarily change the minSdk setting in the Android manifest to 17 just to get this working.

If we run this, we can see that our secondary display now shows different values and also inherits the dark theme from the ActionBar instead of using the light theme of the main content:

However this code is not yet ready for production, as you may have guessed from the comment within in. Firstly, we lost our backwards compatibility by switching to minSdk 17. Secondly, it does not handle connection and disconnection of the secondary display while the Activity is running.

In the next part of this series we’ll look at making this code backwardly compatible.

The source code for this article can be found here.

© 2012, Mark Allison. All rights reserved.

Copyright © 2012 Styling Android. All Rights Reserved.
Information about how to reuse or republish this work may be available at http://blog.stylingandroid.com/license-information.

15 Comments

  1. Very interesting article. Do you know if you can get a second display working in the emulator? I don’t have any hardware yet that support this.

      1. That option is available for me. Do you encounter enable the option which is simulate secondary display but the overlay display has show nothing?

        1. Ya , same for me i am able to simulate the secondary display but not able to populate it with the layout.

          Any solutions for the same ???????????

  2. Interesting. Can this be somehow used for screen recording/capture purposes? 😮 On the Galaxy Nexus access to the framebuffer from user space code is prevented due to some level of DRM in the OMAP4 processor. As a result all present screenrecording apps fail (eg. the popular ScreenCast Video Recorder). But if we could define a simulated secondary display over the real display of the device, could we access the simulated display’s contents and record it at a high FPS (24 – 30) into an mp4 file? 😮
    (Sorry if the question is silly … I’m not an Android developer, so I don’t really know if my question makes any sense in the context of the new display management APIs.)

  3. Hi Mark,

    I remember Presentation class is extends from Dialog. Am i right? So below describe may be incorrect?

    Presentation extends DialogFragment, so we need to call show() to display it. One word of warning here: because Presentation extends DialogFragment.

  4. Is it possible to display two different contents on the main display & Secondary display? (assume secondary display also on the pop up Main display only.

  5. Hey. Thanks for the tutorial! It really helped! 🙂
    I know this is old, but do you have a suggestion or a source for the Presentation API?
    I plan draw something on main screen (Cancas, Gestures, Points, like Microsoft Paint ;), but I want to show this on the second screen. Do you have any idea how I could solve this?

    Thank you very much 🙂

Leave a Reply to Peter Fortuin Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.