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