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
19a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.content.Context;
20a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.content.res.Resources;
21a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.hardware.display.DisplayManager;
22a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.hardware.display.DisplayManager.DisplayListener;
23a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.view.ContextThemeWrapper;
24a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.view.Display;
25a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.view.Gravity;
26a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.view.WindowManagerImpl;
27a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.os.Handler;
28a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.os.Message;
29a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.util.DisplayMetrics;
30a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.util.Log;
31a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownimport android.util.TypedValue;
32a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
33a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown/**
34a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * Base class for presentations.
35a95a3b494fd88f83c9f5d32e001452575ba235ecJeff Brown * <p>
36a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * A presentation is a special kind of dialog whose purpose is to present
37a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * content on a secondary display.  A {@link Presentation} is associated with
38a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * the target {@link Display} at creation time and configures its context and
39a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * resource configuration according to the display's metrics.
40a95a3b494fd88f83c9f5d32e001452575ba235ecJeff Brown * </p><p>
41a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * Notably, the {@link Context} of a presentation is different from the context
42a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * of its containing {@link Activity}.  It is important to inflate the layout
43a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * of a presentation and load other resources using the presentation's own context
44a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * to ensure that assets of the correct size and density for the target display
45a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * are loaded.
46a95a3b494fd88f83c9f5d32e001452575ba235ecJeff Brown * </p><p>
47a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * A presentation is automatically canceled (see {@link Dialog#cancel()}) when
48a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * the display to which it is attached is removed.  An activity should take
49a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * care of pausing and resuming whatever content is playing within the presentation
50a95a3b494fd88f83c9f5d32e001452575ba235ecJeff Brown * whenever the activity itself is paused or resumed.
51a95a3b494fd88f83c9f5d32e001452575ba235ecJeff Brown * </p>
52a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown *
5392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <h3>Choosing a presentation display</h3>
5492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <p>
5592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Before showing a {@link Presentation} it's important to choose the {@link Display}
5692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * on which it will appear.  Choosing a presentation display is sometimes difficult
5792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * because there may be multiple displays attached.  Rather than trying to guess
5892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * which display is best, an application should let the system choose a suitable
5992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * presentation display.
6092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p>
6192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * There are two main ways to choose a {@link Display}.
6292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p>
6392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *
6492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <h4>Using the media router to choose a presentation display</h4>
6592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <p>
6692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The easiest way to choose a presentation display is to use the
6792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * {@link android.media.MediaRouter MediaRouter} API.  The media router service keeps
6892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * track of which audio and video routes are available on the system.
6992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The media router sends notifications whenever routes are selected or unselected
7092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * or when the preferred presentation display of a route changes.
7192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * So an application can simply watch for these notifications and show or dismiss
7292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * a presentation on the preferred presentation display automatically.
7392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p>
7492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The preferred presentation display is the display that the media router recommends
7592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * that the application should use if it wants to show content on the secondary display.
7692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Sometimes there may not be a preferred presentation display in which
7792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * case the application should show its content locally without using a presentation.
7892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p>
7992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Here's how to use the media router to create and show a presentation on the preferred
8092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * presentation display using {@link android.media.MediaRouter.RouteInfo#getPresentationDisplay()}.
8192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p>
829cc531cc26d928c7b53105def0d80647fba1acd7Scott Main * <pre>
8392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * MediaRouter mediaRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
8492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * MediaRouter.RouteInfo route = mediaRouter.getSelectedRoute();
859cc531cc26d928c7b53105def0d80647fba1acd7Scott Main * if (route != null) {
8692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *     Display presentationDisplay = route.getPresentationDisplay();
879cc531cc26d928c7b53105def0d80647fba1acd7Scott Main *     if (presentationDisplay != null) {
8892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *         Presentation presentation = new MyPresentation(context, presentationDisplay);
8992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *         presentation.show();
909cc531cc26d928c7b53105def0d80647fba1acd7Scott Main *     }
919cc531cc26d928c7b53105def0d80647fba1acd7Scott Main * }</pre>
9292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <p>
9392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The following sample code from <code>ApiDemos</code> demonstrates how to use the media
9492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * router to automatically switch between showing content in the main activity and showing
9592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * the content in a presentation when a presentation display is available.
9692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p>
9792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/PresentationWithMediaRouterActivity.java
9892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *      activity}
9992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *
10092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <h4>Using the display manager to choose a presentation display</h4>
10192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <p>
10292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Another way to choose a presentation display is to use the {@link DisplayManager} API
10392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * directly.  The display manager service provides functions to enumerate and describe all
10492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * displays that are attached to the system including displays that may be used
10592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * for presentations.
10692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p>
10792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The display manager keeps track of all displays in the system.  However, not all
10892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * displays are appropriate for showing presentations.  For example, if an activity
10992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * attempted to show a presentation on the main display it might obscure its own content
11092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * (it's like opening a dialog on top of your activity).
11192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p>
11292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Here's how to identify suitable displays for showing presentations using
11392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * {@link DisplayManager#getDisplays(String)} and the
11492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * {@link DisplayManager#DISPLAY_CATEGORY_PRESENTATION} category.
11592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p>
1169cc531cc26d928c7b53105def0d80647fba1acd7Scott Main * <pre>
11792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * DisplayManager displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
11892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Display[] presentationDisplays = displayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION);
1199cc531cc26d928c7b53105def0d80647fba1acd7Scott Main * if (presentationDisplays.length > 0) {
12092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *     // If there is more than one suitable presentation display, then we could consider
12192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *     // giving the user a choice.  For this example, we simply choose the first display
12292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *     // which is the one the system recommends as the preferred presentation display.
12392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *     Display display = presentationDisplays[0];
12492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *     Presentation presentation = new MyPresentation(context, presentationDisplay);
12592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *     presentation.show();
1269cc531cc26d928c7b53105def0d80647fba1acd7Scott Main * }</pre>
12792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <p>
12892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The following sample code from <code>ApiDemos</code> demonstrates how to use the display
12992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * manager to enumerate displays and show content on multiple presentation displays
13092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * simultaneously.
13192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p>
13292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/PresentationActivity.java
13392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *      activity}
13492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown *
13592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see android.media.MediaRouter#ROUTE_TYPE_LIVE_VIDEO for information on about live
13692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * video routes and how to obtain the preferred presentation display for the
13792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * current media route.
138a95a3b494fd88f83c9f5d32e001452575ba235ecJeff Brown * @see DisplayManager for information on how to enumerate displays and receive
139a95a3b494fd88f83c9f5d32e001452575ba235ecJeff Brown * notifications when displays are added or removed.
140a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown */
141a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownpublic class Presentation extends Dialog {
142a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    private static final String TAG = "Presentation";
143a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
144a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    private static final int MSG_CANCEL = 1;
145a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
146a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    private final Display mDisplay;
147a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    private final DisplayManager mDisplayManager;
148a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
149a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    /**
150a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * Creates a new presentation that is attached to the specified display
151a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * using the default theme.
152a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     *
153a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * @param outerContext The context of the application that is showing the presentation.
154a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * The presentation will create its own context (see {@link #getContext()}) based
155a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * on this context and information about the associated display.
156a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * @param display The display to which the presentation should be attached.
157a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     */
158a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    public Presentation(Context outerContext, Display display) {
159a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        this(outerContext, display, 0);
160a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
161a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
162a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    /**
163a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * Creates a new presentation that is attached to the specified display
164a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * using the optionally specified theme.
165a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     *
166a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * @param outerContext The context of the application that is showing the presentation.
167a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * The presentation will create its own context (see {@link #getContext()}) based
168a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * on this context and information about the associated display.
169a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * @param display The display to which the presentation should be attached.
170a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * @param theme A style resource describing the theme to use for the window.
171a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * See <a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">
172a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * Style and Theme Resources</a> for more information about defining and using
173a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * styles.  This theme is applied on top of the current theme in
174a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * <var>outerContext</var>.  If 0, the default presentation theme will be used.
175a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     */
176a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    public Presentation(Context outerContext, Display display, int theme) {
177a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        super(createPresentationContext(outerContext, display, theme), theme, false);
178a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
179a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        mDisplay = display;
180a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        mDisplayManager = (DisplayManager)getContext().getSystemService(Context.DISPLAY_SERVICE);
181a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
182a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        getWindow().setGravity(Gravity.FILL);
183a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        setCanceledOnTouchOutside(false);
184a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
185a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
186a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    /**
187a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * Gets the {@link Display} that this presentation appears on.
188a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     *
189a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * @return The display.
190a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     */
191a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    public Display getDisplay() {
192a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        return mDisplay;
193a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
194a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
195a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    /**
196a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * Gets the {@link Resources} that should be used to inflate the layout of this presentation.
197a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * This resources object has been configured according to the metrics of the
198a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * display that the presentation appears on.
199a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     *
200a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * @return The presentation resources object.
201a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     */
202a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    public Resources getResources() {
203a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        return getContext().getResources();
204a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
205a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
206a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    @Override
207a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    protected void onStart() {
208a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        super.onStart();
20992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown        mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
210a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
211a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // Since we were not watching for display changes until just now, there is a
212a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // chance that the display metrics have changed.  If so, we will need to
213a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // dismiss the presentation immediately.  This case is expected
214a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // to be rare but surprising, so we'll write a log message about it.
215a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        if (!isConfigurationStillValid()) {
216a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            Log.i(TAG, "Presentation is being immediately dismissed because the "
217a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                    + "display metrics have changed since it was created.");
218a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            mHandler.sendEmptyMessage(MSG_CANCEL);
219a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
220a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
221a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
222a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    @Override
223a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    protected void onStop() {
224a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        mDisplayManager.unregisterDisplayListener(mDisplayListener);
225a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        super.onStop();
226a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
227a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
228a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    /**
2296018aeec27914f138f36b00d8f00136a87562fd3Craig Mautner     * Inherited from {@link Dialog#show}. Will throw
2306018aeec27914f138f36b00d8f00136a87562fd3Craig Mautner     * {@link android.view.WindowManager.InvalidDisplayException} if the specified secondary
2316018aeec27914f138f36b00d8f00136a87562fd3Craig Mautner     * {@link Display} can't be found.
2326018aeec27914f138f36b00d8f00136a87562fd3Craig Mautner     */
2336018aeec27914f138f36b00d8f00136a87562fd3Craig Mautner    @Override
2346018aeec27914f138f36b00d8f00136a87562fd3Craig Mautner    public void show() {
2356018aeec27914f138f36b00d8f00136a87562fd3Craig Mautner        super.show();
2366018aeec27914f138f36b00d8f00136a87562fd3Craig Mautner    }
2376018aeec27914f138f36b00d8f00136a87562fd3Craig Mautner
2386018aeec27914f138f36b00d8f00136a87562fd3Craig Mautner    /**
239a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * Called by the system when the {@link Display} to which the presentation
240a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * is attached has been removed.
241a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     *
242a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * The system automatically calls {@link #cancel} to dismiss the presentation
243a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * after sending this event.
244a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     *
245a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * @see #getDisplay
246a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     */
247a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    public void onDisplayRemoved() {
248a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
249a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
250a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    /**
251a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * Called by the system when the properties of the {@link Display} to which
252a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * the presentation is attached have changed.
253a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     *
254a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * If the display metrics have changed (for example, if the display has been
255a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * resized or rotated), then the system automatically calls
256a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * {@link #cancel} to dismiss the presentation.
257a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     *
258a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     * @see #getDisplay
259a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown     */
260a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    public void onDisplayChanged() {
261a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
262a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
263a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    private void handleDisplayRemoved() {
264a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        onDisplayRemoved();
265a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        cancel();
266a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
267a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
268a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    private void handleDisplayChanged() {
269a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        onDisplayChanged();
270a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
271a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // We currently do not support configuration changes for presentations
272a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // (although we could add that feature with a bit more work).
273a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // If the display metrics have changed in any way then the current configuration
274a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // is invalid and the application must recreate the presentation to get
275a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // a new context.
276a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        if (!isConfigurationStillValid()) {
277a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            cancel();
278a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
279a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
280a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
281a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    private boolean isConfigurationStillValid() {
282a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        DisplayMetrics dm = new DisplayMetrics();
283a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        mDisplay.getMetrics(dm);
2847ac8bbddfcaa2539f6311be54323d22f2dcc4a35Dianne Hackborn        return dm.equalsPhysical(getResources().getDisplayMetrics());
285a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
286a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
287a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    private static Context createPresentationContext(
288a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            Context outerContext, Display display, int theme) {
289a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        if (outerContext == null) {
290a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            throw new IllegalArgumentException("outerContext must not be null");
291a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
292a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        if (display == null) {
293a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            throw new IllegalArgumentException("display must not be null");
294a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
295a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
296a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        Context displayContext = outerContext.createDisplayContext(display);
297a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        if (theme == 0) {
298a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            TypedValue outValue = new TypedValue();
299a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            displayContext.getTheme().resolveAttribute(
300a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                    com.android.internal.R.attr.presentationTheme, outValue, true);
301a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            theme = outValue.resourceId;
302a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
303a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
304a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // Derive the display's window manager from the outer window manager.
305a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // We do this because the outer window manager have some extra information
306a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // such as the parent window, which is important if the presentation uses
307a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // an application window type.
308a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        final WindowManagerImpl outerWindowManager =
309a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                (WindowManagerImpl)outerContext.getSystemService(Context.WINDOW_SERVICE);
310a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        final WindowManagerImpl displayWindowManager =
311a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                outerWindowManager.createPresentationWindowManager(display);
312a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        return new ContextThemeWrapper(displayContext, theme) {
313a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            @Override
314a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            public Object getSystemService(String name) {
315a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                if (Context.WINDOW_SERVICE.equals(name)) {
316a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                    return displayWindowManager;
317a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                }
318a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                return super.getSystemService(name);
319a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            }
320a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        };
321a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
322a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
323a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    private final DisplayListener mDisplayListener = new DisplayListener() {
324a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        @Override
325a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        public void onDisplayAdded(int displayId) {
326a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
327a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
328a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        @Override
329a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        public void onDisplayRemoved(int displayId) {
330a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            if (displayId == mDisplay.getDisplayId()) {
331a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                handleDisplayRemoved();
332a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            }
333a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
334a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
335a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        @Override
336a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        public void onDisplayChanged(int displayId) {
337a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            if (displayId == mDisplay.getDisplayId()) {
338a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                handleDisplayChanged();
339a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            }
340a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
341a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    };
342a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
343a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    private final Handler mHandler = new Handler() {
344a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        @Override
345a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        public void handleMessage(Message msg) {
346a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            switch (msg.what) {
347a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                case MSG_CANCEL:
348a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                    cancel();
349a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                    break;
350a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            }
351a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
352a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    };
353a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown}
354