Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Set Up a Window on an External Display from a Service?

Tags:

android

Android added Presentation in API Level 17 (Android 4.2) to support displaying content on an external Display, such as as TV or monitor connected via HDMI, MHL, Miracast, or SlimPort. However, Presentation extends Dialog, and so it is only usable from an Activity.

And, as far as I knew, that was the end of the story.

However, this StackOverflow answer hints at a possible way to use an external Display from a Service, by means of createDisplayContext() and WindowManager created from that Context. Then, the addView() method on that WindowManager should render the View onto the indicated Display. If this can be made to work, it really opens the door for interesting uses of external displays, such as playing a video on a TV while being able to use unrelated apps (e.g., a Web browser) on the device's own touchscreen.

However, that answer glosses over a key detail: how to set up the WindowManager.LayoutParams for the addView() call. In particular, there are a dizzying array of possible TYPE_ values for the type field. I have crashed in two attempts, though with different messages:

  • TYPE_APPLICATION results in android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application

  • TYPE_APPLICATION_MEDIA results in android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?

For example, here is my WindowManager.LayoutParams for the second scenario above:

WindowManager.LayoutParams p=
    new WindowManager.LayoutParams(
                                   WindowManager.LayoutParams.MATCH_PARENT,
                                   WindowManager.LayoutParams.MATCH_PARENT,
                                   0,
                                   0,
                                   WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA,
                                   0, PixelFormat.OPAQUE);

Reading through the docs for type suggest that none of the TYPE_APPLICATION will be correct, as I do not have a token. Moreover, the point behind this exercise is to not have a token, as least as far as I can tell, as the Service is supposed to run independently from any UI.

If you look at the source to Presentation, it defers the WindowManager work to Dialog, which uses com.android.internal.policy.PolicyManager, which quickly dead-ends in an IPolicy. An SDK app does not have access to PolicyManager, anyway.

Has anyone gotten the createDisplayContext() approach to work from a Service? If so, what did you use for the type (or, more generally, for the WindowManager.LayoutParams in general)? Bonus points for a solution that does not involve some icky permission. :-)

Thanks!

like image 591
CommonsWare Avatar asked Mar 21 '14 13:03

CommonsWare


People also ask

How do I get Windows to show on an external monitor?

Turn the monitor on. Right-click the Windows desktop and select Display Settings from the drop-down list. If two monitors are not displayed normally, click Detect. Select Show only on 2 from the drop-down list.

How do I split screens between laptop and monitor?

Split screen on one monitorPress and hold the Windows key . Press the left or right arrow key. If you press the left arrow key, the active program window shows on the left side of the split screen. If you press the right arrow key, it shows on the right side of the split screen.


1 Answers

TYPE_SYSTEM_ALERT type used conjunctly with the SYSTEM_ALERT_WINDOW permission should work.

It makes sense that launching a dialog from a service requires "icky" permissions, it basically allows you to draw over other apps :)

like image 172
ph0b Avatar answered Sep 20 '22 19:09

ph0b