10debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski/*
20debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * Copyright (C) 2012 The Android Open Source Project
30debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski *
40debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
50debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * you may not use this file except in compliance with the License.
60debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * You may obtain a copy of the License at
70debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski *
80debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
90debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski *
100debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * Unless required by applicable law or agreed to in writing, software
110debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
120debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * See the License for the specific language governing permissions and
140debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * limitations under the License.
150debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski */
160debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski
170debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinskipackage android.app;
180debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski
1953ab92d89069fb0178ba98eb641a6fc87145543aAdam Lesinskiimport android.content.Context;
20cf76872a62075abf9008e99ca08413fb70761dc2Amith Yamasaniimport android.content.res.Resources;
21cf76872a62075abf9008e99ca08413fb70761dc2Amith Yamasaniimport android.hardware.display.DisplayManager;
220debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinskiimport android.hardware.display.DisplayManager.DisplayListener;
23cf76872a62075abf9008e99ca08413fb70761dc2Amith Yamasaniimport android.view.ContextThemeWrapper;
247f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinskiimport android.view.Display;
250debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinskiimport android.view.Gravity;
263516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.view.WindowManagerImpl;
27b0ff32245cb6b51e43dd3ee40b86d683c62de2b9Amith Yamasaniimport android.os.Handler;
280debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinskiimport android.os.Message;
290debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinskiimport android.util.DisplayMetrics;
30b0ff32245cb6b51e43dd3ee40b86d683c62de2b9Amith Yamasaniimport android.util.Log;
31e4a8da8ea241858b52d8122480316db79582c44dAmith Yamasaniimport android.util.TypedValue;
323c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski
330debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski/**
3437a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani * Base class for presentations.
350debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * <p>
363c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski * A presentation is a special kind of dialog whose purpose is to present
373c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski * content on a secondary display.  A {@link Presentation} is associated with
384a503b1ece485d44c15eb02ec2bcd464b46e6f7fDianne Hackborn * the target {@link Display} at creation time and configures its context and
39cf76872a62075abf9008e99ca08413fb70761dc2Amith Yamasani * resource configuration according to the display's metrics.
4053ab92d89069fb0178ba98eb641a6fc87145543aAdam Lesinski * </p><p>
413516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * Notably, the {@link Context} of a presentation is different from the context
423c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski * of its containing {@link Activity}.  It is important to inflate the layout
437f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski * of a presentation and load other resources using the presentation's own context
44b0ff32245cb6b51e43dd3ee40b86d683c62de2b9Amith Yamasani * to ensure that assets of the correct size and density for the target display
4506bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani * are loaded.
467cc902bea78dd16488d367e8ed0ccf25d4d825c2Wenchao Tong * </p><p>
4715e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani * A presentation is automatically canceled (see {@link Dialog#cancel()}) when
486776849dc5ff851a225745393f082b702754e278Amith Yamasani * the display to which it is attached is removed.  An activity should take
490debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * care of pausing and resuming whatever content is playing within the presentation
500debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * whenever the activity itself is paused or resumed.
510debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * </p>
5206bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani *
530debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * <h3>Choosing a presentation display</h3>
540debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * <p>
55520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani * Before showing a {@link Presentation} it's important to choose the {@link Display}
567eb599b267d00cbde891c0a87924f2f5086f4497Jeff Hao * on which it will appear.  Choosing a presentation display is sometimes difficult
577f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski * because there may be multiple displays attached.  Rather than trying to guess
5806bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani * which display is best, an application should let the system choose a suitable
5937a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski * presentation display.
603c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski * </p><p>
613c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski * There are two main ways to choose a {@link Display}.
62b0ff32245cb6b51e43dd3ee40b86d683c62de2b9Amith Yamasani * </p>
63b4b9ca7580c75f07330e5222cbd9ccc93b12935eZach Johnson *
640debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * <h4>Using the media router to choose a presentation display</h4>
6506bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani * <p>
66a6232df053cdc2df9d8a1d97a5c81d55cce7a1e2Adam Lesinski * The easiest way to choose a presentation display is to use the
670debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * {@link android.media.MediaRouter MediaRouter} API.  The media router service keeps
683c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski * track of which audio and video routes are available on the system.
694a503b1ece485d44c15eb02ec2bcd464b46e6f7fDianne Hackborn * The media router sends notifications whenever routes are selected or unselected
70a6232df053cdc2df9d8a1d97a5c81d55cce7a1e2Adam Lesinski * or when the preferred presentation display of a route changes.
7106bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani * So an application can simply watch for these notifications and show or dismiss
723c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski * a presentation on the preferred presentation display automatically.
730a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani * </p><p>
746776849dc5ff851a225745393f082b702754e278Amith Yamasani * The preferred presentation display is the display that the media router recommends
750debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * that the application should use if it wants to show content on the secondary display.
7637a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani * Sometimes there may not be a preferred presentation display in which
771bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski * case the application should show its content locally without using a presentation.
780debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * </p><p>
790debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * Here's how to use the media router to create and show a presentation on the preferred
8006bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani * presentation display using {@link android.media.MediaRouter.RouteInfo#getPresentationDisplay()}.
810debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * </p>
821bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski * <pre>
8306bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani * MediaRouter mediaRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
8406bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani * MediaRouter.RouteInfo route = mediaRouter.getSelectedRoute();
8506bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani * if (route != null) {
861bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski *     Display presentationDisplay = route.getPresentationDisplay();
87b0ff32245cb6b51e43dd3ee40b86d683c62de2b9Amith Yamasani *     if (presentationDisplay != null) {
883c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski *         Presentation presentation = new MyPresentation(context, presentationDisplay);
893c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski *         presentation.show();
900debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski *     }
913516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * }</pre>
923516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * <p>
933516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * The following sample code from <code>ApiDemos</code> demonstrates how to use the media
943516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * router to automatically switch between showing content in the main activity and showing
953c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski * the content in a presentation when a presentation display is available.
963c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski * </p>
9706bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/PresentationWithMediaRouterActivity.java
980debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski *      activity}
990debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski *
100af575b9f8e1b59be9c8862b6a65c0dcb88145a23Amith Yamasani * <h4>Using the display manager to choose a presentation display</h4>
1016776849dc5ff851a225745393f082b702754e278Amith Yamasani * <p>
1020a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani * Another way to choose a presentation display is to use the {@link DisplayManager} API
1030debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * directly.  The display manager service provides functions to enumerate and describe all
104520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani * displays that are attached to the system including displays that may be used
1050debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * for presentations.
106af575b9f8e1b59be9c8862b6a65c0dcb88145a23Amith Yamasani * </p><p>
10766143fa5b34eea7413335111838fb692987b611aAdam Lesinski * The display manager keeps track of all displays in the system.  However, not all
108520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani * displays are appropriate for showing presentations.  For example, if an activity
109a6232df053cdc2df9d8a1d97a5c81d55cce7a1e2Adam Lesinski * attempted to show a presentation on the main display it might obscure its own content
110a6232df053cdc2df9d8a1d97a5c81d55cce7a1e2Adam Lesinski * (it's like opening a dialog on top of your activity).
111a6232df053cdc2df9d8a1d97a5c81d55cce7a1e2Adam Lesinski * </p><p>
112a6232df053cdc2df9d8a1d97a5c81d55cce7a1e2Adam Lesinski * Here's how to identify suitable displays for showing presentations using
113a6232df053cdc2df9d8a1d97a5c81d55cce7a1e2Adam Lesinski * {@link DisplayManager#getDisplays(String)} and the
1140debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * {@link DisplayManager#DISPLAY_CATEGORY_PRESENTATION} category.
1150debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * </p>
1160debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * <pre>
1170debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * DisplayManager displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
1183c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski * Display[] presentationDisplays = displayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION);
119b0ff32245cb6b51e43dd3ee40b86d683c62de2b9Amith Yamasani * if (presentationDisplays.length > 0) {
12006bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani *     // If there is more than one suitable presentation display, then we could consider
12115e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani *     // giving the user a choice.  For this example, we simply choose the first display
122520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani *     // which is the one the system recommends as the preferred presentation display.
123520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani *     Display display = presentationDisplays[0];
12437a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani *     Presentation presentation = new MyPresentation(context, presentationDisplay);
1258dca36dc8a5d17315775ce216689addc5bd9be00Xiaohui Chen *     presentation.show();
1260debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * }</pre>
1273c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski * <p>
1280debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * The following sample code from <code>ApiDemos</code> demonstrates how to use the display
1290debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * manager to enumerate displays and show content on multiple presentation displays
1303c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski * simultaneously.
131e4a8da8ea241858b52d8122480316db79582c44dAmith Yamasani * </p>
13206bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/PresentationActivity.java
13306bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani *      activity}
134520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani *
1356776849dc5ff851a225745393f082b702754e278Amith Yamasani * @see android.media.MediaRouter#ROUTE_TYPE_LIVE_VIDEO for information on about live
1360debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski * video routes and how to obtain the preferred presentation display for the
1373c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski * current media route.
1383c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski * @see DisplayManager for information on how to enumerate displays and receive
13937a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski * notifications when displays are added or removed.
14037a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski */
141520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasanipublic class Presentation extends Dialog {
14292617036fcc9b25378c8448c923d6346a012346bDianne Hackborn    private static final String TAG = "Presentation";
14315e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani
14406bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani    private static final int MSG_CANCEL = 1;
145520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani
146a6232df053cdc2df9d8a1d97a5c81d55cce7a1e2Adam Lesinski    private final Display mDisplay;
14706bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani    private final DisplayManager mDisplayManager;
14806bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani
149b0ff32245cb6b51e43dd3ee40b86d683c62de2b9Amith Yamasani    /**
1500a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani     * Creates a new presentation that is attached to the specified display
1510a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani     * using the default theme.
1520a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani     *
153b0ff32245cb6b51e43dd3ee40b86d683c62de2b9Amith Yamasani     * @param outerContext The context of the application that is showing the presentation.
154b0ff32245cb6b51e43dd3ee40b86d683c62de2b9Amith Yamasani     * The presentation will create its own context (see {@link #getContext()}) based
155b0ff32245cb6b51e43dd3ee40b86d683c62de2b9Amith Yamasani     * on this context and information about the associated display.
1560debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski     * @param display The display to which the presentation should be attached.
1570debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski     */
1580debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski    public Presentation(Context outerContext, Display display) {
1590debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski        this(outerContext, display, 0);
1600debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski    }
1610debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski
1620debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski    /**
1633c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski     * Creates a new presentation that is attached to the specified display
16415e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani     * using the optionally specified theme.
1650debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski     *
1660debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski     * @param outerContext The context of the application that is showing the presentation.
1670debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski     * The presentation will create its own context (see {@link #getContext()}) based
1683c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski     * on this context and information about the associated display.
1693c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski     * @param display The display to which the presentation should be attached.
1703c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski     * @param theme A style resource describing the theme to use for the window.
1713c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski     * See <a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">
1723c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski     * Style and Theme Resources</a> for more information about defining and using
1733c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski     * styles.  This theme is applied on top of the current theme in
1743c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski     * <var>outerContext</var>.  If 0, the default presentation theme will be used.
17515e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani     */
17615e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani    public Presentation(Context outerContext, Display display, int theme) {
17715e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani        super(createPresentationContext(outerContext, display, theme), theme, false);
17815e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani
1790debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski        mDisplay = display;
18092617036fcc9b25378c8448c923d6346a012346bDianne Hackborn        mDisplayManager = (DisplayManager)getContext().getSystemService(Context.DISPLAY_SERVICE);
18192617036fcc9b25378c8448c923d6346a012346bDianne Hackborn
18292617036fcc9b25378c8448c923d6346a012346bDianne Hackborn        getWindow().setGravity(Gravity.FILL);
18392617036fcc9b25378c8448c923d6346a012346bDianne Hackborn        setCanceledOnTouchOutside(false);
18492617036fcc9b25378c8448c923d6346a012346bDianne Hackborn    }
18592617036fcc9b25378c8448c923d6346a012346bDianne Hackborn
18692617036fcc9b25378c8448c923d6346a012346bDianne Hackborn    /**
18792617036fcc9b25378c8448c923d6346a012346bDianne Hackborn     * Gets the {@link Display} that this presentation appears on.
18892617036fcc9b25378c8448c923d6346a012346bDianne Hackborn     *
1890debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski     * @return The display.
1903c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski     */
1910debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski    public Display getDisplay() {
1920debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski        return mDisplay;
19337a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski    }
19437a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski
195a6232df053cdc2df9d8a1d97a5c81d55cce7a1e2Adam Lesinski    /**
1960debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski     * Gets the {@link Resources} that should be used to inflate the layout of this presentation.
1970debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski     * This resources object has been configured according to the metrics of the
1980debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski     * display that the presentation appears on.
1990debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski     *
200b0ff32245cb6b51e43dd3ee40b86d683c62de2b9Amith Yamasani     * @return The presentation resources object.
201b0ff32245cb6b51e43dd3ee40b86d683c62de2b9Amith Yamasani     */
202b0ff32245cb6b51e43dd3ee40b86d683c62de2b9Amith Yamasani    public Resources getResources() {
203b0ff32245cb6b51e43dd3ee40b86d683c62de2b9Amith Yamasani        return getContext().getResources();
204a6232df053cdc2df9d8a1d97a5c81d55cce7a1e2Adam Lesinski    }
205a6232df053cdc2df9d8a1d97a5c81d55cce7a1e2Adam Lesinski
206a6232df053cdc2df9d8a1d97a5c81d55cce7a1e2Adam Lesinski    @Override
207a6232df053cdc2df9d8a1d97a5c81d55cce7a1e2Adam Lesinski    protected void onStart() {
208e4a8da8ea241858b52d8122480316db79582c44dAmith Yamasani        super.onStart();
20906bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani        mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
2101958e5e7870579337f1d1d3e6c6fae096ba3abb9Dianne Hackborn
2116776849dc5ff851a225745393f082b702754e278Amith Yamasani        // Since we were not watching for display changes until just now, there is a
2126776849dc5ff851a225745393f082b702754e278Amith Yamasani        // chance that the display metrics have changed.  If so, we will need to
21306bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani        // dismiss the presentation immediately.  This case is expected
21406bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani        // to be rare but surprising, so we'll write a log message about it.
215520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani        if (!isConfigurationStillValid()) {
216520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani            Log.i(TAG, "Presentation is being dismissed because the "
21706bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani                    + "display metrics have changed since it was created.");
21806bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani            mHandler.sendEmptyMessage(MSG_CANCEL);
21906bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani        }
22006bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani    }
22106bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani
22206bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani    @Override
22306bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani    protected void onStop() {
22406bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani        mDisplayManager.unregisterDisplayListener(mDisplayListener);
22515e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani        super.onStop();
22615e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani    }
227b0ff32245cb6b51e43dd3ee40b86d683c62de2b9Amith Yamasani
228b0ff32245cb6b51e43dd3ee40b86d683c62de2b9Amith Yamasani    /**
229b0ff32245cb6b51e43dd3ee40b86d683c62de2b9Amith Yamasani     * Inherited from {@link Dialog#show}. Will throw
23015e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani     * {@link android.view.WindowManager.InvalidDisplayException} if the specified secondary
2313c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski     * {@link Display} can't be found.
2323c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski     */
2333c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski    @Override
23415e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani    public void show() {
23515e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani        super.show();
2363c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski    }
2373c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski
2383c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski    /**
23915e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani     * Called by the system when the {@link Display} to which the presentation
24015e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani     * is attached has been removed.
2416776849dc5ff851a225745393f082b702754e278Amith Yamasani     *
24215e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani     * The system automatically calls {@link #cancel} to dismiss the presentation
24315e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani     * after sending this event.
24415e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani     *
24515e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani     * @see #getDisplay
24615e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani     */
24715e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani    public void onDisplayRemoved() {
24815e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani    }
24915e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani
25015e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani    /**
25115e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani     * Called by the system when the properties of the {@link Display} to which
25215e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani     * the presentation is attached have changed.
25315e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani     *
254520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani     * If the display metrics have changed (for example, if the display has been
255520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani     * resized or rotated), then the system automatically calls
2560debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski     * {@link #cancel} to dismiss the presentation.
2570debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski     *
2583c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski     * @see #getDisplay
2590debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski     */
26006bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani    public void onDisplayChanged() {
26106bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani    }
26206bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani
26306bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani    private void handleDisplayRemoved() {
26406bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani        onDisplayRemoved();
26506bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani        cancel();
26606bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani    }
26706bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani
26806bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani    private void handleDisplayChanged() {
26906bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani        onDisplayChanged();
27006bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani
27106bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani        // We currently do not support configuration changes for presentations
27206bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani        // (although we could add that feature with a bit more work).
27306bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani        // If the display metrics have changed in any way then the current configuration
27406bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani        // is invalid and the application must recreate the presentation to get
27506bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani        // a new context.
27606bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani        if (!isConfigurationStillValid()) {
27706bf824628c118fbd5ad6756913d7fd63a6f4ce5Amith Yamasani            Log.i(TAG, "Presentation is being dismissed because the "
2783c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski                    + "display metrics have changed since it was created.");
2793c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski            cancel();
2803c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski        }
2813c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski    }
2820debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski
2833c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski    private boolean isConfigurationStillValid() {
2843c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski        DisplayMetrics dm = new DisplayMetrics();
2853c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski        mDisplay.getMetrics(dm);
2863c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski        return dm.equalsPhysical(getResources().getDisplayMetrics());
2870debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski    }
2880debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski
2893c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski    private static Context createPresentationContext(
2903c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski            Context outerContext, Display display, int theme) {
2913c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski        if (outerContext == null) {
2923c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski            throw new IllegalArgumentException("outerContext must not be null");
2933c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski        }
2940debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski        if (display == null) {
2950debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski            throw new IllegalArgumentException("display must not be null");
2963c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski        }
2973c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski
2983c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski        Context displayContext = outerContext.createDisplayContext(display);
2993c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski        if (theme == 0) {
3003c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski            TypedValue outValue = new TypedValue();
3013c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski            displayContext.getTheme().resolveAttribute(
3020debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski                    com.android.internal.R.attr.presentationTheme, outValue, true);
3030debc9aff4c0cbc28e083a948081d91b0f171319Adam Lesinski            theme = outValue.resourceId;
3043c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski        }
3053c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski
3063c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski        // Derive the display's window manager from the outer window manager.
3073c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski        // We do this because the outer window manager have some extra information
3083c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski        // such as the parent window, which is important if the presentation uses
3093c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski        // an application window type.
310520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani        final WindowManagerImpl outerWindowManager =
31115e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani                (WindowManagerImpl)outerContext.getSystemService(Context.WINDOW_SERVICE);
31215e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani        final WindowManagerImpl displayWindowManager =
31315e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani                outerWindowManager.createPresentationWindowManager(display);
31415e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani        return new ContextThemeWrapper(displayContext, theme) {
315520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani            @Override
316520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani            public Object getSystemService(String name) {
317520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani                if (Context.WINDOW_SERVICE.equals(name)) {
318520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani                    return displayWindowManager;
319520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani                }
3208dca36dc8a5d17315775ce216689addc5bd9be00Xiaohui Chen                return super.getSystemService(name);
32115e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani            }
32215e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani        };
32315e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani    }
32415e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani
325520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani    private final DisplayListener mDisplayListener = new DisplayListener() {
326520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani        @Override
327520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani        public void onDisplayAdded(int displayId) {
328520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani        }
329520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani
330520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani        @Override
331a6232df053cdc2df9d8a1d97a5c81d55cce7a1e2Adam Lesinski        public void onDisplayRemoved(int displayId) {
332520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani            if (displayId == mDisplay.getDisplayId()) {
333520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani                handleDisplayRemoved();
334520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani            }
335520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani        }
336520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani
337520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani        @Override
338520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani        public void onDisplayChanged(int displayId) {
339520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani            if (displayId == mDisplay.getDisplayId()) {
340520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani                handleDisplayChanged();
341520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani            }
342a6232df053cdc2df9d8a1d97a5c81d55cce7a1e2Adam Lesinski        }
343520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani    };
344520d8f2ac6ad2c3cd244e1f710103b3a43a41725Amith Yamasani
3458dca36dc8a5d17315775ce216689addc5bd9be00Xiaohui Chen    private final Handler mHandler = new Handler() {
3468dca36dc8a5d17315775ce216689addc5bd9be00Xiaohui Chen        @Override
3478dca36dc8a5d17315775ce216689addc5bd9be00Xiaohui Chen        public void handleMessage(Message msg) {
3488dca36dc8a5d17315775ce216689addc5bd9be00Xiaohui Chen            switch (msg.what) {
3498dca36dc8a5d17315775ce216689addc5bd9be00Xiaohui Chen                case MSG_CANCEL:
3508dca36dc8a5d17315775ce216689addc5bd9be00Xiaohui Chen                    cancel();
3516776849dc5ff851a225745393f082b702754e278Amith Yamasani                    break;
3526776849dc5ff851a225745393f082b702754e278Amith Yamasani            }
35315e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani        }
35415e47235c055495ec0ccc24768a6746a960d3a61Amith Yamasani    };
3556776849dc5ff851a225745393f082b702754e278Amith Yamasani}
3566776849dc5ff851a225745393f082b702754e278Amith Yamasani