1a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown/*
2a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * Copyright (C) 2012 The Android Open Source Project
3a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown *
4a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
5a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * you may not use this file except in compliance with the License.
6a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * You may obtain a copy of the License at
7a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown *
8a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
9a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown *
10a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * Unless required by applicable law or agreed to in writing, software
11a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
12a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * See the License for the specific language governing permissions and
14a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * limitations under the License.
15a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown */
16a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
17a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownpackage android.app;
18a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
195b6714c2fa3cdd87642766e3fb0a1478d2422ec2Wale Ogunwaleimport static android.content.Context.DISPLAY_SERVICE;
205b6714c2fa3cdd87642766e3fb0a1478d2422ec2Wale Ogunwaleimport static android.content.Context.WINDOW_SERVICE;
215b6714c2fa3cdd87642766e3fb0a1478d2422ec2Wale Ogunwaleimport static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION;
225b6714c2fa3cdd87642766e3fb0a1478d2422ec2Wale Ogunwale
23a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.content.Context;
24a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.content.res.Resources;
25a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.hardware.display.DisplayManager;
26a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.hardware.display.DisplayManager.DisplayListener;
275b6714c2fa3cdd87642766e3fb0a1478d2422ec2Wale Ogunwaleimport android.os.Binder;
285b6714c2fa3cdd87642766e3fb0a1478d2422ec2Wale Ogunwaleimport android.os.IBinder;
29a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.view.ContextThemeWrapper;
30a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.view.Display;
31a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.view.Gravity;
325b6714c2fa3cdd87642766e3fb0a1478d2422ec2Wale Ogunwaleimport android.view.Window;
335b6714c2fa3cdd87642766e3fb0a1478d2422ec2Wale Ogunwaleimport android.view.WindowManager;
34a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.view.WindowManagerImpl;
35a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.os.Handler;
36a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.os.Message;
37a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.util.DisplayMetrics;
38a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.util.Log;
39a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.util.TypedValue;
40a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
41a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown/**
42a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * Base class for presentations.
43a95a3b494fd88f83c9f5d32e001452575ba235ecJeff Brown * <p>
44a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * A presentation is a special kind of dialog whose purpose is to present
45a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * content on a secondary display.  A {@link Presentation} is associated with
46a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * the target {@link Display} at creation time and configures its context and
47a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * resource configuration according to the display's metrics.
48a95a3b494fd88f83c9f5d32e001452575ba235ecJeff Brown * </p><p>
49a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * Notably, the {@link Context} of a presentation is different from the context
50a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * of its containing {@link Activity}.  It is important to inflate the layout
51a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * of a presentation and load other resources using the presentation's own context
52a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * to ensure that assets of the correct size and density for the target display
53a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * are loaded.
54a95a3b494fd88f83c9f5d32e001452575ba235ecJeff Brown * </p><p>
55a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * A presentation is automatically canceled (see {@link Dialog#cancel()}) when
56a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * the display to which it is attached is removed.  An activity should take
57a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * care of pausing and resuming whatever content is playing within the presentation
58a95a3b494fd88f83c9f5d32e001452575ba235ecJeff Brown * whenever the activity itself is paused or resumed.
59a95a3b494fd88f83c9f5d32e001452575ba235ecJeff Brown * </p>
60a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown *
6192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <h3>Choosing a presentation display</h3>
6292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <p>
6392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Before showing a {@link Presentation} it's important to choose the {@link Display}
6492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * on which it will appear.  Choosing a presentation display is sometimes difficult
6592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * because there may be multiple displays attached.  Rather than trying to guess
6692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * which display is best, an application should let the system choose a suitable
6792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * presentation display.
6892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p>
6992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * There are two main ways to choose a {@link Display}.
7092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p>
7192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *
7292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <h4>Using the media router to choose a presentation display</h4>
7392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <p>
7492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The easiest way to choose a presentation display is to use the
7592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * {@link android.media.MediaRouter MediaRouter} API.  The media router service keeps
7692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * track of which audio and video routes are available on the system.
7792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The media router sends notifications whenever routes are selected or unselected
7892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * or when the preferred presentation display of a route changes.
7992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * So an application can simply watch for these notifications and show or dismiss
8092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * a presentation on the preferred presentation display automatically.
8192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p>
8292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The preferred presentation display is the display that the media router recommends
8392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * that the application should use if it wants to show content on the secondary display.
8492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Sometimes there may not be a preferred presentation display in which
8592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * case the application should show its content locally without using a presentation.
8692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p>
8792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Here's how to use the media router to create and show a presentation on the preferred
8892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * presentation display using {@link android.media.MediaRouter.RouteInfo#getPresentationDisplay()}.
8992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p>
909cc531cc26d928c7b53105def0d80647fba1acd7Scott Main * <pre>
9192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * MediaRouter mediaRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
9292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * MediaRouter.RouteInfo route = mediaRouter.getSelectedRoute();
939cc531cc26d928c7b53105def0d80647fba1acd7Scott Main * if (route != null) {
9492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *     Display presentationDisplay = route.getPresentationDisplay();
959cc531cc26d928c7b53105def0d80647fba1acd7Scott Main *     if (presentationDisplay != null) {
9692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *         Presentation presentation = new MyPresentation(context, presentationDisplay);
9792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *         presentation.show();
989cc531cc26d928c7b53105def0d80647fba1acd7Scott Main *     }
999cc531cc26d928c7b53105def0d80647fba1acd7Scott Main * }</pre>
10092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <p>
10192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The following sample code from <code>ApiDemos</code> demonstrates how to use the media
10292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * router to automatically switch between showing content in the main activity and showing
10392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * the content in a presentation when a presentation display is available.
10492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p>
10592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/PresentationWithMediaRouterActivity.java
10692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *      activity}
10792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *
10892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <h4>Using the display manager to choose a presentation display</h4>
10992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <p>
11092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Another way to choose a presentation display is to use the {@link DisplayManager} API
11192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * directly.  The display manager service provides functions to enumerate and describe all
11292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * displays that are attached to the system including displays that may be used
11392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * for presentations.
11492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p>
11592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The display manager keeps track of all displays in the system.  However, not all
11692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * displays are appropriate for showing presentations.  For example, if an activity
11792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * attempted to show a presentation on the main display it might obscure its own content
11892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * (it's like opening a dialog on top of your activity).
11992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p>
12092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Here's how to identify suitable displays for showing presentations using
12192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * {@link DisplayManager#getDisplays(String)} and the
12292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * {@link DisplayManager#DISPLAY_CATEGORY_PRESENTATION} category.
12392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p>
1249cc531cc26d928c7b53105def0d80647fba1acd7Scott Main * <pre>
12592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * DisplayManager displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
12692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Display[] presentationDisplays = displayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION);
1279cc531cc26d928c7b53105def0d80647fba1acd7Scott Main * if (presentationDisplays.length > 0) {
12892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *     // If there is more than one suitable presentation display, then we could consider
12992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *     // giving the user a choice.  For this example, we simply choose the first display
13092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *     // which is the one the system recommends as the preferred presentation display.
13192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *     Display display = presentationDisplays[0];
13292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *     Presentation presentation = new MyPresentation(context, presentationDisplay);
13392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *     presentation.show();
1349cc531cc26d928c7b53105def0d80647fba1acd7Scott Main * }</pre>
13592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <p>
13692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The following sample code from <code>ApiDemos</code> demonstrates how to use the display
13792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * manager to enumerate displays and show content on multiple presentation displays
13892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * simultaneously.
13992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p>
14092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/PresentationActivity.java
14192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *      activity}
14292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *
14392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see android.media.MediaRouter#ROUTE_TYPE_LIVE_VIDEO for information on about live
14492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * video routes and how to obtain the preferred presentation display for the
14592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * current media route.
146a95a3b494fd88f83c9f5d32e001452575ba235ecJeff Brown * @see DisplayManager for information on how to enumerate displays and receive
147a95a3b494fd88f83c9f5d32e001452575ba235ecJeff Brown * notifications when displays are added or removed.
148a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown */
149a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownpublic class Presentation extends Dialog {
150a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    private static final String TAG = "Presentation";
151a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
152a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    private static final int MSG_CANCEL = 1;
153a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
154a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    private final Display mDisplay;
155a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    private final DisplayManager mDisplayManager;
1565b6714c2fa3cdd87642766e3fb0a1478d2422ec2Wale Ogunwale    private final IBinder mToken = new Binder();
157a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
158a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    /**
159a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * Creates a new presentation that is attached to the specified display
160a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * using the default theme.
161a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     *
162a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * @param outerContext The context of the application that is showing the presentation.
163a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * The presentation will create its own context (see {@link #getContext()}) based
164a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * on this context and information about the associated display.
165a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * @param display The display to which the presentation should be attached.
166a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     */
167a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    public Presentation(Context outerContext, Display display) {
168a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        this(outerContext, display, 0);
169a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
170a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
171a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    /**
172a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * Creates a new presentation that is attached to the specified display
173a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * using the optionally specified theme.
174a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     *
175a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * @param outerContext The context of the application that is showing the presentation.
176a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * The presentation will create its own context (see {@link #getContext()}) based
177a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * on this context and information about the associated display.
178a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * @param display The display to which the presentation should be attached.
179a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * @param theme A style resource describing the theme to use for the window.
180a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * See <a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">
181a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * Style and Theme Resources</a> for more information about defining and using
182a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * styles.  This theme is applied on top of the current theme in
183a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * <var>outerContext</var>.  If 0, the default presentation theme will be used.
184a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     */
185a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    public Presentation(Context outerContext, Display display, int theme) {
186a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        super(createPresentationContext(outerContext, display, theme), theme, false);
187a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
188a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        mDisplay = display;
1895b6714c2fa3cdd87642766e3fb0a1478d2422ec2Wale Ogunwale        mDisplayManager = (DisplayManager)getContext().getSystemService(DISPLAY_SERVICE);
190a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
1915b6714c2fa3cdd87642766e3fb0a1478d2422ec2Wale Ogunwale        final Window w = getWindow();
1925b6714c2fa3cdd87642766e3fb0a1478d2422ec2Wale Ogunwale        final WindowManager.LayoutParams attr = w.getAttributes();
1935b6714c2fa3cdd87642766e3fb0a1478d2422ec2Wale Ogunwale        attr.token = mToken;
1945b6714c2fa3cdd87642766e3fb0a1478d2422ec2Wale Ogunwale        w.setAttributes(attr);
1955b6714c2fa3cdd87642766e3fb0a1478d2422ec2Wale Ogunwale        w.setGravity(Gravity.FILL);
1965b6714c2fa3cdd87642766e3fb0a1478d2422ec2Wale Ogunwale        w.setType(TYPE_PRESENTATION);
197a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        setCanceledOnTouchOutside(false);
198a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
199a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
200a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    /**
201a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * Gets the {@link Display} that this presentation appears on.
202a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     *
203a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * @return The display.
204a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     */
205a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    public Display getDisplay() {
206a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        return mDisplay;
207a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
208a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
209a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    /**
210a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * Gets the {@link Resources} that should be used to inflate the layout of this presentation.
211a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * This resources object has been configured according to the metrics of the
212a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * display that the presentation appears on.
213a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     *
214a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * @return The presentation resources object.
215a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     */
216a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    public Resources getResources() {
217a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        return getContext().getResources();
218a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
219a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
220a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    @Override
221a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    protected void onStart() {
222a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        super.onStart();
22392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown        mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
224a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
225a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // Since we were not watching for display changes until just now, there is a
226a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // chance that the display metrics have changed.  If so, we will need to
227a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // dismiss the presentation immediately.  This case is expected
228a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // to be rare but surprising, so we'll write a log message about it.
229a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        if (!isConfigurationStillValid()) {
230fe4ad335d80960233022cc2cab79338f5d327582Jeff Brown            Log.i(TAG, "Presentation is being dismissed because the "
231a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                    + "display metrics have changed since it was created.");
232a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            mHandler.sendEmptyMessage(MSG_CANCEL);
233a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
234a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
235a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
236a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    @Override
237a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    protected void onStop() {
238a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        mDisplayManager.unregisterDisplayListener(mDisplayListener);
239a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        super.onStop();
240a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
241a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
242a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    /**
2436018aeec27914f138f36b00d8f00136a87562fd3Craig Mautner     * Inherited from {@link Dialog#show}. Will throw
2446018aeec27914f138f36b00d8f00136a87562fd3Craig Mautner     * {@link android.view.WindowManager.InvalidDisplayException} if the specified secondary
2456018aeec27914f138f36b00d8f00136a87562fd3Craig Mautner     * {@link Display} can't be found.
2466018aeec27914f138f36b00d8f00136a87562fd3Craig Mautner     */
2476018aeec27914f138f36b00d8f00136a87562fd3Craig Mautner    @Override
2486018aeec27914f138f36b00d8f00136a87562fd3Craig Mautner    public void show() {
2496018aeec27914f138f36b00d8f00136a87562fd3Craig Mautner        super.show();
2506018aeec27914f138f36b00d8f00136a87562fd3Craig Mautner    }
2516018aeec27914f138f36b00d8f00136a87562fd3Craig Mautner
2526018aeec27914f138f36b00d8f00136a87562fd3Craig Mautner    /**
253a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * Called by the system when the {@link Display} to which the presentation
254a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * is attached has been removed.
255a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     *
256a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * The system automatically calls {@link #cancel} to dismiss the presentation
257a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * after sending this event.
258a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     *
259a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * @see #getDisplay
260a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     */
261a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    public void onDisplayRemoved() {
262a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
263a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
264a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    /**
265a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * Called by the system when the properties of the {@link Display} to which
266a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * the presentation is attached have changed.
267a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     *
268a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * If the display metrics have changed (for example, if the display has been
269a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * resized or rotated), then the system automatically calls
270a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * {@link #cancel} to dismiss the presentation.
271a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     *
272a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * @see #getDisplay
273a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     */
274a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    public void onDisplayChanged() {
275a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
276a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
277a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    private void handleDisplayRemoved() {
278a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        onDisplayRemoved();
279a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        cancel();
280a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
281a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
282a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    private void handleDisplayChanged() {
283a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        onDisplayChanged();
284a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
285a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // We currently do not support configuration changes for presentations
286a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // (although we could add that feature with a bit more work).
287a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // If the display metrics have changed in any way then the current configuration
288a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // is invalid and the application must recreate the presentation to get
289a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // a new context.
290a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        if (!isConfigurationStillValid()) {
291fe4ad335d80960233022cc2cab79338f5d327582Jeff Brown            Log.i(TAG, "Presentation is being dismissed because the "
292fe4ad335d80960233022cc2cab79338f5d327582Jeff Brown                    + "display metrics have changed since it was created.");
293a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            cancel();
294a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
295a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
296a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
297a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    private boolean isConfigurationStillValid() {
298a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        DisplayMetrics dm = new DisplayMetrics();
299a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        mDisplay.getMetrics(dm);
3007ac8bbddfcaa2539f6311be54323d22f2dcc4a35Dianne Hackborn        return dm.equalsPhysical(getResources().getDisplayMetrics());
301a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
302a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
303a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    private static Context createPresentationContext(
304a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            Context outerContext, Display display, int theme) {
305a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        if (outerContext == null) {
306a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            throw new IllegalArgumentException("outerContext must not be null");
307a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
308a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        if (display == null) {
309a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            throw new IllegalArgumentException("display must not be null");
310a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
311a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
312a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        Context displayContext = outerContext.createDisplayContext(display);
313a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        if (theme == 0) {
314a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            TypedValue outValue = new TypedValue();
315a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            displayContext.getTheme().resolveAttribute(
316a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                    com.android.internal.R.attr.presentationTheme, outValue, true);
317a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            theme = outValue.resourceId;
318a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
319a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
320a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // Derive the display's window manager from the outer window manager.
321a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // We do this because the outer window manager have some extra information
322a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // such as the parent window, which is important if the presentation uses
323a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // an application window type.
324a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        final WindowManagerImpl outerWindowManager =
3255b6714c2fa3cdd87642766e3fb0a1478d2422ec2Wale Ogunwale                (WindowManagerImpl)outerContext.getSystemService(WINDOW_SERVICE);
326a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        final WindowManagerImpl displayWindowManager =
3274ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski                outerWindowManager.createPresentationWindowManager(displayContext);
328a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        return new ContextThemeWrapper(displayContext, theme) {
329a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            @Override
330a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            public Object getSystemService(String name) {
3315b6714c2fa3cdd87642766e3fb0a1478d2422ec2Wale Ogunwale                if (WINDOW_SERVICE.equals(name)) {
332a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                    return displayWindowManager;
333a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                }
334a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                return super.getSystemService(name);
335a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            }
336a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        };
337a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
338a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
339a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    private final DisplayListener mDisplayListener = new DisplayListener() {
340a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        @Override
341a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        public void onDisplayAdded(int displayId) {
342a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
343a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
344a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        @Override
345a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        public void onDisplayRemoved(int displayId) {
346a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            if (displayId == mDisplay.getDisplayId()) {
347a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                handleDisplayRemoved();
348a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            }
349a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
350a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
351a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        @Override
352a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        public void onDisplayChanged(int displayId) {
353a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            if (displayId == mDisplay.getDisplayId()) {
354a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                handleDisplayChanged();
355a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            }
356a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
357a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    };
358a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
359a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    private final Handler mHandler = new Handler() {
360a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        @Override
361a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        public void handleMessage(Message msg) {
362a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            switch (msg.what) {
363a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                case MSG_CANCEL:
364a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                    cancel();
365a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                    break;
366a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            }
367a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
368a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    };
369a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown}
370