diff options
21 files changed, 600 insertions, 93 deletions
diff --git a/api/current.txt b/api/current.txt index 10ed68d..10a525c 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 4dede0b..690d639 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -3759,5 +3759,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; } |
