Multiple Displays

Multiple Displays – Part 4

In the previous article we got our app (which shows the characteristics of our displays) backwardly compatibile, but it still lacks the ability to handle connection and disconnection of an external display while the MainActivity is running. In this article we’ll add the ability to do precisely that.

Detecting display connection changes is actually pretty easy, but it is important to do it in order to properly clean things up. It is for this reason that I’ve marked the code, up to this point, as not being fit for production. To get notified of display connection changes we need to register an appropriate listener on our DisplayManager. Let’s begin by defining our listener, which implements the DisplayListener interface:

[java] @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private class MyDisplayListener implements DisplayListener
{
@Override
public void onDisplayAdded(int displayId)
{
DisplayManager dm =
(DisplayManager) getSystemService(DISPLAY_SERVICE);
Display disp = dm.getDisplay(displayId);
if (disp != null)
{
mPresentation = new MyPresentation(
MainActivity.this,
disp);
mPresentation.show();
}
}

@Override
public void onDisplayChanged(int displayId)
{
}

@Override
public void onDisplayRemoved(int displayId)
{
if(mPresentation != null &&
mPresentation.getDisplay().getDisplayId() == displayId)
{
mPresentation = null;
}
}
}
[/java]

Once again, DisplayListener is specific to SDK 17 and later, so we need the appropriate annotation. Also we need to ensure that it only on devices running 4.2 or higher, so we’ll create and register it in our multiInit() method:

[java] private MyDisplayListener mListener = null;

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private void multiInit()
{
DisplayManager dm = (DisplayManager) getSystemService(DISPLAY_SERVICE);
if (dm != null)
{
mListener = new MyDisplayListener();
dm.registerDisplayListener(mListener, null);
Display[] displays = dm.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION);
for (Display display : displays)
{
mPresentation = new MyPresentation(this, display);
mPresentation.show();
}
}
}
[/java]

We should also clean up after ourselves, and unregister the listener in onDestroy() including the appropriate version checks and annotations, of course:

[java] @Override
protected void onDestroy()
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
{
multiDestroy();
}
super.onDestroy();
}
.
.
.
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private void multiDestroy()
{
if(mListener != null)
{
DisplayManager dm = (DisplayManager) getSystemService(DISPLAY_SERVICE);
dm.unregisterDisplayListener(mListener);
}
}
[/java]

Our app will now correctly handle the connection and disconnection of the external display.

Another thing that we’ll now look at is why the external display has a different theme to the main display, and how we can change this. It is worth remembering that Presentation actually extends Dialog – so is an implementation of DialogFragment. Normally you can control the themeing of a Dialog by using the appropriate constructor, and the same applies to Presentation. What we need to do is change the existing constructor to include the theme option:

[java] @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public class MyPresentation extends Presentation
{

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

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

Then we just need to change wherever this is instantiated to pass in an appropriate theme:

[java] mPresentation = new MyPresentation(this, display,
android.R.style.Theme_Holo_Light_NoActionBar);
[/java]

The neat thing about this is that it enables us to us a slightly different theme on the presentation display. For example, in this case I have used android.R.style.Theme_Holo_Light_NoActionBar because I don’t want the ActionBar to show. Had I used android.R.style.Theme_Holo_Light the ActionBar would display on the external presentation display. Normally we won’t want to show the ActionBar on an external display because it is not a touch screen, so the concept of an ActionBar (which is effectively an interactive control) appearing on a non-interactive display seems a little strange. Having said that, the ActionBar implementation in this app does not actually contain any interactive elements, but that’s not really an issue, here.

Android always seems to have multiple ways of doing certain things, and in the final article in this series we’ll have a look at an alternate mechanism for managing external displays.

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.

3 Comments

  1. Hey Mark,

    “Presentation actually extends Dialog – so is an implementation of DialogFragment”
    Presentation extends Dialog – yes, but Dialog is not an implementation of DialogFragment, isn’t it?

    Have a great day
    Tom

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