summaryrefslogtreecommitdiffstats
path: root/core/java/android/content/res/CompatibilityInfo.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/content/res/CompatibilityInfo.java')
-rw-r--r--core/java/android/content/res/CompatibilityInfo.java358
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();
}
}