diff options
Diffstat (limited to 'core/java/android/content/res/CompatibilityInfo.java')
-rw-r--r-- | core/java/android/content/res/CompatibilityInfo.java | 358 |
1 files changed, 202 insertions, 156 deletions
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java index e403ac2..ab9bfce 100644 --- a/core/java/android/content/res/CompatibilityInfo.java +++ b/core/java/android/content/res/CompatibilityInfo.java @@ -21,9 +21,9 @@ import android.graphics.Canvas; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.Region; +import android.os.Parcel; +import android.os.Parcelable; import android.util.DisplayMetrics; -import android.util.Log; -import android.view.Gravity; import android.view.MotionEvent; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; @@ -34,32 +34,27 @@ import android.view.WindowManager.LayoutParams; * * {@hide} */ -public class CompatibilityInfo { - private static final boolean DBG = false; - private static final String TAG = "CompatibilityInfo"; - +public class CompatibilityInfo implements Parcelable { /** default compatibility info object for compatible applications */ public static final CompatibilityInfo DEFAULT_COMPATIBILITY_INFO = new CompatibilityInfo() { - @Override - public void setExpandable(boolean expandable) { - throw new UnsupportedOperationException("trying to change default compatibility info"); - } }; /** - * The default width of the screen in portrait mode. + * This is the number of pixels we would like to have along the + * short axis of an app that needs to run on a normal size screen. */ - public static final int DEFAULT_PORTRAIT_WIDTH = 320; + public static final int DEFAULT_NORMAL_SHORT_DIMENSION = 320; /** - * The default height of the screen in portrait mode. - */ - public static final int DEFAULT_PORTRAIT_HEIGHT = 480; + * This is the maximum aspect ratio we will allow while keeping + * applications in a compatible screen size. + */ + public static final float MAXIMUM_ASPECT_RATIO = (854f/480f); /** * A compatibility flags */ - private int mCompatibilityFlags; + private final int mCompatibilityFlags; /** * A flag mask to tell if the application needs scaling (when mApplicationScale != 1.0f) @@ -68,54 +63,27 @@ public class CompatibilityInfo { private static final int SCALING_REQUIRED = 1; /** - * A flag mask to indicates that the application can expand over the original size. - * The flag is set to true if - * 1) Application declares its expandable in manifest file using <supports-screens> or - * 2) Configuration.SCREENLAYOUT_COMPAT_NEEDED is not set - * {@see compatibilityFlag} + * Has the application said that its UI is expandable? Based on the + * <supports-screen> android:expandible in the manifest. */ private static final int EXPANDABLE = 2; /** - * A flag mask to tell if the application is configured to be expandable. This differs - * from EXPANDABLE in that the application that is not expandable will be - * marked as expandable if Configuration.SCREENLAYOUT_COMPAT_NEEDED is not set. - */ - private static final int CONFIGURED_EXPANDABLE = 4; - - /** - * A flag mask to indicates that the application supports large screens. - * The flag is set to true if - * 1) Application declares it supports large screens in manifest file using <supports-screens> or - * 2) The screen size is not large - * {@see compatibilityFlag} + * Has the application said that its UI supports large screens? Based on the + * <supports-screen> android:largeScreens in the manifest. */ private static final int LARGE_SCREENS = 8; /** - * A flag mask to tell if the application supports large screens. This differs - * from LARGE_SCREENS in that the application that does not support large - * screens will be marked as supporting them if the current screen is not - * large. - */ - private static final int CONFIGURED_LARGE_SCREENS = 16; - - /** - * A flag mask to indicates that the application supports xlarge screens. - * The flag is set to true if - * 1) Application declares it supports xlarge screens in manifest file using <supports-screens> or - * 2) The screen size is not xlarge - * {@see compatibilityFlag} + * Has the application said that its UI supports xlarge screens? Based on the + * <supports-screen> android:xlargeScreens in the manifest. */ private static final int XLARGE_SCREENS = 32; /** - * A flag mask to tell if the application supports xlarge screens. This differs - * from XLARGE_SCREENS in that the application that does not support xlarge - * screens will be marked as supporting them if the current screen is not - * xlarge. + * Set if the application needs to run in screen size compatibility mode. */ - private static final int CONFIGURED_XLARGE_SCREENS = 64; + private static final int NEEDS_SCREEN_COMPAT = 128; /** * The effective screen density we have selected for this application. @@ -132,28 +100,55 @@ public class CompatibilityInfo { */ public final float applicationInvertedScale; - /** - * The flags from ApplicationInfo. - */ - public final int appFlags; - - public CompatibilityInfo(ApplicationInfo appInfo) { - appFlags = appInfo.flags; - + public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, boolean forceCompat) { + int compatFlags = 0; + if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) { - // Saying you support large screens also implies you support xlarge - // screens; there is no compatibility mode for a large app on an - // xlarge screen. - mCompatibilityFlags |= LARGE_SCREENS | CONFIGURED_LARGE_SCREENS - | XLARGE_SCREENS | CONFIGURED_XLARGE_SCREENS - | EXPANDABLE | CONFIGURED_EXPANDABLE; + compatFlags |= LARGE_SCREENS; + if (!forceCompat) { + // If we aren't forcing the app into compatibility mode, then + // assume if it supports large screens that we should allow it + // to use the full space of an xlarge screen as well. + compatFlags |= XLARGE_SCREENS | EXPANDABLE; + } } if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) { - mCompatibilityFlags |= XLARGE_SCREENS | CONFIGURED_XLARGE_SCREENS - | EXPANDABLE | CONFIGURED_EXPANDABLE; + compatFlags |= XLARGE_SCREENS | EXPANDABLE; + } + if (!forceCompat) { + // If we are forcing compatibility mode, then ignore an app that + // just says it is resizable for screens. We'll only have it fill + // the screen if it explicitly says it supports the screen size we + // are running in. + if ((appInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) { + compatFlags |= EXPANDABLE; + } + } + + boolean supportsScreen = false; + switch (screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK) { + case Configuration.SCREENLAYOUT_SIZE_XLARGE: + if ((compatFlags&XLARGE_SCREENS) != 0) { + supportsScreen = true; + } + break; + case Configuration.SCREENLAYOUT_SIZE_LARGE: + if ((compatFlags&LARGE_SCREENS) != 0) { + supportsScreen = true; + } + break; + } + + if ((screenLayout&Configuration.SCREENLAYOUT_COMPAT_NEEDED) == 0) { + if ((compatFlags&EXPANDABLE) != 0) { + supportsScreen = true; + } } - if ((appInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) { - mCompatibilityFlags |= EXPANDABLE | CONFIGURED_EXPANDABLE; + + if (supportsScreen) { + compatFlags &= ~NEEDS_SCREEN_COMPAT; + } else { + compatFlags |= NEEDS_SCREEN_COMPAT; } if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) { @@ -165,13 +160,14 @@ public class CompatibilityInfo { applicationScale = DisplayMetrics.DENSITY_DEVICE / (float) DisplayMetrics.DENSITY_DEFAULT; applicationInvertedScale = 1.0f / applicationScale; - mCompatibilityFlags |= SCALING_REQUIRED; + compatFlags |= SCALING_REQUIRED; } + + mCompatibilityFlags = compatFlags; } - private CompatibilityInfo(int appFlags, int compFlags, + private CompatibilityInfo(int compFlags, int dens, float scale, float invertedScale) { - this.appFlags = appFlags; mCompatibilityFlags = compFlags; applicationDensity = dens; applicationScale = scale; @@ -179,81 +175,13 @@ public class CompatibilityInfo { } private CompatibilityInfo() { - this(ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS - | ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS - | ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS - | ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS - | ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS, - EXPANDABLE | CONFIGURED_EXPANDABLE, + this(XLARGE_SCREENS | LARGE_SCREENS | EXPANDABLE, DisplayMetrics.DENSITY_DEVICE, 1.0f, 1.0f); } /** - * Returns the copy of this instance. - */ - public CompatibilityInfo copy() { - CompatibilityInfo info = new CompatibilityInfo(appFlags, mCompatibilityFlags, - applicationDensity, applicationScale, applicationInvertedScale); - return info; - } - - /** - * Sets expandable bit in the compatibility flag. - */ - public void setExpandable(boolean expandable) { - if (expandable) { - mCompatibilityFlags |= CompatibilityInfo.EXPANDABLE; - } else { - mCompatibilityFlags &= ~CompatibilityInfo.EXPANDABLE; - } - } - - /** - * Sets large screen bit in the compatibility flag. - */ - public void setLargeScreens(boolean expandable) { - if (expandable) { - mCompatibilityFlags |= CompatibilityInfo.LARGE_SCREENS; - } else { - mCompatibilityFlags &= ~CompatibilityInfo.LARGE_SCREENS; - } - } - - /** - * Sets large screen bit in the compatibility flag. - */ - public void setXLargeScreens(boolean expandable) { - if (expandable) { - mCompatibilityFlags |= CompatibilityInfo.XLARGE_SCREENS; - } else { - mCompatibilityFlags &= ~CompatibilityInfo.XLARGE_SCREENS; - } - } - - /** - * @return true if the application is configured to be expandable. - */ - public boolean isConfiguredExpandable() { - return (mCompatibilityFlags & CompatibilityInfo.CONFIGURED_EXPANDABLE) != 0; - } - - /** - * @return true if the application is configured to be expandable. - */ - public boolean isConfiguredLargeScreens() { - return (mCompatibilityFlags & CompatibilityInfo.CONFIGURED_LARGE_SCREENS) != 0; - } - - /** - * @return true if the application is configured to be expandable. - */ - public boolean isConfiguredXLargeScreens() { - return (mCompatibilityFlags & CompatibilityInfo.CONFIGURED_XLARGE_SCREENS) != 0; - } - - /** * @return true if the scaling is required */ public boolean isScalingRequired() { @@ -261,14 +189,12 @@ public class CompatibilityInfo { } public boolean supportsScreen() { - return (mCompatibilityFlags & (EXPANDABLE|LARGE_SCREENS)) - == (EXPANDABLE|LARGE_SCREENS); + return (mCompatibilityFlags&NEEDS_SCREEN_COMPAT) == 0; } @Override public String toString() { - return "CompatibilityInfo{scale=" + applicationScale + - ", supports screen=" + supportsScreen() + "}"; + return "CompatibilityInfo{scale=" + applicationScale + "}"; } /** @@ -423,24 +349,144 @@ public class CompatibilityInfo { } } + public void applyToDisplayMetrics(DisplayMetrics inoutDm) { + if (!supportsScreen()) { + // This is a larger screen device and the app is not + // compatible with large screens, so diddle it. + CompatibilityInfo.updateCompatibleScreenFrame(inoutDm, null, inoutDm); + } + + if (isScalingRequired()) { + float invertedRatio = applicationInvertedScale; + inoutDm.density *= invertedRatio; + inoutDm.densityDpi = (int)((inoutDm.density*DisplayMetrics.DENSITY_DEFAULT)+.5f); + inoutDm.scaledDensity *= invertedRatio; + inoutDm.xdpi *= invertedRatio; + inoutDm.ydpi *= invertedRatio; + inoutDm.widthPixels = (int) (inoutDm.widthPixels * invertedRatio + 0.5f); + inoutDm.heightPixels = (int) (inoutDm.heightPixels * invertedRatio + 0.5f); + } + } + + public void applyToConfiguration(Configuration inoutConfig) { + if (!supportsScreen()) { + // This is a larger screen device and the app is not + // compatible with large screens, so we are forcing it to + // run as if the screen is normal size. + inoutConfig.screenLayout = + (inoutConfig.screenLayout&~Configuration.SCREENLAYOUT_SIZE_MASK) + | Configuration.SCREENLAYOUT_SIZE_NORMAL; + } + } + /** - * Returns the frame Rect for applications runs under compatibility mode. + * Compute the frame Rect for applications runs under compatibility mode. * * @param dm the display metrics used to compute the frame size. * @param orientation the orientation of the screen. * @param outRect the output parameter which will contain the result. + * @return Returns the scaling factor for the window. */ - public static void updateCompatibleScreenFrame(DisplayMetrics dm, int orientation, - Rect outRect) { - int width = dm.widthPixels; - int portraitHeight = (int) (DEFAULT_PORTRAIT_HEIGHT * dm.density + 0.5f); - int portraitWidth = (int) (DEFAULT_PORTRAIT_WIDTH * dm.density + 0.5f); - if (orientation == Configuration.ORIENTATION_LANDSCAPE) { - int xOffset = (width - portraitHeight) / 2 ; - outRect.set(xOffset, 0, xOffset + portraitHeight, portraitWidth); + public static float updateCompatibleScreenFrame(DisplayMetrics dm, + Rect outRect, DisplayMetrics outDm) { + final int width = dm.realWidthPixels; + final int height = dm.realHeightPixels; + int shortSize, longSize; + if (width < height) { + shortSize = width; + longSize = height; + } else { + shortSize = height; + longSize = width; + } + int newShortSize = (int)(DEFAULT_NORMAL_SHORT_DIMENSION * dm.density + 0.5f); + float aspect = ((float)longSize) / shortSize; + if (aspect > MAXIMUM_ASPECT_RATIO) { + aspect = MAXIMUM_ASPECT_RATIO; + } + int newLongSize = (int)(newShortSize * aspect + 0.5f); + int newWidth, newHeight; + if (width < height) { + newWidth = newShortSize; + newHeight = newLongSize; } else { - int xOffset = (width - portraitWidth) / 2 ; - outRect.set(xOffset, 0, xOffset + portraitWidth, portraitHeight); + newWidth = newLongSize; + newHeight = newShortSize; + } + + float sw = width/(float)newWidth; + float sh = height/(float)newHeight; + float scale = sw < sh ? sw : sh; + if (scale < 1) { + scale = 1; } + + if (outRect != null) { + final int left = (int)((width-(newWidth*scale))/2); + final int top = (int)((height-(newHeight*scale))/2); + outRect.set(left, top, left+newWidth, top+newHeight); + } + + if (outDm != null) { + outDm.widthPixels = newWidth; + outDm.heightPixels = newHeight; + } + + return scale; + } + + @Override + public boolean equals(Object o) { + try { + CompatibilityInfo oc = (CompatibilityInfo)o; + if (mCompatibilityFlags != oc.mCompatibilityFlags) return false; + if (applicationDensity != oc.applicationDensity) return false; + if (applicationScale != oc.applicationScale) return false; + if (applicationInvertedScale != oc.applicationInvertedScale) return false; + return true; + } catch (ClassCastException e) { + return false; + } + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + mCompatibilityFlags; + result = 31 * result + applicationDensity; + result = 31 * result + Float.floatToIntBits(applicationScale); + result = 31 * result + Float.floatToIntBits(applicationInvertedScale); + return result; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mCompatibilityFlags); + dest.writeInt(applicationDensity); + dest.writeFloat(applicationScale); + dest.writeFloat(applicationInvertedScale); + } + + public static final Parcelable.Creator<CompatibilityInfo> CREATOR + = new Parcelable.Creator<CompatibilityInfo>() { + public CompatibilityInfo createFromParcel(Parcel source) { + return new CompatibilityInfo(source); + } + + public CompatibilityInfo[] newArray(int size) { + return new CompatibilityInfo[size]; + } + }; + + private CompatibilityInfo(Parcel source) { + mCompatibilityFlags = source.readInt(); + applicationDensity = source.readInt(); + applicationScale = source.readFloat(); + applicationInvertedScale = source.readFloat(); } } |