diff options
author | Jeff Brown <jeffbrown@google.com> | 2012-08-23 19:48:44 -0700 |
---|---|---|
committer | Jeff Brown <jeffbrown@google.com> | 2012-08-31 15:42:45 -0700 |
commit | a492c3a7b2c18426fd0cb4d017eacbc368195dc5 (patch) | |
tree | 67744a8d91519d997cb761a697600041d74165fa | |
parent | 00453e7a0182b50cf01e65c97650b526284fe084 (diff) | |
download | frameworks_base-a492c3a7b2c18426fd0cb4d017eacbc368195dc5.zip frameworks_base-a492c3a7b2c18426fd0cb4d017eacbc368195dc5.tar.gz frameworks_base-a492c3a7b2c18426fd0cb4d017eacbc368195dc5.tar.bz2 |
Initial draft of high-level multi-display APIs.
This patch introduces the ability to create a Context that
is bound to a Display. The context gets its configuration and
metrics from that display and is able to provide a WindowManager
that is bound to the display.
To make it easier to use, we also add a new kind of Dialog
called a Presentation. Presentation takes care of setting
up the context as needed and watches for significant changes
in the display configuration. If the display is removed,
then the presentation simply dismisses itself.
Change-Id: Idc54b4ec84b1ff91505cfb78910cf8cd09696d7d
21 files changed, 600 insertions, 93 deletions
diff --git a/api/current.txt b/api/current.txt index 31d0c46..7ffb9e5 100644 --- a/api/current.txt +++ b/api/current.txt @@ -773,6 +773,7 @@ package android { field public static final int preferenceLayoutChild = 16842900; // 0x1010094 field public static final int preferenceScreenStyle = 16842891; // 0x101008b field public static final int preferenceStyle = 16842894; // 0x101008e + field public static final int presentationTheme = 16843712; // 0x10103c0 field public static final int previewImage = 16843482; // 0x10102da field public static final int priority = 16842780; // 0x101001c field public static final int privateImeOptions = 16843299; // 0x1010223 @@ -3901,6 +3902,15 @@ package android.app { method public abstract void onSendFinished(android.app.PendingIntent, android.content.Intent, int, java.lang.String, android.os.Bundle); } + public class Presentation extends android.app.Dialog { + ctor public Presentation(android.content.Context, android.view.Display); + ctor public Presentation(android.content.Context, android.view.Display, int); + method public android.view.Display getDisplay(); + method public android.content.res.Resources getResources(); + method public void onDisplayChanged(); + method public void onDisplayRemoved(); + } + public class ProgressDialog extends android.app.AlertDialog { ctor public ProgressDialog(android.content.Context); ctor public ProgressDialog(android.content.Context, int); @@ -5268,6 +5278,7 @@ package android.content { method public abstract int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int); method public abstract deprecated void clearWallpaper() throws java.io.IOException; method public abstract android.content.Context createConfigurationContext(android.content.res.Configuration); + method public abstract android.content.Context createDisplayContext(android.view.Display); method public abstract android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract java.lang.String[] databaseList(); method public abstract boolean deleteDatabase(java.lang.String); @@ -5417,6 +5428,7 @@ package android.content { method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int); method public void clearWallpaper() throws java.io.IOException; method public android.content.Context createConfigurationContext(android.content.res.Configuration); + method public android.content.Context createDisplayContext(android.view.Display); method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public java.lang.String[] databaseList(); method public boolean deleteDatabase(java.lang.String); @@ -21228,6 +21240,7 @@ package android.test.mock { method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int); method public void clearWallpaper(); method public android.content.Context createConfigurationContext(android.content.res.Configuration); + method public android.content.Context createDisplayContext(android.view.Display); method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public java.lang.String[] databaseList(); method public boolean deleteDatabase(java.lang.String); @@ -22911,6 +22924,7 @@ package android.util { public class DisplayMetrics { ctor public DisplayMetrics(); + method public boolean equals(android.util.DisplayMetrics); method public void setTo(android.util.DisplayMetrics); method public void setToDefaults(); field public static final int DENSITY_DEFAULT = 160; // 0xa0 diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 4a1bf75..1b788c2 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -203,7 +203,7 @@ public final class ActivityThread { = new HashMap<String, WeakReference<LoadedApk>>(); final HashMap<String, WeakReference<LoadedApk>> mResourcePackages = new HashMap<String, WeakReference<LoadedApk>>(); - final HashMap<CompatibilityInfo, DisplayMetrics> mDisplayMetrics + final HashMap<CompatibilityInfo, DisplayMetrics> mDefaultDisplayMetrics = new HashMap<CompatibilityInfo, DisplayMetrics>(); final HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources = new HashMap<ResourcesKey, WeakReference<Resources> >(); @@ -1475,12 +1475,14 @@ public final class ActivityThread { private static class ResourcesKey { final private String mResDir; + final private int mDisplayId; final private Configuration mOverrideConfiguration; final private float mScale; final private int mHash; - ResourcesKey(String resDir, Configuration overrideConfiguration, float scale) { + ResourcesKey(String resDir, int displayId, Configuration overrideConfiguration, float scale) { mResDir = resDir; + mDisplayId = displayId; if (overrideConfiguration != null) { if (Configuration.EMPTY.equals(overrideConfiguration)) { overrideConfiguration = null; @@ -1490,6 +1492,7 @@ public final class ActivityThread { mScale = scale; int hash = 17; hash = 31 * hash + mResDir.hashCode(); + hash = 31 * hash + mDisplayId; hash = 31 * hash + (mOverrideConfiguration != null ? mOverrideConfiguration.hashCode() : 0); hash = 31 * hash + Float.floatToIntBits(mScale); @@ -1510,6 +1513,9 @@ public final class ActivityThread { if (!mResDir.equals(peer.mResDir)) { return false; } + if (mDisplayId != peer.mDisplayId) { + return false; + } if (mOverrideConfiguration != peer.mOverrideConfiguration) { if (mOverrideConfiguration == null || peer.mOverrideConfiguration == null) { return false; @@ -1552,28 +1558,32 @@ public final class ActivityThread { return sPackageManager; } - DisplayMetrics getDisplayMetricsLocked(CompatibilityInfo ci, boolean forceUpdate) { - DisplayMetrics dm = mDisplayMetrics.get(ci); - if (dm != null && !forceUpdate) { + private void flushDisplayMetricsLocked() { + mDefaultDisplayMetrics.clear(); + } + + DisplayMetrics getDisplayMetricsLocked(int displayId, CompatibilityInfo ci) { + boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY); + DisplayMetrics dm = isDefaultDisplay ? mDefaultDisplayMetrics.get(ci) : null; + if (dm != null) { return dm; } + dm = new DisplayMetrics(); DisplayManagerGlobal displayManager = DisplayManagerGlobal.getInstance(); if (displayManager == null) { // may be null early in system startup - dm = new DisplayMetrics(); dm.setToDefaults(); return dm; } - if (dm == null) { - dm = new DisplayMetrics(); - mDisplayMetrics.put(ci, dm); + if (isDefaultDisplay) { + mDefaultDisplayMetrics.put(ci, dm); } CompatibilityInfoHolder cih = new CompatibilityInfoHolder(); cih.set(ci); - Display d = displayManager.getCompatibleDisplay(Display.DEFAULT_DISPLAY, cih); + Display d = displayManager.getCompatibleDisplay(displayId, cih); d.getMetrics(dm); //Slog.i("foo", "New metrics: w=" + metrics.widthPixels + " h=" // + metrics.heightPixels + " den=" + metrics.density @@ -1602,9 +1612,11 @@ public final class ActivityThread { * @param compInfo the compability info. It will use the default compatibility info when it's * null. */ - Resources getTopLevelResources(String resDir, Configuration overrideConfiguration, + Resources getTopLevelResources(String resDir, + int displayId, Configuration overrideConfiguration, CompatibilityInfo compInfo) { - ResourcesKey key = new ResourcesKey(resDir, overrideConfiguration, + ResourcesKey key = new ResourcesKey(resDir, + displayId, overrideConfiguration, compInfo.applicationScale); Resources r; synchronized (mPackages) { @@ -1636,15 +1648,21 @@ public final class ActivityThread { } //Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics); - DisplayMetrics metrics = getDisplayMetricsLocked(null, false); + DisplayMetrics dm = getDisplayMetricsLocked(displayId, null); Configuration config; - if (key.mOverrideConfiguration != null) { + boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY); + if (!isDefaultDisplay || key.mOverrideConfiguration != null) { config = new Configuration(getConfiguration()); - config.updateFrom(key.mOverrideConfiguration); + if (!isDefaultDisplay) { + applyNonDefaultDisplayMetricsToConfigurationLocked(dm, config); + } + if (key.mOverrideConfiguration != null) { + config.updateFrom(key.mOverrideConfiguration); + } } else { config = getConfiguration(); } - r = new Resources(assets, metrics, config, compInfo); + r = new Resources(assets, dm, config, compInfo); if (false) { Slog.i(TAG, "Created app resources " + resDir + " " + r + ": " + r.getConfiguration() + " appScale=" @@ -1670,9 +1688,10 @@ public final class ActivityThread { /** * Creates the top level resources for the given package. */ - Resources getTopLevelResources(String resDir, Configuration overrideConfiguration, + Resources getTopLevelResources(String resDir, + int displayId, Configuration overrideConfiguration, LoadedApk pkgInfo) { - return getTopLevelResources(resDir, overrideConfiguration, + return getTopLevelResources(resDir, displayId, overrideConfiguration, pkgInfo.mCompatibilityInfo.get()); } @@ -1844,7 +1863,8 @@ public final class ActivityThread { context.init(info, null, this); context.getResources().updateConfiguration( getConfiguration(), getDisplayMetricsLocked( - CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, false)); + Display.DEFAULT_DISPLAY, + CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)); mSystemContext = context; //Slog.i(TAG, "Created system resources " + context.getResources() // + ": " + context.getResources().getConfiguration()); @@ -3707,7 +3727,9 @@ public final class ActivityThread { return false; } int changes = mResConfiguration.updateFrom(config); - DisplayMetrics dm = getDisplayMetricsLocked(null, true); + flushDisplayMetricsLocked(); + DisplayMetrics defaultDisplayMetrics = getDisplayMetricsLocked( + Display.DEFAULT_DISPLAY, null); if (compat != null && (mResCompatibilityInfo == null || !mResCompatibilityInfo.equals(compat))) { @@ -3722,7 +3744,7 @@ public final class ActivityThread { Locale.setDefault(config.locale); } - Resources.updateSystemConfiguration(config, dm, compat); + Resources.updateSystemConfiguration(config, defaultDisplayMetrics, compat); ApplicationPackageManager.configurationChanged(); //Slog.i(TAG, "Configuration changed in " + currentPackageName()); @@ -3737,13 +3759,22 @@ public final class ActivityThread { if (r != null) { if (DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources " + r + " config to: " + config); - Configuration override = entry.getKey().mOverrideConfiguration; - if (override != null) { + int displayId = entry.getKey().mDisplayId; + boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY); + DisplayMetrics dm = defaultDisplayMetrics; + Configuration overrideConfig = entry.getKey().mOverrideConfiguration; + if (!isDefaultDisplay || overrideConfig != null) { if (tmpConfig == null) { tmpConfig = new Configuration(); } tmpConfig.setTo(config); - tmpConfig.updateFrom(override); + if (!isDefaultDisplay) { + dm = getDisplayMetricsLocked(displayId, null); + applyNonDefaultDisplayMetricsToConfigurationLocked(dm, tmpConfig); + } + if (overrideConfig != null) { + tmpConfig.updateFrom(overrideConfig); + } r.updateConfiguration(tmpConfig, dm, compat); } else { r.updateConfiguration(config, dm, compat); @@ -3759,6 +3790,22 @@ public final class ActivityThread { return changes != 0; } + final void applyNonDefaultDisplayMetricsToConfigurationLocked( + DisplayMetrics dm, Configuration config) { + config.screenLayout = Configuration.SCREENLAYOUT_SIZE_XLARGE + | Configuration.SCREENLAYOUT_LONG_NO; + config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH; + config.orientation = (dm.widthPixels >= dm.heightPixels) ? + Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT; + config.densityDpi = dm.densityDpi; + config.screenWidthDp = (int)(dm.widthPixels / dm.density); + config.screenHeightDp = (int)(dm.heightPixels / dm.density); + config.smallestScreenWidthDp = config.screenWidthDp; // assume screen does not rotate + config.compatScreenWidthDp = config.screenWidthDp; + config.compatScreenHeightDp = config.screenHeightDp; + config.compatSmallestScreenWidthDp = config.smallestScreenWidthDp; + } + final Configuration applyCompatConfiguration(int displayDensity) { Configuration config = mConfiguration; if (mCompatConfiguration == null) { diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java index 7809e73..6ab2bd1 100644 --- a/core/java/android/app/AlertDialog.java +++ b/core/java/android/app/AlertDialog.java @@ -110,8 +110,9 @@ public class AlertDialog extends Dialog implements DialogInterface { this(context, theme, true); } - AlertDialog(Context context, int theme, boolean createContextWrapper) { - super(context, resolveDialogTheme(context, theme), createContextWrapper); + AlertDialog(Context context, int theme, boolean createThemeContextWrapper) { + super(context, resolveDialogTheme(context, theme), createThemeContextWrapper); + mWindow.alwaysReadCloseOnTouchAttr(); mAlert = new AlertController(getContext(), this, getWindow()); } diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 91753aa..c4f1371 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -54,6 +54,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.util.Log; +import android.view.Display; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -722,8 +723,8 @@ final class ApplicationPackageManager extends PackageManager { return mContext.mMainThread.getSystemContext().getResources(); } Resources r = mContext.mMainThread.getTopLevelResources( - app.uid == Process.myUid() ? app.sourceDir - : app.publicSourceDir, null, mContext.mPackageInfo); + app.uid == Process.myUid() ? app.sourceDir : app.publicSourceDir, + Display.DEFAULT_DISPLAY, null, mContext.mPackageInfo); if (r != null) { return r; } diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 1b6f84b..ea77bcd 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -168,6 +168,7 @@ class ContextImpl extends Context { private int mThemeResource = 0; private Resources.Theme mTheme = null; private PackageManager mPackageManager; + private Display mDisplay; // may be null if default display private Context mReceiverRestrictedContext = null; private boolean mRestricted; @@ -502,8 +503,13 @@ class ContextImpl extends Context { registerService(WINDOW_SERVICE, new ServiceFetcher() { public Object getService(ContextImpl ctx) { - return new WindowManagerImpl(ctx.getOuterContext(), - Display.DEFAULT_DISPLAY); + Display display = ctx.mDisplay; + if (display == null) { + DisplayManager dm = (DisplayManager)ctx.getOuterContext().getSystemService( + Context.DISPLAY_SERVICE); + display = dm.getDisplay(Display.DEFAULT_DISPLAY); + } + return new WindowManagerImpl(display); }}); registerService(USER_SERVICE, new ServiceFetcher() { @@ -1676,22 +1682,52 @@ class ContextImpl extends Context { @Override public Context createConfigurationContext(Configuration overrideConfiguration) { + if (overrideConfiguration == null) { + throw new IllegalArgumentException("overrideConfiguration must not be null"); + } + ContextImpl c = new ContextImpl(); c.init(mPackageInfo, null, mMainThread); c.mResources = mMainThread.getTopLevelResources( - mPackageInfo.getResDir(), overrideConfiguration, + mPackageInfo.getResDir(), + getDisplayId(), overrideConfiguration, mResources.getCompatibilityInfo()); return c; } @Override + public Context createDisplayContext(Display display) { + if (display == null) { + throw new IllegalArgumentException("display must not be null"); + } + + int displayId = display.getDisplayId(); + CompatibilityInfo ci = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO; + CompatibilityInfoHolder cih = getCompatibilityInfo(displayId); + if (cih != null) { + ci = cih.get(); + } + + ContextImpl context = new ContextImpl(); + context.init(mPackageInfo, null, mMainThread); + context.mDisplay = display; + context.mResources = mMainThread.getTopLevelResources( + mPackageInfo.getResDir(), displayId, null, ci); + return context; + } + + private int getDisplayId() { + return mDisplay != null ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY; + } + + @Override public boolean isRestricted() { return mRestricted; } @Override - public CompatibilityInfoHolder getCompatibilityInfo() { - return mPackageInfo.mCompatibilityInfo; + public CompatibilityInfoHolder getCompatibilityInfo(int displayId) { + return displayId == Display.DEFAULT_DISPLAY ? mPackageInfo.mCompatibilityInfo : null; } private File getDataDirFile() { @@ -1735,6 +1771,7 @@ class ContextImpl extends Context { mResources = context.mResources; mMainThread = context.mMainThread; mContentResolver = context.mContentResolver; + mDisplay = context.mDisplay; mOuterContext = this; } @@ -1758,7 +1795,8 @@ class ContextImpl extends Context { " compatiblity info:" + container.getDisplayMetrics()); } mResources = mainThread.getTopLevelResources( - mPackageInfo.getResDir(), null, container.getCompatibilityInfo()); + mPackageInfo.getResDir(), Display.DEFAULT_DISPLAY, + null, container.getCompatibilityInfo()); } mMainThread = mainThread; mContentResolver = new ApplicationContentResolver(this, mainThread); diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java index 16112cb..b3d99c5 100644 --- a/core/java/android/app/Dialog.java +++ b/core/java/android/app/Dialog.java @@ -147,15 +147,19 @@ public class Dialog implements DialogInterface, Window.Callback, this(context, theme, true); } - Dialog(Context context, int theme, boolean createContextWrapper) { - if (theme == 0) { - TypedValue outValue = new TypedValue(); - context.getTheme().resolveAttribute(com.android.internal.R.attr.dialogTheme, - outValue, true); - theme = outValue.resourceId; + Dialog(Context context, int theme, boolean createContextThemeWrapper) { + if (createContextThemeWrapper) { + if (theme == 0) { + TypedValue outValue = new TypedValue(); + context.getTheme().resolveAttribute(com.android.internal.R.attr.dialogTheme, + outValue, true); + theme = outValue.resourceId; + } + mContext = new ContextThemeWrapper(context, theme); + } else { + mContext = context; } - mContext = createContextWrapper ? new ContextThemeWrapper(context, theme) : context; mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); Window w = PolicyManager.makeNewWindow(mContext); mWindow = w; @@ -164,7 +168,7 @@ public class Dialog implements DialogInterface, Window.Callback, w.setGravity(Gravity.CENTER); mListenersHandler = new ListenersHandler(this); } - + /** * @deprecated * @hide diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 1e89bb2..6197b1a 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -41,6 +41,7 @@ import android.os.UserHandle; import android.util.AndroidRuntimeException; import android.util.Slog; import android.view.CompatibilityInfoHolder; +import android.view.Display; import java.io.File; import java.io.IOException; @@ -139,7 +140,8 @@ public final class LoadedApk { ContextImpl.createSystemContext(mainThread); ActivityThread.mSystemContext.getResources().updateConfiguration( mainThread.getConfiguration(), - mainThread.getDisplayMetricsLocked(compatInfo, false), + mainThread.getDisplayMetricsLocked( + Display.DEFAULT_DISPLAY, compatInfo), compatInfo); //Slog.i(TAG, "Created system resources " // + mSystemContext.getResources() + ": " @@ -471,7 +473,8 @@ public final class LoadedApk { public Resources getResources(ActivityThread mainThread) { if (mResources == null) { - mResources = mainThread.getTopLevelResources(mResDir, null, this); + mResources = mainThread.getTopLevelResources(mResDir, + Display.DEFAULT_DISPLAY, null, this); } return mResources; } diff --git a/core/java/android/app/Presentation.java b/core/java/android/app/Presentation.java new file mode 100644 index 0000000..eb5a652 --- /dev/null +++ b/core/java/android/app/Presentation.java @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app; + +import android.content.Context; +import android.content.res.Resources; +import android.hardware.display.DisplayManager; +import android.hardware.display.DisplayManager.DisplayListener; +import android.view.ContextThemeWrapper; +import android.view.Display; +import android.view.Gravity; +import android.view.WindowManagerImpl; +import android.os.Handler; +import android.os.Message; +import android.util.DisplayMetrics; +import android.util.Log; +import android.util.TypedValue; + +/** + * Base class for presentations. + * + * A presentation is a special kind of dialog whose purpose is to present + * content on a secondary display. A {@link Presentation} is associated with + * the target {@link Display} at creation time and configures its context and + * resource configuration according to the display's metrics. + * + * Notably, the {@link Context} of a presentation is different from the context + * of its containing {@link Activity}. It is important to inflate the layout + * of a presentation and load other resources using the presentation's own context + * to ensure that assets of the correct size and density for the target display + * are loaded. + * + * A presentation is automatically canceled (see {@link Dialog#cancel()}) when + * the display to which it is attached is removed. An activity should take + * care of pausing and resuming whatever content is playing within the presentation + * whenever the activity itself is paused or resume. + * + * @see {@link DisplayManager} for information on how to enumerate displays. + */ +public class Presentation extends Dialog { + private static final String TAG = "Presentation"; + + private static final int MSG_CANCEL = 1; + + private final Display mDisplay; + private final DisplayManager mDisplayManager; + + /** + * Creates a new presentation that is attached to the specified display + * using the default theme. + * + * @param outerContext The context of the application that is showing the presentation. + * The presentation will create its own context (see {@link #getContext()}) based + * on this context and information about the associated display. + * @param display The display to which the presentation should be attached. + */ + public Presentation(Context outerContext, Display display) { + this(outerContext, display, 0); + } + + /** + * Creates a new presentation that is attached to the specified display + * using the optionally specified theme. + * + * @param outerContext The context of the application that is showing the presentation. + * The presentation will create its own context (see {@link #getContext()}) based + * on this context and information about the associated display. + * @param display The display to which the presentation should be attached. + * @param theme A style resource describing the theme to use for the window. + * See <a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes"> + * Style and Theme Resources</a> for more information about defining and using + * styles. This theme is applied on top of the current theme in + * <var>outerContext</var>. If 0, the default presentation theme will be used. + */ + public Presentation(Context outerContext, Display display, int theme) { + super(createPresentationContext(outerContext, display, theme), theme, false); + + mDisplay = display; + mDisplayManager = (DisplayManager)getContext().getSystemService(Context.DISPLAY_SERVICE); + + getWindow().setGravity(Gravity.FILL); + setCanceledOnTouchOutside(false); + } + + /** + * Gets the {@link Display} that this presentation appears on. + * + * @return The display. + */ + public Display getDisplay() { + return mDisplay; + } + + /** + * Gets the {@link Resources} that should be used to inflate the layout of this presentation. + * This resources object has been configured according to the metrics of the + * display that the presentation appears on. + * + * @return The presentation resources object. + */ + public Resources getResources() { + return getContext().getResources(); + } + + @Override + protected void onStart() { + super.onStart(); + mDisplayManager.registerDisplayListener(mDisplayListener, null); + + // Since we were not watching for display changes until just now, there is a + // chance that the display metrics have changed. If so, we will need to + // dismiss the presentation immediately. This case is expected + // to be rare but surprising, so we'll write a log message about it. + if (!isConfigurationStillValid()) { + Log.i(TAG, "Presentation is being immediately dismissed because the " + + "display metrics have changed since it was created."); + mHandler.sendEmptyMessage(MSG_CANCEL); + } + } + + @Override + protected void onStop() { + mDisplayManager.unregisterDisplayListener(mDisplayListener); + super.onStop(); + } + + /** + * Called by the system when the {@link Display} to which the presentation + * is attached has been removed. + * + * The system automatically calls {@link #cancel} to dismiss the presentation + * after sending this event. + * + * @see #getDisplay + */ + public void onDisplayRemoved() { + } + + /** + * Called by the system when the properties of the {@link Display} to which + * the presentation is attached have changed. + * + * If the display metrics have changed (for example, if the display has been + * resized or rotated), then the system automatically calls + * {@link #cancel} to dismiss the presentation. + * + * @see #getDisplay + */ + public void onDisplayChanged() { + } + + private void handleDisplayRemoved() { + onDisplayRemoved(); + cancel(); + } + + private void handleDisplayChanged() { + onDisplayChanged(); + + // We currently do not support configuration changes for presentations + // (although we could add that feature with a bit more work). + // If the display metrics have changed in any way then the current configuration + // is invalid and the application must recreate the presentation to get + // a new context. + if (!isConfigurationStillValid()) { + cancel(); + } + } + + private boolean isConfigurationStillValid() { + DisplayMetrics dm = new DisplayMetrics(); + mDisplay.getMetrics(dm); + return dm.equals(getResources().getDisplayMetrics()); + } + + private static Context createPresentationContext( + Context outerContext, Display display, int theme) { + if (outerContext == null) { + throw new IllegalArgumentException("outerContext must not be null"); + } + if (display == null) { + throw new IllegalArgumentException("display must not be null"); + } + + Context displayContext = outerContext.createDisplayContext(display); + if (theme == 0) { + TypedValue outValue = new TypedValue(); + displayContext.getTheme().resolveAttribute( + com.android.internal.R.attr.presentationTheme, outValue, true); + theme = outValue.resourceId; + } + + // Derive the display's window manager from the outer window manager. + // We do this because the outer window manager have some extra information + // such as the parent window, which is important if the presentation uses + // an application window type. + final WindowManagerImpl outerWindowManager = + (WindowManagerImpl)outerContext.getSystemService(Context.WINDOW_SERVICE); + final WindowManagerImpl displayWindowManager = + outerWindowManager.createPresentationWindowManager(display); + return new ContextThemeWrapper(displayContext, theme) { + @Override + public Object getSystemService(String name) { + if (Context.WINDOW_SERVICE.equals(name)) { + return displayWindowManager; + } + return super.getSystemService(name); + } + }; + } + + private final DisplayListener mDisplayListener = new DisplayListener() { + @Override + public void onDisplayAdded(int displayId) { + } + + @Override + public void onDisplayRemoved(int displayId) { + if (displayId == mDisplay.getDisplayId()) { + handleDisplayRemoved(); + } + } + + @Override + public void onDisplayChanged(int displayId) { + if (displayId == mDisplay.getDisplayId()) { + handleDisplayChanged(); + } + } + }; + + private final Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_CANCEL: + cancel(); + break; + } + } + }; +} diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index c2b796a..8a4cb44 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -35,6 +35,8 @@ import android.os.Looper; import android.os.UserHandle; import android.util.AttributeSet; import android.view.CompatibilityInfoHolder; +import android.view.Display; +import android.view.WindowManager; import java.io.File; import java.io.FileInputStream; @@ -2547,7 +2549,7 @@ public abstract class Context { /** * Return a new Context object for the current Context but whose resources * are adjusted to match the given Configuration. Each call to this method - * returns a new instance of a Contex object; Context objects are not + * returns a new instance of a Context object; Context objects are not * shared, however common state (ClassLoader, other Resources for the * same configuration) may be so the Context itself can be fairly lightweight. * @@ -2557,19 +2559,40 @@ public abstract class Context { * orientation change), the resources of this context will also change except * for those that have been explicitly overridden with a value here. * - * @return A Context for the application. + * @return A Context with the given configuration override. */ public abstract Context createConfigurationContext(Configuration overrideConfiguration); /** + * Return a new Context object for the current Context but whose resources + * are adjusted to match the metrics of the given Display. Each call to this method + * returns a new instance of a Context object; Context objects are not + * shared, however common state (ClassLoader, other Resources for the + * same configuration) may be so the Context itself can be fairly lightweight. + * + * The returned display Context provides a {@link WindowManager} + * (see {@link #getSystemService(String)}) that is configured to show windows + * on the given display. The WindowManager's {@link WindowManager#getDefaultDisplay} + * method can be used to retrieve the Display from the returned Context. + * + * @param display A {@link Display} object specifying the display + * for whose metrics the Context's resources should be tailored and upon which + * new windows should be shown. + * + * @return A Context for the display. + */ + public abstract Context createDisplayContext(Display display); + + /** * Gets the compatibility info holder for this context. This information * is provided on a per-application basis and is used to simulate lower density * display metrics for legacy applications. * + * @param displayId The display id for which to get compatibility info. * @return The compatibility info holder, or null if not required by the application. * @hide */ - public abstract CompatibilityInfoHolder getCompatibilityInfo(); + public abstract CompatibilityInfoHolder getCompatibilityInfo(int displayId); /** * Indicates whether this Context is restricted. diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index e503388..e8c63d6 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -36,6 +36,7 @@ import android.os.Looper; import android.os.RemoteException; import android.os.UserHandle; import android.view.CompatibilityInfoHolder; +import android.view.Display; import java.io.File; import java.io.FileInputStream; @@ -582,13 +583,18 @@ public class ContextWrapper extends Context { } @Override + public Context createDisplayContext(Display display) { + return mBase.createDisplayContext(display); + } + + @Override public boolean isRestricted() { return mBase.isRestricted(); } /** @hide */ @Override - public CompatibilityInfoHolder getCompatibilityInfo() { - return mBase.getCompatibilityInfo(); + public CompatibilityInfoHolder getCompatibilityInfo(int displayId) { + return mBase.getCompatibilityInfo(displayId); } } diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 74996da..2814301 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -19,7 +19,6 @@ package android.hardware.display; import android.content.Context; import android.os.Handler; import android.util.SparseArray; -import android.view.CompatibilityInfoHolder; import android.view.Display; /** @@ -92,7 +91,7 @@ public final class DisplayManager { Display display = mDisplays.get(displayId); if (display == null) { display = mGlobal.getCompatibleDisplay(displayId, - getCompatibilityInfoForDisplayLocked(displayId)); + mContext.getCompatibilityInfo(displayId)); if (display != null) { mDisplays.put(displayId, display); } @@ -102,14 +101,6 @@ public final class DisplayManager { return display; } - private CompatibilityInfoHolder getCompatibilityInfoForDisplayLocked(int displayId) { - CompatibilityInfoHolder cih = null; - if (displayId == Display.DEFAULT_DISPLAY) { - cih = mContext.getCompatibilityInfo(); - } - return cih; - } - /** * Registers an display listener to receive notifications about when * displays are added, removed or changed. diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java index 506594b..85e4b9d 100644 --- a/core/java/android/util/DisplayMetrics.java +++ b/core/java/android/util/DisplayMetrics.java @@ -206,13 +206,52 @@ public class DisplayMetrics { public void setToDefaults() { widthPixels = 0; heightPixels = 0; - density = noncompatDensity = DENSITY_DEVICE / (float) DENSITY_DEFAULT; - densityDpi = noncompatDensityDpi = DENSITY_DEVICE; + density = DENSITY_DEVICE / (float) DENSITY_DEFAULT; + densityDpi = DENSITY_DEVICE; scaledDensity = density; - xdpi = noncompatXdpi = DENSITY_DEVICE; - ydpi = noncompatYdpi = DENSITY_DEVICE; - noncompatWidthPixels = 0; - noncompatHeightPixels = 0; + xdpi = DENSITY_DEVICE; + ydpi = DENSITY_DEVICE; + noncompatWidthPixels = widthPixels; + noncompatHeightPixels = heightPixels; + noncompatDensity = density; + noncompatDensityDpi = densityDpi; + noncompatScaledDensity = scaledDensity; + noncompatXdpi = xdpi; + noncompatYdpi = ydpi; + } + + @Override + public boolean equals(Object o) { + return o instanceof DisplayMetrics && equals((DisplayMetrics)o); + } + + /** + * Returns true if these display metrics equal the other display metrics. + * + * @param other The display metrics with which to compare. + * @return True if the display metrics are equal. + */ + public boolean equals(DisplayMetrics other) { + return other != null + && widthPixels == other.widthPixels + && heightPixels == other.heightPixels + && density == other.density + && densityDpi == other.densityDpi + && scaledDensity == other.scaledDensity + && xdpi == other.xdpi + && ydpi == other.ydpi + && noncompatWidthPixels == other.noncompatWidthPixels + && noncompatHeightPixels == other.noncompatHeightPixels + && noncompatDensity == other.noncompatDensity + && noncompatDensityDpi == other.noncompatDensityDpi + && noncompatScaledDensity == other.noncompatScaledDensity + && noncompatXdpi == other.noncompatXdpi + && noncompatYdpi == other.noncompatYdpi; + } + + @Override + public int hashCode() { + return widthPixels * heightPixels * densityDpi; } @Override diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index f30952c..7412f39 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -16,6 +16,8 @@ package android.view; +import android.app.Presentation; +import android.content.Context; import android.content.pm.ActivityInfo; import android.graphics.PixelFormat; import android.os.IBinder; @@ -29,6 +31,17 @@ import android.util.Log; * The interface that apps use to talk to the window manager. * <p> * Use <code>Context.getSystemService(Context.WINDOW_SERVICE)</code> to get one of these. + * </p><p> + * Each window manager instance is bound to a particular {@link Display}. + * To obtain a {@link WindowManager} for a different display, use + * {@link Context#createDisplayContext} to obtain a {@link Context} for that + * display, then use <code>Context.getSystemService(Context.WINDOW_SERVICE)</code> + * to get the WindowManager. + * </p><p> + * The simplest way to show a window on another display is to create a + * {@link Presentation}. The presentation will automatically obtain a + * {@link WindowManager} and {@link Context} for that display. + * </p> * * @see android.content.Context#getSystemService * @see android.content.Context#WINDOW_SERVICE @@ -49,12 +62,24 @@ public interface WindowManager extends ViewManager { } /** - * Use this method to get the default Display object. - * - * @return default Display object + * Returns the {@link Display} upon which this {@link WindowManager} instance + * will create new windows. + * <p> + * Despite the name of this method, the display that is returned is not + * necessarily the primary display of the system (see {@link Display#DEFAULT_DISPLAY}). + * The returned display could instead be a secondary display that this + * window manager instance is managing. Think of it as the display that + * this {@link WindowManager} instance uses by default. + * </p><p> + * To create windows on a different display, you need to obtain a + * {@link WindowManager} for that {@link Display}. (See the {@link WindowManager} + * class documentation for more information.) + * </p> + * + * @return The display that this window manager is managing. */ public Display getDefaultDisplay(); - + /** * Special variation of {@link #removeView} that immediately invokes * the given view hierarchy's {@link View#onDetachedFromWindow() diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index aa9179f..52d79f8 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -16,9 +16,6 @@ package android.view; -import android.content.Context; -import android.hardware.display.DisplayManager; - /** * Provides low-level communication with the system window manager for * operations that are bound to a particular context, display or parent window. @@ -47,25 +44,24 @@ import android.hardware.display.DisplayManager; */ public final class WindowManagerImpl implements WindowManager { private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); - private final Context mContext; private final Display mDisplay; private final Window mParentWindow; - public WindowManagerImpl(Context context, int displayId) { - DisplayManager dm = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); - mContext = context; - mDisplay = dm.getDisplay(displayId); - mParentWindow = null; + public WindowManagerImpl(Display display) { + this(display, null); } - private WindowManagerImpl(Context context, Display display, Window parentWindow) { - mContext = context; + private WindowManagerImpl(Display display, Window parentWindow) { mDisplay = display; mParentWindow = parentWindow; } public WindowManagerImpl createLocalWindowManager(Window parentWindow) { - return new WindowManagerImpl(mContext, mDisplay, parentWindow); + return new WindowManagerImpl(mDisplay, parentWindow); + } + + public WindowManagerImpl createPresentationWindowManager(Display display) { + return new WindowManagerImpl(display, mParentWindow); } @Override diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 209fff0..3757afc 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -768,11 +768,15 @@ <attr name="dialogCustomTitleDecorLayout" format="reference" /> <!-- Window decor layout to use in dialog mode with title only --> <attr name="dialogTitleDecorLayout" format="reference" /> + <!-- Theme to use for alert dialogs spawned from this theme. --> <attr name="alertDialogTheme" format="reference" /> <!-- Icon drawable to use for alerts --> <attr name="alertDialogIcon" format="reference" /> + <!-- Theme to use for presentations spawned from this theme. --> + <attr name="presentationTheme" format="reference" /> + <!-- Drawable to use for generic vertical dividers. --> <attr name="dividerVertical" format="reference" /> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 6414df8..caf4e4b 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -3752,5 +3752,6 @@ <public type="attr" name="listPreferredItemPaddingStart" /> <public type="attr" name="listPreferredItemPaddingEnd" /> <public type="attr" name="singleUser" /> + <public type="attr" name="presentationTheme" /> </resources> diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml index 28fed45..d465356 100644 --- a/core/res/res/values/styles_device_defaults.xml +++ b/core/res/res/values/styles_device_defaults.xml @@ -673,7 +673,6 @@ easier. </style> - <!-- Animation Styles --> <style name="Animation.DeviceDefault.Activity" parent="Animation.Holo.Activity"> diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml index 2f93335..215551b 100644 --- a/core/res/res/values/themes.xml +++ b/core/res/res/values/themes.xml @@ -186,17 +186,24 @@ please see themes_device_defaults.xml. <item name="windowFixedHeightMinor">0dp</item> <!-- Dialog attributes --> - <item name="alertDialogStyle">@android:style/AlertDialog</item> <item name="dialogTheme">@android:style/Theme.Dialog</item> <item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons</item> <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title</item> <item name="dialogTitleDecorLayout">@layout/dialog_title</item> + + <!-- AlertDialog attributes --> <item name="alertDialogTheme">@android:style/Theme.Dialog.Alert</item> + <item name="alertDialogStyle">@android:style/AlertDialog</item> <item name="alertDialogCenterButtons">true</item> <item name="alertDialogIcon">@android:drawable/ic_dialog_alert</item> + <!-- Presentation attributes (introduced after API level 10 so does not + have a special old-style theme. --> + <item name="presentationTheme">@android:style/Theme.DeviceDefault.Dialog.Presentation</item> + + <!-- Toast attributes --> <item name="toastFrameBackground">@android:drawable/toast_frame</item> - + <!-- Panel attributes --> <item name="panelBackground">@android:drawable/menu_background</item> <item name="panelFullBackground">@android:drawable/menu_background_fill_parent_width</item> @@ -1012,17 +1019,23 @@ please see themes_device_defaults.xml. <item name="windowActionModeOverlay">false</item> <!-- Dialog attributes --> - <item name="alertDialogStyle">@android:style/AlertDialog.Holo</item> <item name="dialogTheme">@android:style/Theme.Holo.Dialog</item> <item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons_holo</item> <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_holo</item> <item name="dialogTitleDecorLayout">@layout/dialog_title_holo</item> + + <!-- AlertDialog attributes --> <item name="alertDialogTheme">@android:style/Theme.Holo.Dialog.Alert</item> + <item name="alertDialogStyle">@android:style/AlertDialog.Holo</item> <item name="alertDialogCenterButtons">false</item> <item name="alertDialogIcon">@android:drawable/ic_dialog_alert_holo_dark</item> + <!-- Presentation attributes --> + <item name="presentationTheme">@android:style/Theme.Holo.Dialog.Presentation</item> + + <!-- Toast attributes --> <item name="toastFrameBackground">@android:drawable/toast_frame_holo</item> - + <!-- Panel attributes --> <item name="panelBackground">@android:drawable/menu_hardkey_panel_holo_dark</item> <item name="panelFullBackground">@android:drawable/menu_background_fill_parent_width</item> @@ -1319,17 +1332,23 @@ please see themes_device_defaults.xml. <item name="windowActionModeOverlay">false</item> <!-- Dialog attributes --> - <item name="alertDialogStyle">@android:style/AlertDialog.Holo.Light</item> <item name="dialogTheme">@android:style/Theme.Holo.Light.Dialog</item> <item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons_holo</item> <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_holo</item> <item name="dialogTitleDecorLayout">@layout/dialog_title_holo</item> - <item name="alertDialogCenterButtons">false</item> + + <!-- AlertDialog attributes --> <item name="alertDialogTheme">@android:style/Theme.Holo.Light.Dialog.Alert</item> + <item name="alertDialogStyle">@android:style/AlertDialog.Holo.Light</item> + <item name="alertDialogCenterButtons">false</item> <item name="alertDialogIcon">@android:drawable/ic_dialog_alert_holo_light</item> + <!-- Presentation attributes --> + <item name="presentationTheme">@android:style/Theme.Holo.Light.Dialog.Presentation</item> + + <!-- Toast attributes --> <item name="toastFrameBackground">@android:drawable/toast_frame_holo</item> - + <!-- Panel attributes --> <item name="panelBackground">@android:drawable/menu_hardkey_panel_holo_light</item> <item name="panelFullBackground">@android:drawable/menu_background_fill_parent_width</item> @@ -1663,6 +1682,10 @@ please see themes_device_defaults.xml. <style name="Theme.Holo.DialogWhenLarge.NoActionBar" parent="@android:style/Theme.Holo.NoActionBar"> </style> + <!-- Theme for a presentation window on a secondary display. --> + <style name="Theme.Holo.Dialog.Presentation" parent="@android:style/Theme.Holo.NoActionBar.Fullscreen"> + </style> + <!-- Light holo dialog themes --> <!-- Holo light theme for dialog windows and activities, which is used by the @@ -1760,6 +1783,10 @@ please see themes_device_defaults.xml. <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item> </style> + <!-- Theme for a presentation window on a secondary display. --> + <style name="Theme.Holo.Light.Dialog.Presentation" parent="@android:style/Theme.Holo.Light.NoActionBar.Fullscreen" > + </style> + <!-- Default holographic (dark) for windows that want to have the user's selected wallpaper appear behind them. --> <style name="Theme.Holo.Wallpaper"> diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml index eef831f..2a2b9e0 100644 --- a/core/res/res/values/themes_device_defaults.xml +++ b/core/res/res/values/themes_device_defaults.xml @@ -87,9 +87,14 @@ easier. <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Activity</item> <!-- Dialog attributes --> - <item name="alertDialogStyle">@android:style/AlertDialog.DeviceDefault</item> <item name="dialogTheme">@android:style/Theme.DeviceDefault.Dialog</item> + + <!-- AlertDialog attributes --> <item name="alertDialogTheme">@android:style/Theme.DeviceDefault.Dialog.Alert</item> + <item name="alertDialogStyle">@android:style/AlertDialog.DeviceDefault</item> + + <!-- Presentation attributes --> + <item name="presentationTheme">@android:style/Theme.DeviceDefault.Dialog.Presentation</item> <!-- Text selection handle attributes --> <item name="textSelectHandleWindowStyle">@android:style/Widget.DeviceDefault.TextSelectHandle</item> @@ -239,9 +244,14 @@ easier. <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Activity</item> <!-- Dialog attributes --> - <item name="alertDialogStyle">@android:style/AlertDialog.DeviceDefault.Light</item> <item name="dialogTheme">@android:style/Theme.DeviceDefault.Light.Dialog</item> + + <!-- AlertDialog attributes --> <item name="alertDialogTheme">@android:style/Theme.DeviceDefault.Light.Dialog.Alert</item> + <item name="alertDialogStyle">@android:style/AlertDialog.DeviceDefault.Light</item> + + <!-- Presentation attributes --> + <item name="presentationTheme">@android:style/Theme.DeviceDefault.Light.Dialog.Presentation</item> <!-- Text selection handle attributes --> <item name="textSelectHandleWindowStyle">@android:style/Widget.DeviceDefault.TextSelectHandle</item> @@ -460,6 +470,15 @@ easier. <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" parent="Theme.Holo.Light.DialogWhenLarge.NoActionBar" > </style> + + <!-- DeviceDefault theme for a presentation window on a secondary display. --> + <style name="Theme.DeviceDefault.Dialog.Presentation" parent="Theme.Holo.Dialog.Presentation"> + </style> + + <!-- DeviceDefault light theme for a presentation window on a secondary display. --> + <style name="Theme.DeviceDefault.Light.Dialog.Presentation" parent="Theme.Holo.Light.Dialog.Presentation"> + </style> + <!-- DeviceDefault theme for panel windows. This removes all extraneous window decorations, so you basically have an empty rectangle in which to place your content. It makes the window floating, with a transparent background, and turns off dimming behind the window. --> diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java index eb1f2d6..9004e10 100644 --- a/test-runner/src/android/test/mock/MockContext.java +++ b/test-runner/src/android/test/mock/MockContext.java @@ -40,6 +40,7 @@ import android.os.Handler; import android.os.Looper; import android.os.UserHandle; import android.view.CompatibilityInfoHolder; +import android.view.Display; import java.io.File; import java.io.FileInputStream; @@ -521,13 +522,18 @@ public class MockContext extends Context { } @Override + public Context createDisplayContext(Display display) { + throw new UnsupportedOperationException(); + } + + @Override public boolean isRestricted() { throw new UnsupportedOperationException(); } /** @hide */ @Override - public CompatibilityInfoHolder getCompatibilityInfo() { + public CompatibilityInfoHolder getCompatibilityInfo(int displayId) { throw new UnsupportedOperationException(); } } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index 260ee3e..e629b75 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -67,6 +67,7 @@ import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.BridgeInflater; import android.view.CompatibilityInfoHolder; +import android.view.Display; import android.view.Surface; import android.view.View; import android.view.ViewGroup; @@ -925,6 +926,12 @@ public final class BridgeContext extends Context { } @Override + public Context createDisplayContext(Display display) { + // pass + return null; + } + + @Override public String[] databaseList() { // pass return null; @@ -1357,7 +1364,7 @@ public final class BridgeContext extends Context { } @Override - public CompatibilityInfoHolder getCompatibilityInfo() { + public CompatibilityInfoHolder getCompatibilityInfo(int displayId) { // pass return null; } |