summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2009-07-22 21:48:55 -0700
committerDianne Hackborn <hackbod@google.com>2009-07-24 10:47:15 -0700
commit11ea33471e1a14a8594f0b2cd012d86340dd3bd8 (patch)
treebb73c079d8bb21c19fa913b8fd9c587a9089ea84
parent3b99e64e5899030b5d6f8201cb56cd149c80b24d (diff)
downloadframeworks_base-11ea33471e1a14a8594f0b2cd012d86340dd3bd8.zip
frameworks_base-11ea33471e1a14a8594f0b2cd012d86340dd3bd8.tar.gz
frameworks_base-11ea33471e1a14a8594f0b2cd012d86340dd3bd8.tar.bz2
Allow for screen density drawables in compatibility mode.
This change allows us to use drawables that match the current screen density even when being loaded in compatibility mode. In this case, the bitmap is loaded in the screen density, and the bitmap and nine-patch drawables take care of accounting for the density difference. This should be safe for existing applications, for the most part, since they shouldn't really be pulling the bitmap out of the drawable. For the small rare chance of them breaking, it worth getting the correct graphics. Also this will only happen when there is actually a resource of the matching density, and no existing apps should have resources for anything besides the default density (though of course all of the framework resources will be available in the native density). As part of this, the bitmap density API has been changed to a single integer provider the DPI unit density.
-rw-r--r--api/current.xml254
-rw-r--r--core/java/android/app/ActivityThread.java16
-rw-r--r--core/java/android/app/ApplicationContext.java17
-rw-r--r--core/java/android/app/LauncherActivity.java4
-rw-r--r--core/java/android/text/style/ImageSpan.java4
-rw-r--r--core/java/android/util/DisplayMetrics.java9
-rw-r--r--core/java/android/view/Display.java1
-rw-r--r--core/java/android/view/View.java2
-rw-r--r--core/java/android/view/ViewRoot.java6
-rw-r--r--core/java/android/widget/ImageView.java2
-rw-r--r--core/java/com/android/internal/widget/EditStyledText.java3
-rw-r--r--core/jni/android/graphics/Canvas.cpp15
-rw-r--r--core/jni/android/graphics/Graphics.cpp9
-rw-r--r--core/jni/android/graphics/GraphicsJNI.h1
-rw-r--r--core/jni/android/graphics/NinePatch.cpp40
-rw-r--r--graphics/java/android/graphics/Bitmap.java176
-rw-r--r--graphics/java/android/graphics/BitmapFactory.java180
-rw-r--r--graphics/java/android/graphics/Canvas.java86
-rw-r--r--graphics/java/android/graphics/NinePatch.java31
-rw-r--r--graphics/java/android/graphics/drawable/BitmapDrawable.java128
-rw-r--r--graphics/java/android/graphics/drawable/Drawable.java32
-rw-r--r--graphics/java/android/graphics/drawable/NinePatchDrawable.java115
-rw-r--r--tests/DpiTest/res/drawable-hdpi/npatch240dpi.9.pngbin0 -> 17331 bytes
-rw-r--r--tests/DpiTest/res/drawable-hdpi/smlnpatch240dpi.9.pngbin0 -> 946 bytes
-rw-r--r--tests/DpiTest/res/drawable-ldpi/npatch120dpi.9.pngbin0 -> 6299 bytes
-rw-r--r--tests/DpiTest/res/drawable-ldpi/smlnpatch120dpi.9.pngbin0 -> 804 bytes
-rw-r--r--tests/DpiTest/res/drawable/npatch160dpi.9.pngbin0 -> 9978 bytes
-rw-r--r--tests/DpiTest/res/drawable/smlnpatch160dpi.9.pngbin0 -> 855 bytes
-rw-r--r--tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java25
29 files changed, 799 insertions, 357 deletions
diff --git a/api/current.xml b/api/current.xml
index 46969e0..d56263f 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -49107,8 +49107,8 @@
visibility="public"
>
</method>
-<method name="getDensityScale"
- return="float"
+<method name="getDensity"
+ return="int"
abstract="false"
native="false"
synchronized="false"
@@ -49217,6 +49217,19 @@
<parameter name="metrics" type="android.util.DisplayMetrics">
</parameter>
</method>
+<method name="getScaledHeight"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="targetDensity" type="int">
+</parameter>
+</method>
<method name="getScaledWidth"
return="int"
abstract="false"
@@ -49243,19 +49256,21 @@
<parameter name="metrics" type="android.util.DisplayMetrics">
</parameter>
</method>
-<method name="getWidth"
+<method name="getScaledWidth"
return="int"
abstract="false"
native="false"
synchronized="false"
static="false"
- final="true"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
+<parameter name="targetDensity" type="int">
+</parameter>
</method>
-<method name="hasAlpha"
- return="boolean"
+<method name="getWidth"
+ return="int"
abstract="false"
native="false"
synchronized="false"
@@ -49265,13 +49280,13 @@
visibility="public"
>
</method>
-<method name="isAutoScalingEnabled"
+<method name="hasAlpha"
return="boolean"
abstract="false"
native="false"
synchronized="false"
static="false"
- final="false"
+ final="true"
deprecated="not deprecated"
visibility="public"
>
@@ -49320,20 +49335,7 @@
visibility="public"
>
</method>
-<method name="setAutoScalingEnabled"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="autoScalingEnabled" type="boolean">
-</parameter>
-</method>
-<method name="setDensityScale"
+<method name="setDensity"
return="void"
abstract="false"
native="false"
@@ -49343,7 +49345,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="densityScale" type="float">
+<parameter name="density" type="int">
</parameter>
</method>
<method name="setPixel"
@@ -49413,11 +49415,11 @@
visibility="public"
>
</field>
-<field name="DENSITY_SCALE_UNKNOWN"
- type="float"
+<field name="DENSITY_NONE"
+ type="int"
transient="false"
volatile="false"
- value="-1.0f"
+ value="0"
static="true"
final="true"
deprecated="not deprecated"
@@ -49633,7 +49635,7 @@
<parameter name="id" type="int">
</parameter>
</method>
-<method name="decodeStream"
+<method name="decodeResourceStream"
return="android.graphics.Bitmap"
abstract="false"
native="false"
@@ -49792,6 +49794,26 @@
visibility="public"
>
</field>
+<field name="inScreenDensity"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="inTargetDensity"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="inTempStorage"
type="byte[]"
transient="false"
@@ -51046,8 +51068,8 @@
visibility="public"
>
</method>
-<method name="getDensityScale"
- return="float"
+<method name="getDensity"
+ return="int"
abstract="false"
native="false"
synchronized="false"
@@ -51403,7 +51425,7 @@
<parameter name="bitmap" type="android.graphics.Bitmap">
</parameter>
</method>
-<method name="setDensityScale"
+<method name="setDensity"
return="void"
abstract="false"
native="false"
@@ -51413,7 +51435,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="densityScale" type="float">
+<parameter name="density" type="int">
</parameter>
</method>
<method name="setDrawFilter"
@@ -53725,6 +53747,17 @@
<parameter name="paint" type="android.graphics.Paint">
</parameter>
</method>
+<method name="getDensity"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getHeight"
return="int"
abstract="false"
@@ -59128,9 +59161,29 @@
type="android.graphics.drawable.BitmapDrawable"
static="false"
final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="BitmapDrawable"
+ type="android.graphics.drawable.BitmapDrawable"
+ static="false"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
+<parameter name="res" type="android.content.res.Resources">
+</parameter>
+</constructor>
+<constructor name="BitmapDrawable"
+ type="android.graphics.drawable.BitmapDrawable"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="bitmap" type="android.graphics.Bitmap">
+</parameter>
</constructor>
<constructor name="BitmapDrawable"
type="android.graphics.drawable.BitmapDrawable"
@@ -59139,6 +59192,8 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="res" type="android.content.res.Resources">
+</parameter>
<parameter name="bitmap" type="android.graphics.Bitmap">
</parameter>
</constructor>
@@ -59304,6 +59359,45 @@
<parameter name="gravity" type="int">
</parameter>
</method>
+<method name="setTargetDensity"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="canvas" type="android.graphics.Canvas">
+</parameter>
+</method>
+<method name="setTargetDensity"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="metrics" type="android.util.DisplayMetrics">
+</parameter>
+</method>
+<method name="setTargetDensity"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="density" type="int">
+</parameter>
+</method>
<method name="setTileModeX"
return="void"
abstract="false"
@@ -59640,6 +59734,25 @@
<parameter name="pathName" type="java.lang.String">
</parameter>
</method>
+<method name="createFromResourceStream"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="res" type="android.content.res.Resources">
+</parameter>
+<parameter name="value" type="android.util.TypedValue">
+</parameter>
+<parameter name="is" type="java.io.InputStream">
+</parameter>
+<parameter name="srcName" type="java.lang.String">
+</parameter>
+</method>
<method name="createFromStream"
return="android.graphics.drawable.Drawable"
abstract="false"
@@ -61337,9 +61450,27 @@
type="android.graphics.drawable.NinePatchDrawable"
static="false"
final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="bitmap" type="android.graphics.Bitmap">
+</parameter>
+<parameter name="chunk" type="byte[]">
+</parameter>
+<parameter name="padding" type="android.graphics.Rect">
+</parameter>
+<parameter name="srcName" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="NinePatchDrawable"
+ type="android.graphics.drawable.NinePatchDrawable"
+ static="false"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
+<parameter name="res" type="android.content.res.Resources">
+</parameter>
<parameter name="bitmap" type="android.graphics.Bitmap">
</parameter>
<parameter name="chunk" type="byte[]">
@@ -61353,9 +61484,21 @@
type="android.graphics.drawable.NinePatchDrawable"
static="false"
final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="patch" type="android.graphics.NinePatch">
+</parameter>
+</constructor>
+<constructor name="NinePatchDrawable"
+ type="android.graphics.drawable.NinePatchDrawable"
+ static="false"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
+<parameter name="res" type="android.content.res.Resources">
+</parameter>
<parameter name="patch" type="android.graphics.NinePatch">
</parameter>
</constructor>
@@ -61420,6 +61563,45 @@
<parameter name="cf" type="android.graphics.ColorFilter">
</parameter>
</method>
+<method name="setTargetDensity"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="canvas" type="android.graphics.Canvas">
+</parameter>
+</method>
+<method name="setTargetDensity"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="metrics" type="android.util.DisplayMetrics">
+</parameter>
+</method>
+<method name="setTargetDensity"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="density" type="int">
+</parameter>
+</method>
</class>
<class name="PaintDrawable"
extends="android.graphics.drawable.ShapeDrawable"
@@ -133364,6 +133546,16 @@
visibility="public"
>
</field>
+<field name="densityDpi"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="heightPixels"
type="int"
transient="false"
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 76b47f1..182843a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -177,11 +177,17 @@ public final class ActivityThread {
synchronized (mPackages) {
// Resources is app scale dependent.
ResourcesKey key = new ResourcesKey(resDir, compInfo.applicationScale);
- //Log.w(TAG, "getTopLevelResources: " + resDir);
+ if (false) {
+ Log.w(TAG, "getTopLevelResources: " + resDir + " / "
+ + compInfo.applicationScale);
+ }
WeakReference<Resources> wr = mActiveResources.get(key);
Resources r = wr != null ? wr.get() : null;
if (r != null && r.getAssets().isUpToDate()) {
- //Log.w(TAG, "Returning cached resources " + r + " " + resDir);
+ if (false) {
+ Log.w(TAG, "Returning cached resources " + r + " " + resDir
+ + ": appScale=" + r.getCompatibilityInfo().applicationScale);
+ }
return r;
}
@@ -198,7 +204,11 @@ public final class ActivityThread {
//Log.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);
DisplayMetrics metrics = getDisplayMetricsLocked(false);
r = new Resources(assets, metrics, getConfiguration(), compInfo);
- //Log.i(TAG, "Created app resources " + r + ": " + r.getConfiguration());
+ if (false) {
+ Log.i(TAG, "Created app resources " + resDir + " " + r + ": "
+ + r.getConfiguration() + " appScale="
+ + r.getCompatibilityInfo().applicationScale);
+ }
// XXX need to remove entries when weak references go away
mActiveResources.put(key, new WeakReference<Resources>(r));
return r;
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index afb2fe9..92929ea 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -541,7 +541,10 @@ class ApplicationContext extends Context {
if (fd != null) {
Bitmap bm = BitmapFactory.decodeFileDescriptor(fd.getFileDescriptor());
if (bm != null) {
- return new BitmapDrawable(bm);
+ // For now clear the density until we figure out how
+ // to deal with it for wallpapers.
+ bm.setDensity(0);
+ return new BitmapDrawable(getResources(), bm);
}
}
} catch (RemoteException e) {
@@ -1949,6 +1952,15 @@ class ApplicationContext extends Context {
try {
Resources r = getResourcesForApplication(appInfo);
dr = r.getDrawable(resid);
+ if (false) {
+ RuntimeException e = new RuntimeException("here");
+ e.fillInStackTrace();
+ Log.w(TAG, "Getting drawable 0x" + Integer.toHexString(resid)
+ + " from package " + packageName
+ + ": app scale=" + r.getCompatibilityInfo().applicationScale
+ + ", caller scale=" + mContext.getResources().getCompatibilityInfo().applicationScale,
+ e);
+ }
if (DEBUG_ICONS) Log.v(TAG, "Getting drawable 0x"
+ Integer.toHexString(resid) + " from " + r
+ ": " + dr);
@@ -2036,10 +2048,9 @@ class ApplicationContext extends Context {
if (app.packageName.equals("system")) {
return mContext.mMainThread.getSystemContext().getResources();
}
- ActivityThread.PackageInfo pi = mContext.mMainThread.getPackageInfoNoCheck(app);
Resources r = mContext.mMainThread.getTopLevelResources(
app.uid == Process.myUid() ? app.sourceDir
- : app.publicSourceDir, pi);
+ : app.publicSourceDir, mContext.mPackageInfo);
if (r != null) {
return r;
}
diff --git a/core/java/android/app/LauncherActivity.java b/core/java/android/app/LauncherActivity.java
index accdda9..d788c43 100644
--- a/core/java/android/app/LauncherActivity.java
+++ b/core/java/android/app/LauncherActivity.java
@@ -297,7 +297,7 @@ public abstract class LauncherActivity extends ListActivity {
icon.setBounds(x, y, x + width, y + height);
icon.draw(canvas);
icon.setBounds(mOldBounds);
- icon = new BitmapDrawable(thumb);
+ icon = new BitmapDrawable(getResources(), thumb);
} else if (iconWidth < width && iconHeight < height) {
final Bitmap.Config c = Bitmap.Config.ARGB_8888;
final Bitmap thumb = Bitmap.createBitmap(mIconWidth, mIconHeight, c);
@@ -309,7 +309,7 @@ public abstract class LauncherActivity extends ListActivity {
icon.setBounds(x, y, x + iconWidth, y + iconHeight);
icon.draw(canvas);
icon.setBounds(mOldBounds);
- icon = new BitmapDrawable(thumb);
+ icon = new BitmapDrawable(getResources(), thumb);
}
}
diff --git a/core/java/android/text/style/ImageSpan.java b/core/java/android/text/style/ImageSpan.java
index 29c0c76..911a23c 100644
--- a/core/java/android/text/style/ImageSpan.java
+++ b/core/java/android/text/style/ImageSpan.java
@@ -43,7 +43,7 @@ public class ImageSpan extends DynamicDrawableSpan {
*/
public ImageSpan(Bitmap b, int verticalAlignment) {
super(verticalAlignment);
- mDrawable = new BitmapDrawable(b);
+ mDrawable = new BitmapDrawable(mContext.getResources(), b);
int width = mDrawable.getIntrinsicWidth();
int height = mDrawable.getIntrinsicHeight();
mDrawable.setBounds(0, 0, width > 0 ? width : 0, height > 0 ? height : 0);
@@ -117,7 +117,7 @@ public class ImageSpan extends DynamicDrawableSpan {
InputStream is = mContext.getContentResolver().openInputStream(
mContentUri);
bitmap = BitmapFactory.decodeStream(is);
- drawable = new BitmapDrawable(bitmap);
+ drawable = new BitmapDrawable(mContext.getResources(), bitmap);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight());
is.close();
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index 061f98a..dd5a440 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -80,6 +80,11 @@ public class DisplayMetrics {
*/
public float density;
/**
+ * The screen density expressed as dots-per-inch. May be either
+ * {@link #DENSITY_LOW}, {@link #DENSITY_MEDIUM}, or {@link #DENSITY_HIGH}.
+ */
+ public int densityDpi;
+ /**
* A scaling factor for fonts displayed on the display. This is the same
* as {@link #density}, except that it may be adjusted in smaller
* increments at runtime based on a user preference for the font size.
@@ -101,6 +106,7 @@ public class DisplayMetrics {
widthPixels = o.widthPixels;
heightPixels = o.heightPixels;
density = o.density;
+ densityDpi = o.densityDpi;
scaledDensity = o.scaledDensity;
xdpi = o.xdpi;
ydpi = o.ydpi;
@@ -110,6 +116,7 @@ public class DisplayMetrics {
widthPixels = 0;
heightPixels = 0;
density = DENSITY_DEVICE / (float) DENSITY_DEFAULT;
+ densityDpi = DENSITY_DEVICE;
scaledDensity = density;
xdpi = DENSITY_DEVICE;
ydpi = DENSITY_DEVICE;
@@ -186,9 +193,11 @@ public class DisplayMetrics {
heightPixels = defaultHeight;
}
}
+
if (compatibilityInfo.isScalingRequired()) {
float invertedRatio = compatibilityInfo.applicationInvertedScale;
density *= invertedRatio;
+ densityDpi = (int)((density*DisplayMetrics.DENSITY_DEFAULT)+.5f);
scaledDensity *= invertedRatio;
xdpi *= invertedRatio;
ydpi *= invertedRatio;
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 5551f64..b055d51 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -94,6 +94,7 @@ public class Display
outMetrics.widthPixels = getWidth();
outMetrics.heightPixels = getHeight();
outMetrics.density = mDensity;
+ outMetrics.densityDpi = (int)((mDensity*DisplayMetrics.DENSITY_DEFAULT)+.5f);
outMetrics.scaledDensity= outMetrics.density;
outMetrics.xdpi = mDpiX;
outMetrics.ydpi = mDpiY;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index ff8868b..7ed2712 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -46,6 +46,7 @@ import android.os.SystemClock;
import android.os.SystemProperties;
import android.util.AttributeSet;
import android.util.Config;
+import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
import android.util.Pool;
@@ -5976,6 +5977,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
try {
bitmap = Bitmap.createBitmap(width, height, quality);
+ bitmap.setDensity(getResources().getDisplayMetrics().densityDpi);
if (autoScale) {
mDrawingCache = new SoftReference<Bitmap>(bitmap);
} else {
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index bb61ad3..b6119aa 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -187,7 +187,7 @@ public final class ViewRoot extends Handler implements ViewParent,
*/
AudioManager mAudioManager;
- private final float mDensity;
+ private final int mDensity;
public ViewRoot(Context context) {
super();
@@ -229,7 +229,7 @@ public final class ViewRoot extends Handler implements ViewParent,
mAdded = false;
mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this);
mViewConfiguration = ViewConfiguration.get(context);
- mDensity = context.getResources().getDisplayMetrics().density;
+ mDensity = context.getResources().getDisplayMetrics().densityDpi;
}
@Override
@@ -1270,7 +1270,7 @@ public final class ViewRoot extends Handler implements ViewParent,
}
// TODO: Do this in native
- canvas.setDensityScale(mDensity);
+ canvas.setDensity(mDensity);
} catch (Surface.OutOfResourcesException e) {
Log.e("ViewRoot", "OutOfResourcesException locking surface", e);
// TODO: we should ask the window manager to do something!
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 2796774..6a9bcfb 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -317,7 +317,7 @@ public class ImageView extends View {
public void setImageBitmap(Bitmap bm) {
// if this is used frequently, may handle bitmaps explicitly
// to reduce the intermediate drawable object
- setImageDrawable(new BitmapDrawable(bm));
+ setImageDrawable(new BitmapDrawable(mContext.getResources(), bm));
}
public void setImageState(int[] state, boolean merge) {
diff --git a/core/java/com/android/internal/widget/EditStyledText.java b/core/java/com/android/internal/widget/EditStyledText.java
index f0ad7b3..82197c0 100644
--- a/core/java/com/android/internal/widget/EditStyledText.java
+++ b/core/java/com/android/internal/widget/EditStyledText.java
@@ -1242,7 +1242,8 @@ public class EditStyledText extends EditText {
try {
InputStream is = mEST.getContext().getContentResolver().openInputStream(uri);
Bitmap bitmap = BitmapFactory.decodeStream(is);
- Drawable drawable = new BitmapDrawable(bitmap);
+ Drawable drawable = new BitmapDrawable(
+ getContext().getResources(), bitmap);
drawable.setBounds(0, 0,
drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight());
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 93d68cb..52acf04 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -462,17 +462,18 @@ public:
static void drawBitmap__BitmapFFPaint(JNIEnv* env, jobject jcanvas,
SkCanvas* canvas, SkBitmap* bitmap,
jfloat left, jfloat top,
- SkPaint* paint,
- jboolean autoScale, jfloat densityScale) {
+ SkPaint* paint, jint canvasDensity,
+ jint bitmapDensity) {
SkScalar left_ = SkFloatToScalar(left);
SkScalar top_ = SkFloatToScalar(top);
- if (!autoScale || densityScale <= 0.0f) {
+ if (canvasDensity == bitmapDensity || canvasDensity == 0
+ || bitmapDensity == 0) {
canvas->drawBitmap(*bitmap, left_, top_, paint);
} else {
canvas->save();
- SkScalar canvasScale = GraphicsJNI::getCanvasDensityScale(env, jcanvas);
- SkScalar scale = canvasScale / SkFloatToScalar(densityScale);
+ SkScalar scale = SkFloatToScalar(canvasDensity / (float)bitmapDensity);
+ canvas->translate(left_, top_);
canvas->scale(scale, scale);
SkPaint filteredPaint;
@@ -481,7 +482,7 @@ public:
}
filteredPaint.setFilterBitmap(true);
- canvas->drawBitmap(*bitmap, left_, top_, &filteredPaint);
+ canvas->drawBitmap(*bitmap, 0, 0, &filteredPaint);
canvas->restore();
}
@@ -905,7 +906,7 @@ static JNINativeMethod gCanvasMethods[] = {
{"native_drawRoundRect","(ILandroid/graphics/RectF;FFI)V",
(void*) SkCanvasGlue::drawRoundRect},
{"native_drawPath","(III)V", (void*) SkCanvasGlue::drawPath},
- {"native_drawBitmap","(IIFFIZF)V",
+ {"native_drawBitmap","(IIFFIII)V",
(void*) SkCanvasGlue::drawBitmap__BitmapFFPaint},
{"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/RectF;I)V",
(void*) SkCanvasGlue::drawBitmapRF},
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 6e159a8..ca1cb7d 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -163,7 +163,6 @@ static jfieldID gBitmapConfig_nativeInstanceID;
static jclass gCanvas_class;
static jfieldID gCanvas_nativeInstanceID;
-static jfieldID gCanvas_densityScaleID;
static jclass gPaint_class;
static jfieldID gPaint_nativeInstanceID;
@@ -320,13 +319,6 @@ SkCanvas* GraphicsJNI::getNativeCanvas(JNIEnv* env, jobject canvas) {
return c;
}
-SkScalar GraphicsJNI::getCanvasDensityScale(JNIEnv* env, jobject canvas) {
- SkASSERT(env);
- SkASSERT(canvas);
- SkASSERT(env->IsInstanceOf(canvas, gCanvas_class));
- return SkFloatToScalar(env->GetFloatField(canvas, gCanvas_densityScaleID));
-}
-
SkPaint* GraphicsJNI::getNativePaint(JNIEnv* env, jobject paint) {
SkASSERT(env);
SkASSERT(paint);
@@ -557,7 +549,6 @@ int register_android_graphics_Graphics(JNIEnv* env)
gCanvas_class = make_globalref(env, "android/graphics/Canvas");
gCanvas_nativeInstanceID = getFieldIDCheck(env, gCanvas_class, "mNativeCanvas", "I");
- gCanvas_densityScaleID = getFieldIDCheck(env, gCanvas_class, "mDensityScale", "F");
gPaint_class = make_globalref(env, "android/graphics/Paint");
gPaint_nativeInstanceID = getFieldIDCheck(env, gPaint_class, "mNativePaint", "I");
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 16925e4..f8b60a8 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -38,7 +38,6 @@ public:
static SkBitmap* getNativeBitmap(JNIEnv*, jobject bitmap);
static SkPicture* getNativePicture(JNIEnv*, jobject picture);
static SkRegion* getNativeRegion(JNIEnv*, jobject region);
- static SkScalar getCanvasDensityScale(JNIEnv*, jobject canvas);
/** Return the corresponding native config from the java Config enum,
or kNo_Config if the java object is null.
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index b11edfc..fd5271e 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -1,5 +1,6 @@
#include <utils/ResourceTypes.h>
+#include "SkCanvas.h"
#include "SkRegion.h"
#include "GraphicsJNI.h"
@@ -45,7 +46,8 @@ public:
}
static void draw(JNIEnv* env, SkCanvas* canvas, SkRect& bounds,
- const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint)
+ const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint,
+ jint destDensity, jint srcDensity)
{
size_t chunkSize = env->GetArrayLength(chunkObj);
void* storage = alloca(chunkSize);
@@ -56,13 +58,32 @@ public:
Res_png_9patch* chunk = static_cast<Res_png_9patch*>(storage);
assert(chunkSize == chunk->serializedSize());
// this relies on deserialization being done in place
- Res_png_9patch::deserialize(chunk);
- NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL);
+ Res_png_9patch::deserialize(chunk);
+
+ if (destDensity == srcDensity || destDensity == 0
+ || srcDensity == 0) {
+ NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL);
+ } else {
+ canvas->save();
+
+ SkScalar scale = SkFloatToScalar(destDensity / (float)srcDensity);
+ canvas->translate(bounds.fLeft, bounds.fTop);
+ canvas->scale(scale, scale);
+
+ bounds.fRight = SkScalarDiv(bounds.fRight-bounds.fLeft, scale);
+ bounds.fBottom = SkScalarDiv(bounds.fBottom-bounds.fTop, scale);
+ bounds.fLeft = bounds.fTop = 0;
+
+ NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL);
+
+ canvas->restore();
+ }
}
}
static void drawF(JNIEnv* env, jobject, SkCanvas* canvas, jobject boundsRectF,
- const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint)
+ const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint,
+ jint destDensity, jint srcDensity)
{
SkASSERT(canvas);
SkASSERT(boundsRectF);
@@ -73,11 +94,12 @@ public:
SkRect bounds;
GraphicsJNI::jrectf_to_rect(env, boundsRectF, &bounds);
- draw(env, canvas, bounds, bitmap, chunkObj, paint);
+ draw(env, canvas, bounds, bitmap, chunkObj, paint, destDensity, srcDensity);
}
static void drawI(JNIEnv* env, jobject, SkCanvas* canvas, jobject boundsRect,
- const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint)
+ const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint,
+ jint destDensity, jint srcDensity)
{
SkASSERT(canvas);
SkASSERT(boundsRect);
@@ -87,7 +109,7 @@ public:
SkRect bounds;
GraphicsJNI::jrect_to_rect(env, boundsRect, &bounds);
- draw(env, canvas, bounds, bitmap, chunkObj, paint);
+ draw(env, canvas, bounds, bitmap, chunkObj, paint, destDensity, srcDensity);
}
static jint getTransparentRegion(JNIEnv* env, jobject,
@@ -126,8 +148,8 @@ public:
static JNINativeMethod gNinePatchMethods[] = {
{ "isNinePatchChunk", "([B)Z", (void*)SkNinePatchGlue::isNinePatchChunk },
{ "validateNinePatchChunk", "(I[B)V", (void*)SkNinePatchGlue::validateNinePatchChunk },
- { "nativeDraw", "(ILandroid/graphics/RectF;I[BI)V", (void*)SkNinePatchGlue::drawF },
- { "nativeDraw", "(ILandroid/graphics/Rect;I[BI)V", (void*)SkNinePatchGlue::drawI },
+ { "nativeDraw", "(ILandroid/graphics/RectF;I[BIII)V", (void*)SkNinePatchGlue::drawF },
+ { "nativeDraw", "(ILandroid/graphics/Rect;I[BIII)V", (void*)SkNinePatchGlue::drawI },
{ "nativeGetTransparentRegion", "(I[BLandroid/graphics/Rect;)I",
(void*)SkNinePatchGlue::getTransparentRegion }
};
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index df659ef..bb19229 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -30,11 +30,11 @@ public final class Bitmap implements Parcelable {
/**
* Indicates that the bitmap was created for an unknown pixel density.
*
- * @see Bitmap#getDensityScale()
- * @see Bitmap#setDensityScale(float)
+ * @see Bitmap#getDensity()
+ * @see Bitmap#setDensity(int)
*/
- public static final float DENSITY_SCALE_UNKNOWN = -1.0f;
-
+ public static final int DENSITY_NONE = 0;
+
// Note: mNativeBitmap is used by FaceDetector_jni.cpp
// Don't change/rename without updating FaceDetector_jni.cpp
private final int mNativeBitmap;
@@ -45,10 +45,10 @@ public final class Bitmap implements Parcelable {
private int mHeight = -1;
private boolean mRecycled;
- private static volatile Matrix sScaleMatrix;
+ // Package-scoped for fast access.
+ /*package*/ int mDensity = DENSITY_NONE;
- private float mDensityScale = DENSITY_SCALE_UNKNOWN;
- private boolean mAutoScaling;
+ private static volatile Matrix sScaleMatrix;
/**
* @noinspection UnusedDeclaration
@@ -70,84 +70,39 @@ public final class Bitmap implements Parcelable {
}
/**
- * <p>Returns the density scale for this bitmap, expressed as a factor of
- * the default density (160.) For instance, a bitmap designed for
- * displays with a density of 240 will have a density scale of 1.5 whereas a bitmap
- * designed for a density of 160 will have a density scale of 1.0.</p>
+ * <p>Returns the density for this bitmap.</p>
*
- * <p>The default density scale is {@link #DENSITY_SCALE_UNKNOWN}.</p>
+ * <p>The default density scale is {@link #DENSITY_NONE}.</p>
*
- * @return A scaling factor of the default density (160) or {@link #DENSITY_SCALE_UNKNOWN}
+ * @return A scaling factor of the default density (160) or {@link #DENSITY_NONE}
* if the scaling factor is unknown.
*
- * @see #setDensityScale(float)
- * @see #isAutoScalingEnabled()
- * @see #setAutoScalingEnabled(boolean)
+ * @see #setDensity(int)
* @see android.util.DisplayMetrics#DENSITY_DEFAULT
- * @see android.util.DisplayMetrics#density
- * @see #DENSITY_SCALE_UNKNOWN
+ * @see android.util.DisplayMetrics#densityDpi
+ * @see #DENSITY_NONE
*/
- public float getDensityScale() {
- return mDensityScale;
+ public int getDensity() {
+ return mDensity;
}
/**
- * <p>Specifies the density scale for this bitmap, expressed as a factor of
- * the default density (160.) For instance, a bitmap designed for
- * displays with a density of 240 will have a density scale of 1.5 whereas a bitmap
- * designed for a density of 160 will have a density scale of 1.0.</p>
+ * <p>Specifies the density for this bitmap. When the bitmap is
+ * drawn to a Canvas that also has a density, it will be scaled
+ * appropriately.</p>
*
- * @param densityScale The density scaling factor to use with this bitmap or
- * {@link #DENSITY_SCALE_UNKNOWN} if the factor is unknown.
+ * @param density The density scaling factor to use with this bitmap or
+ * {@link #DENSITY_NONE} if the density is unknown.
*
- * @see #getDensityScale()
- * @see #isAutoScalingEnabled()
- * @see #setAutoScalingEnabled(boolean)
+ * @see #getDensity()
* @see android.util.DisplayMetrics#DENSITY_DEFAULT
- * @see android.util.DisplayMetrics#density
- * @see #DENSITY_SCALE_UNKNOWN
- */
- public void setDensityScale(float densityScale) {
- mDensityScale = densityScale;
- }
-
- /**
- * </p>Indicates whether this bitmap will be automatically be scaled at the
- * target's density at drawing time. If auto scaling is enabled, this bitmap
- * will be drawn with the following scale factor:</p>
- *
- * <pre>scale = (bitmap density scale factor) / (target density scale factor)</pre>
- *
- * <p>Auto scaling is turned off by default. If auto scaling is enabled but the
- * bitmap has an unknown density scale, then the bitmap will never be automatically
- * scaled at drawing time.</p>
- *
- * @return True if the bitmap must be scaled at drawing time, false otherwise.
- *
- * @see #setAutoScalingEnabled(boolean)
- * @see #getDensityScale()
- * @see #setDensityScale(float)
- */
- public boolean isAutoScalingEnabled() {
- return mAutoScaling;
- }
-
- /**
- * <p>Enables or disables auto scaling for this bitmap. When auto scaling is enabled,
- * the bitmap will be scaled at drawing time to accomodate the drawing target's pixel
- * density. The final scale factor for this bitmap is thus defined:</p>
- *
- * <pre>scale = (bitmap density scale factor) / (target density scale factor)</pre>
- *
- * <p>If auto scaling is enabled but the bitmap has an unknown density scale, then
- * the bitmap will never be automatically scaled at drawing time.</p>
- *
- * @param autoScalingEnabled True to scale the bitmap at drawing time, false otherwise.
+ * @see android.util.DisplayMetrics#densityDpi
+ * @see #DENSITY_NONE
*/
- public void setAutoScalingEnabled(boolean autoScalingEnabled) {
- mAutoScaling = autoScalingEnabled;
+ public void setDensity(int density) {
+ mDensity = density;
}
-
+
/**
* Sets the nine patch chunk.
*
@@ -455,9 +410,8 @@ public final class Bitmap implements Parcelable {
canvas.drawBitmap(source, srcR, dstR, paint);
// The new bitmap was created from a known bitmap source so assume that
- // they use the same density scale
- bitmap.mDensityScale = source.mDensityScale;
- bitmap.mAutoScaling = source.mAutoScaling;
+ // they use the same density
+ bitmap.mDensity = source.mDensity;
return bitmap;
}
@@ -603,65 +557,71 @@ public final class Bitmap implements Parcelable {
}
/**
- * Convenience method that returns the width of this bitmap divided
- * by the density scale factor.
- *
- * @param canvas The Canvas the bitmap will be drawn to.
- * @return The scaled width of this bitmap, according to the density scale factor.
+ * Convenience for calling {@link #getScaledWidth(int)} with the target
+ * density of the given {@link Canvas}.
*/
public int getScaledWidth(Canvas canvas) {
- final float scale = mDensityScale;
- if (!mAutoScaling || scale < 0) {
- return getWidth();
- }
- return (int)(getWidth() * canvas.getDensityScale() / scale);
+ return scaleFromDensity(getWidth(), mDensity, canvas.mDensity);
}
/**
- * Convenience method that returns the height of this bitmap divided
- * by the density scale factor.
- *
- * @param canvas The Canvas the bitmap will be drawn to.
- * @return The scaled height of this bitmap, according to the density scale factor.
+ * Convenience for calling {@link #getScaledHeight(int)} with the target
+ * density of the given {@link Canvas}.
*/
public int getScaledHeight(Canvas canvas) {
- final float scale = mDensityScale;
- if (!mAutoScaling || scale < 0) {
- return getHeight();
- }
- return (int)(getHeight() * canvas.getDensityScale() / scale);
+ return scaleFromDensity(getHeight(), mDensity, canvas.mDensity);
+ }
+
+ /**
+ * Convenience for calling {@link #getScaledWidth(int)} with the target
+ * density of the given {@link DisplayMetrics}.
+ */
+ public int getScaledWidth(DisplayMetrics metrics) {
+ return scaleFromDensity(getWidth(), mDensity, metrics.densityDpi);
+ }
+
+ /**
+ * Convenience for calling {@link #getScaledHeight(int)} with the target
+ * density of the given {@link DisplayMetrics}.
+ */
+ public int getScaledHeight(DisplayMetrics metrics) {
+ return scaleFromDensity(getHeight(), mDensity, metrics.densityDpi);
}
/**
* Convenience method that returns the width of this bitmap divided
* by the density scale factor.
*
- * @param metrics The target display metrics.
+ * @param targetDensity The density of the target canvas of the bitmap.
* @return The scaled width of this bitmap, according to the density scale factor.
*/
- public int getScaledWidth(DisplayMetrics metrics) {
- final float scale = mDensityScale;
- if (!mAutoScaling || scale < 0) {
- return getWidth();
- }
- return (int)(getWidth() * metrics.density / scale);
+ public int getScaledWidth(int targetDensity) {
+ return scaleFromDensity(getWidth(), mDensity, targetDensity);
}
/**
* Convenience method that returns the height of this bitmap divided
* by the density scale factor.
*
- * @param metrics The target display metrics.
+ * @param targetDensity The density of the target canvas of the bitmap.
* @return The scaled height of this bitmap, according to the density scale factor.
*/
- public int getScaledHeight(DisplayMetrics metrics) {
- final float scale = mDensityScale;
- if (!mAutoScaling || scale < 0) {
- return getHeight();
+ public int getScaledHeight(int targetDensity) {
+ return scaleFromDensity(getHeight(), mDensity, targetDensity);
+ }
+
+ /**
+ * @hide
+ */
+ static public int scaleFromDensity(int size, int sdensity, int tdensity) {
+ if (sdensity == DENSITY_NONE || sdensity == tdensity) {
+ return size;
}
- return (int)(getHeight() * metrics.density / scale);
+
+ // Scale by tdensity / sdensity, rounding up.
+ return ( (size * tdensity) + (sdensity >> 1) ) / sdensity;
}
-
+
/**
* Return the number of bytes between rows in the bitmap's pixels. Note that
* this refers to the pixels as stored natively by the bitmap. If you call
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 76abaa2..c8bed24 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -39,7 +39,6 @@ public class BitmapFactory {
*/
public Options() {
inDither = true;
- inDensity = 0;
inScaled = true;
}
@@ -79,22 +78,87 @@ public class BitmapFactory {
public boolean inDither;
/**
- * The desired pixel density of the bitmap.
+ * The pixel density to use for the bitmap. This will always result
+ * in the returned bitmap having a density set for it (see
+ * {@link Bitmap#setDensity(int) Bitmap.setDensity(int)). In addition,
+ * if {@link #inScaled} is set (which it is by default} and this
+ * density does not match {@link #inTargetDensity}, then the bitmap
+ * will be scaled to the target density before being returned.
+ *
+ * <p>If this is 0,
+ * {@link BitmapFactory#decodeResource(Resources, int)},
+ * {@link BitmapFactory#decodeResource(Resources, int, android.graphics.BitmapFactory.Options)},
+ * and {@link BitmapFactory#decodeResourceStream}
+ * will fill in the density associated with the resource. The other
+ * functions will leave it as-is and no density will be applied.
*
- * @see android.util.DisplayMetrics#DENSITY_DEFAULT
- * @see android.util.DisplayMetrics#density
+ * @see #inTargetDensity
+ * @see #inScreenDensity
+ * @see #inScaled
+ * @see Bitmap#setDensity(int)
+ * @see android.util.DisplayMetrics#densityDpi
*/
public int inDensity;
/**
- * </p>If the bitmap is loaded from {@link android.content.res.Resources} and
- * this flag is turned on, the bitmap will be scaled to match the default
- * display's pixel density.</p>
+ * The pixel density of the destination this bitmap will be drawn to.
+ * This is used in conjunction with {@link #inDensity} and
+ * {@link #inScaled} to determine if and how to scale the bitmap before
+ * returning it.
+ *
+ * <p>If this is 0,
+ * {@link BitmapFactory#decodeResource(Resources, int)},
+ * {@link BitmapFactory#decodeResource(Resources, int, android.graphics.BitmapFactory.Options)},
+ * and {@link BitmapFactory#decodeResourceStream}
+ * will fill in the density associated the Resources object's
+ * DisplayMetrics. The other
+ * functions will leave it as-is and no scaling for density will be
+ * performed.
+ *
+ * @see #inDensity
+ * @see #inScreenDensity
+ * @see #inScaled
+ * @see android.util.DisplayMetrics#densityDpi
+ */
+ public int inTargetDensity;
+
+ /**
+ * The pixel density of the actual screen that is being used. This is
+ * purely for applications running in density compatibility code, where
+ * {@link #inTargetDensity} is actually the density the application
+ * sees rather than the real screen density.
+ *
+ * <p>By setting this, you
+ * allow the loading code to avoid scaling a bitmap that is currently
+ * in the screen density up/down to the compatibility density. Instead,
+ * if {@link #inDensity} is the same as {@link #inScreenDensity}, the
+ * bitmap will be left as-is. Anything using the resulting bitmap
+ * must also used {@link Bitmap#getScaledWidth(int)
+ * Bitmap.getScaledWidth} and {@link Bitmap#getScaledHeight
+ * Bitmap.getScaledHeight} to account for any different between the
+ * bitmap's density and the target's density.
+ *
+ * <p>This is never set automatically for the caller by
+ * {@link BitmapFactory} itself. It must be explicitly set, since the
+ * caller must deal with the resulting bitmap in a density-aware way.
+ *
+ * @see #inDensity
+ * @see #inTargetDensity
+ * @see #inScaled
+ * @see android.util.DisplayMetrics#densityDpi
+ */
+ public int inScreenDensity;
+
+ /**
+ * When this flag is set, if {@link #inDensity} and
+ * {@link #inTargetDensity} are not 0, the
+ * bitmap will be scaled to match {@link #inTargetDensity} when loaded,
+ * rather than relying on the graphics system scaling it each time it
+ * is drawn to a Canvas.
*
- * </p>This flag is turned on by default and should be turned off if you need
- * a non-scaled version of the bitmap. In this case,
- * {@link android.graphics.Bitmap#setAutoScalingEnabled(boolean)} can be used
- * to properly scale the bitmap at drawing time.</p>
+ * <p>This flag is turned on by default and should be turned off if you need
+ * a non-scaled version of the bitmap. Nine-patch bitmaps ignore this
+ * flag and are always scaled.
*/
public boolean inScaled;
@@ -235,58 +299,32 @@ public class BitmapFactory {
* Decode a new Bitmap from an InputStream. This InputStream was obtained from
* resources, which we pass to be able to scale the bitmap accordingly.
*/
- public static Bitmap decodeStream(Resources res, TypedValue value, InputStream is,
- Rect pad, Options opts) {
+ public static Bitmap decodeResourceStream(Resources res, TypedValue value,
+ InputStream is, Rect pad, Options opts) {
if (opts == null) {
opts = new Options();
}
- Bitmap bm = decodeStream(is, pad, opts);
-
- if (bm != null && res != null && value != null) {
+ if (opts.inDensity == 0 && value != null) {
final int density = value.density;
- if (density == TypedValue.DENSITY_NONE) {
- return bm;
- }
-
- byte[] np = bm.getNinePatchChunk();
- final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np);
-
- if (opts.inDensity == 0) {
- opts.inDensity = density == TypedValue.DENSITY_DEFAULT ?
- DisplayMetrics.DENSITY_DEFAULT : density;
- }
- float scale = opts.inDensity / (float) DisplayMetrics.DENSITY_DEFAULT;
-
- if (opts.inScaled || isNinePatch) {
- bm.setDensityScale(1.0f);
- bm.setAutoScalingEnabled(false);
- // Assume we are going to prescale for the screen
- scale = res.getDisplayMetrics().density / scale;
- if (scale != 1.0f) {
- // TODO: This is very inefficient and should be done in native by Skia
- final Bitmap oldBitmap = bm;
- bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f),
- (int) (bm.getHeight() * scale + 0.5f), true);
- oldBitmap.recycle();
-
- if (isNinePatch) {
- np = nativeScaleNinePatch(np, scale, pad);
- bm.setNinePatchChunk(np);
- }
- }
- } else {
- bm.setDensityScale(scale);
- bm.setAutoScalingEnabled(true);
+ if (density == TypedValue.DENSITY_DEFAULT) {
+ opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;
+ } else if (density != TypedValue.DENSITY_NONE) {
+ opts.inDensity = density;
}
}
-
- return bm;
+
+ if (opts.inTargetDensity == 0 && res != null) {
+ opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
+ }
+
+ return decodeStream(is, pad, opts);
}
/**
- * Decode an image referenced by a resource ID.
+ * Synonym for opening the given resource and calling
+ * {@link #decodeResourceStream}.
*
* @param res The resources object containing the image data
* @param id The resource id of the image data
@@ -303,7 +341,7 @@ public class BitmapFactory {
final TypedValue value = new TypedValue();
final InputStream is = res.openRawResource(id, value);
- bm = decodeStream(res, value, is, null, opts);
+ bm = decodeResourceStream(res, value, is, null, opts);
is.close();
} catch (java.io.IOException e) {
/* do nothing.
@@ -315,7 +353,8 @@ public class BitmapFactory {
}
/**
- * Decode an image referenced by a resource ID.
+ * Synonym for {@link #decodeResource(Resources, int, android.graphics.BitmapFactory.Options)}
+ * will null Options.
*
* @param res The resources object containing the image data
* @param id The resource id of the image data
@@ -412,6 +451,39 @@ public class BitmapFactory {
bm = nativeDecodeStream(is, tempStorage, outPadding, opts);
}
+ if (bm == null || opts == null) {
+ return bm;
+ }
+
+ final int density = opts.inDensity;
+ if (density == 0) {
+ return bm;
+ }
+
+ bm.setDensity(density);
+ final int targetDensity = opts.inTargetDensity;
+ if (targetDensity == 0 || density == targetDensity
+ || density == opts.inScreenDensity) {
+ return bm;
+ }
+
+ byte[] np = bm.getNinePatchChunk();
+ final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np);
+ if (opts.inScaled || isNinePatch) {
+ float scale = targetDensity / (float)density;
+ // TODO: This is very inefficient and should be done in native by Skia
+ final Bitmap oldBitmap = bm;
+ bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f),
+ (int) (bm.getHeight() * scale + 0.5f), true);
+ oldBitmap.recycle();
+
+ if (isNinePatch) {
+ np = nativeScaleNinePatch(np, scale, outPadding);
+ bm.setNinePatchChunk(np);
+ }
+ bm.setDensity(targetDensity);
+ }
+
return bm;
}
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index da73597..8ecbfbd 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -20,6 +20,7 @@ import android.text.TextUtils;
import android.text.SpannedString;
import android.text.SpannableString;
import android.text.GraphicsOperations;
+import android.util.DisplayMetrics;
import javax.microedition.khronos.opengles.GL;
@@ -47,11 +48,12 @@ public class Canvas {
// optional field set by the caller
private DrawFilter mDrawFilter;
+ // Package-scoped for quick access.
+ /*package*/ int mDensity = DisplayMetrics.DENSITY_DEFAULT;
+
// Used by native code
@SuppressWarnings({"UnusedDeclaration"})
private int mSurfaceFormat;
- @SuppressWarnings({"UnusedDeclaration"})
- private float mDensityScale = 1.0f;
/**
* Construct an empty raster canvas. Use setBitmap() to specify a bitmap to
@@ -76,8 +78,9 @@ public class Canvas {
throwIfRecycled(bitmap);
mNativeCanvas = initRaster(bitmap.ni());
mBitmap = bitmap;
- mDensityScale = bitmap.getDensityScale();
- if (mDensityScale == Bitmap.DENSITY_SCALE_UNKNOWN) mDensityScale = 1.0f;
+ final int density = bitmap.mDensity;
+ mDensity = density == Bitmap.DENSITY_NONE
+ ? DisplayMetrics.DENSITY_DEFAULT : density;
}
/*package*/ Canvas(int nativeCanvas) {
@@ -132,8 +135,9 @@ public class Canvas {
native_setBitmap(mNativeCanvas, bitmap.ni());
mBitmap = bitmap;
- mDensityScale = bitmap.getDensityScale();
- if (mDensityScale == Bitmap.DENSITY_SCALE_UNKNOWN) mDensityScale = 1.0f;
+ final int density = bitmap.mDensity;
+ mDensity = density == Bitmap.DENSITY_NONE
+ ? DisplayMetrics.DENSITY_DEFAULT : density;
}
/**
@@ -172,44 +176,34 @@ public class Canvas {
public native int getHeight();
/**
- * <p>Returns the density scale for this Canvas' backing bitmap, expressed as a
- * factor of the default density (160dpi.) For instance, a bitmap designed for
- * 240dpi displays will have a density scale of 1.5 whereas a bitmap
- * designed for 160dpi will have a density scale of 1.0.</p>
+ * <p>Returns the density for this Canvas' backing bitmap.</p>
*
- * <p>The default density scale is {@link Bitmap#DENSITY_SCALE_UNKNOWN}.</p>
+ * <p>The default density scale is {@link Bitmap#DENSITY_NONE}.</p>
*
* @return A scaling factor of the default density (160dpi) or
- * {@link Bitmap#DENSITY_SCALE_UNKNOWN} if the scaling factor is unknown.
+ * {@link Bitmap#DENSITY_NONE} if the scaling factor is unknown.
*
- * @see #setDensityScale(float)
- * @see Bitmap#getDensityScale()
+ * @see #setDensity(int)
+ * @see Bitmap#getDensity()
*/
- public float getDensityScale() {
- if (mBitmap != null) {
- return mBitmap.getDensityScale();
- }
- return mDensityScale;
+ public int getDensity() {
+ return mDensity;
}
/**
- * <p>Specifies the density scale for this Canvas' backing bitmap, expressed as a
- * factor of the default density (160dpi.) For instance, a bitmap designed for
- * 240dpi displays will have a density scale of 1.5 whereas a bitmap
- * designed for 160dpi will have a density scale of 1.0.</p>
+ * <p>Specifies the density for this Canvas' backing bitmap.
*
- * @param densityScale The density scaling factor to use with this bitmap or
- * {@link Bitmap#DENSITY_SCALE_UNKNOWN} if the factor is unknown.
+ * @param density The density scaling factor to use with this bitmap or
+ * {@link Bitmap#DENSITY_NONE} if the factor is unknown.
*
- * @see #getDensityScale()
- * @see Bitmap#setDensityScale(float)
+ * @see #getDensity()
+ * @see Bitmap#setDensity(int)
*/
- public void setDensityScale(float densityScale) {
+ public void setDensity(int density) {
if (mBitmap != null) {
- mBitmap.setDensityScale(densityScale);
+ mBitmap.setDensity(density);
}
- mDensityScale = densityScale;
- if (mDensityScale == Bitmap.DENSITY_SCALE_UNKNOWN) mDensityScale = 1.0f;
+ mDensity = density;
}
// the SAVE_FLAG constants must match their native equivalents
@@ -945,12 +939,17 @@ public class Canvas {
/**
* Draw the specified bitmap, with its top/left corner at (x,y), using
* the specified paint, transformed by the current matrix.
- * Note: if the paint contains a maskfilter that generates a mask which
+ *
+ * <p>Note: if the paint contains a maskfilter that generates a mask which
* extends beyond the bitmap's original width/height (e.g. BlurMaskFilter),
* then the bitmap will be drawn as if it were in a Shader with CLAMP mode.
* Thus the color outside of the original width/height will be the edge
* color replicated.
*
+ * <p>If the bitmap and canvas have different densities, this function
+ * will take care of automatically scaling the bitmap to draw at the
+ * same density as the canvas.
+ *
* @param bitmap The bitmap to be drawn
* @param left The position of the left side of the bitmap being drawn
* @param top The position of the top side of the bitmap being drawn
@@ -959,20 +958,25 @@ public class Canvas {
public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
throwIfRecycled(bitmap);
native_drawBitmap(mNativeCanvas, bitmap.ni(), left, top,
- paint != null ? paint.mNativePaint : 0, bitmap.isAutoScalingEnabled(),
- bitmap.getDensityScale());
+ paint != null ? paint.mNativePaint : 0, mDensity, bitmap.mDensity);
}
/**
* Draw the specified bitmap, scaling/translating automatically to fill
* the destination rectangle. If the source rectangle is not null, it
* specifies the subset of the bitmap to draw.
- * Note: if the paint contains a maskfilter that generates a mask which
+ *
+ * <p>Note: if the paint contains a maskfilter that generates a mask which
* extends beyond the bitmap's original width/height (e.g. BlurMaskFilter),
* then the bitmap will be drawn as if it were in a Shader with CLAMP mode.
* Thus the color outside of the original width/height will be the edge
* color replicated.
*
+ * <p>This function <em>ignores the density associated with the bitmap</em>.
+ * This is because the source and destination rectangle coordinate
+ * spaces are in their respective densities, so must already have the
+ * appropriate scaling factor applied.
+ *
* @param bitmap The bitmap to be drawn
* @param src May be null. The subset of the bitmap to be drawn
* @param dst The rectangle that the bitmap will be scaled/translated
@@ -992,12 +996,18 @@ public class Canvas {
* Draw the specified bitmap, scaling/translating automatically to fill
* the destination rectangle. If the source rectangle is not null, it
* specifies the subset of the bitmap to draw.
- * Note: if the paint contains a maskfilter that generates a mask which
+ *
+ * <p>Note: if the paint contains a maskfilter that generates a mask which
* extends beyond the bitmap's original width/height (e.g. BlurMaskFilter),
* then the bitmap will be drawn as if it were in a Shader with CLAMP mode.
* Thus the color outside of the original width/height will be the edge
* color replicated.
*
+ * <p>This function <em>ignores the density associated with the bitmap</em>.
+ * This is because the source and destination rectangle coordinate
+ * spaces are in their respective densities, so must already have the
+ * appropriate scaling factor applied.
+ *
* @param bitmap The bitmap to be drawn
* @param src May be null. The subset of the bitmap to be drawn
* @param dst The rectangle that the bitmap will be scaled/translated
@@ -1489,8 +1499,8 @@ public class Canvas {
int paint);
private native void native_drawBitmap(int nativeCanvas, int bitmap,
float left, float top,
- int nativePaintOrZero, boolean autoScale,
- float densityScale);
+ int nativePaintOrZero,
+ int canvasDensity, int bitmapDensity);
private native void native_drawBitmap(int nativeCanvas, int bitmap,
Rect src, RectF dst,
int nativePaintOrZero);
diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java
index 778c903..88dfd67 100644
--- a/graphics/java/android/graphics/NinePatch.java
+++ b/graphics/java/android/graphics/NinePatch.java
@@ -68,7 +68,7 @@ public class NinePatch {
}
/**
- * Draw a bitmap to nine patches.
+ * Draw a bitmap of nine patches.
*
* @param canvas A container for the current matrix and clip used to draw the bitmap.
* @param location Where to draw the bitmap.
@@ -76,23 +76,25 @@ public class NinePatch {
public void draw(Canvas canvas, RectF location) {
nativeDraw(canvas.mNativeCanvas, location,
mBitmap.ni(), mChunk,
- mPaint != null ? mPaint.mNativePaint : 0);
+ mPaint != null ? mPaint.mNativePaint : 0,
+ canvas.mDensity, mBitmap.mDensity);
}
/**
- * Draw a bitmap to nine patches.
+ * Draw a bitmap of nine patches.
*
* @param canvas A container for the current matrix and clip used to draw the bitmap.
* @param location Where to draw the bitmap.
*/
public void draw(Canvas canvas, Rect location) {
nativeDraw(canvas.mNativeCanvas, location,
- mBitmap.ni(), mChunk,
- mPaint != null ? mPaint.mNativePaint : 0);
+ mBitmap.ni(), mChunk,
+ mPaint != null ? mPaint.mNativePaint : 0,
+ canvas.mDensity, mBitmap.mDensity);
}
/**
- * Draw a bitmap to nine patches.
+ * Draw a bitmap of nine patches.
*
* @param canvas A container for the current matrix and clip used to draw the bitmap.
* @param location Where to draw the bitmap.
@@ -100,9 +102,18 @@ public class NinePatch {
*/
public void draw(Canvas canvas, Rect location, Paint paint) {
nativeDraw(canvas.mNativeCanvas, location,
- mBitmap.ni(), mChunk, paint != null ? paint.mNativePaint : 0);
+ mBitmap.ni(), mChunk, paint != null ? paint.mNativePaint : 0,
+ canvas.mDensity, mBitmap.mDensity);
}
+ /**
+ * Return the underlying bitmap's density, as per
+ * {@link Bitmap#getDensity() Bitmap.getDensity()}.
+ */
+ public int getDensity() {
+ return mBitmap.mDensity;
+ }
+
public int getWidth() {
return mBitmap.getWidth();
}
@@ -129,9 +140,11 @@ public class NinePatch {
private static native void validateNinePatchChunk(int bitmap, byte[] chunk);
private static native void nativeDraw(int canvas_instance, RectF loc, int bitmap_instance,
- byte[] c, int paint_instance_or_null);
+ byte[] c, int paint_instance_or_null,
+ int destDensity, int srcDensity);
private static native void nativeDraw(int canvas_instance, Rect loc, int bitmap_instance,
- byte[] c, int paint_instance_or_null);
+ byte[] c, int paint_instance_or_null,
+ int destDensity, int srcDensity);
private static native int nativeGetTransparentRegion(
int bitmap, byte[] chunk, Rect location);
}
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 5b32246..eade73a 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -63,18 +63,56 @@ public class BitmapDrawable extends Drawable {
private boolean mApplyGravity;
private boolean mRebuildShader;
- private int mBitmapWidth;
- private int mBitmapHeight;
private boolean mMutated;
+
+ private int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
+ // These are scaled to match the target density.
+ private int mBitmapWidth;
+ private int mBitmapHeight;
+
+ /**
+ * Create an empty drawable, not dealing with density.
+ * @deprecated Use {@link #BitmapDrawable(Resources)} to ensure
+ * that the drawable has correctly set its target density.
+ */
public BitmapDrawable() {
mBitmapState = new BitmapState((Bitmap) null);
}
+ /**
+ * Create an empty drawable, setting initial target density based on
+ * the display metrics of the resources.
+ */
+ public BitmapDrawable(Resources res) {
+ mBitmapState = new BitmapState((Bitmap) null);
+ if (res != null) {
+ setTargetDensity(res.getDisplayMetrics());
+ mBitmapState.mTargetDensity = mTargetDensity;
+ }
+ }
+
+ /**
+ * Create drawable from a bitmap, not dealing with density.
+ * @deprecated Use {@link #BitmapDrawable(Resources, Bitmap)} to ensure
+ * that the drawable has correctly set its target density.
+ */
public BitmapDrawable(Bitmap bitmap) {
this(new BitmapState(bitmap));
}
+ /**
+ * Create drawable from a bitmap, setting initial target density based on
+ * the display metrics of the resources.
+ */
+ public BitmapDrawable(Resources res, Bitmap bitmap) {
+ this(new BitmapState(bitmap));
+ if (res != null) {
+ setTargetDensity(res.getDisplayMetrics());
+ mBitmapState.mTargetDensity = mTargetDensity;
+ }
+ }
+
public BitmapDrawable(String filepath) {
this(new BitmapState(BitmapFactory.decodeFile(filepath)));
if (mBitmap == null) {
@@ -97,11 +135,15 @@ public class BitmapDrawable extends Drawable {
return mBitmap;
}
+ private void computeBitmapSize() {
+ mBitmapWidth = mBitmap.getScaledWidth(mTargetDensity);
+ mBitmapHeight = mBitmap.getScaledHeight(mTargetDensity);
+ }
+
private void setBitmap(Bitmap bitmap) {
mBitmap = bitmap;
if (bitmap != null) {
- mBitmapWidth = bitmap.getWidth();
- mBitmapHeight = bitmap.getHeight();
+ computeBitmapSize();
} else {
mBitmapWidth = mBitmapHeight = -1;
}
@@ -114,13 +156,11 @@ public class BitmapDrawable extends Drawable {
*
* @param canvas The Canvas from which the density scale must be obtained.
*
- * @see android.graphics.Bitmap#setDensityScale(float)
- * @see android.graphics.Bitmap#getDensityScale()
- *
- * @hide pending API council approval
+ * @see android.graphics.Bitmap#setDensity(int)
+ * @see android.graphics.Bitmap#getDensity()
*/
- public void setDensityScale(Canvas canvas) {
- setDensityScale(canvas.getDensityScale());
+ public void setTargetDensity(Canvas canvas) {
+ setTargetDensity(canvas.getDensity());
}
/**
@@ -128,32 +168,33 @@ public class BitmapDrawable extends Drawable {
*
* @param metrics The DisplayMetrics indicating the density scale for this drawable.
*
- * @see android.graphics.Bitmap#setDensityScale(float)
- * @see android.graphics.Bitmap#getDensityScale()
- *
- * @hide pending API council approval
+ * @see android.graphics.Bitmap#setDensity(int)
+ * @see android.graphics.Bitmap#getDensity()
*/
- public void setDensityScale(DisplayMetrics metrics) {
- setDensityScale(metrics.density);
+ public void setTargetDensity(DisplayMetrics metrics) {
+ mTargetDensity = metrics.densityDpi;
+ if (mBitmap != null) {
+ computeBitmapSize();
+ }
}
/**
- * Set the density scale at which this drawable will be rendered.
+ * Set the density at which this drawable will be rendered.
*
* @param density The density scale for this drawable.
*
- * @see android.graphics.Bitmap#setDensityScale(float)
- * @see android.graphics.Bitmap#getDensityScale()
- *
- * @hide pending API council approval
+ * @see android.graphics.Bitmap#setDensity(int)
+ * @see android.graphics.Bitmap#getDensity()
*/
- public void setDensityScale(float density) {
- density = (density == Bitmap.DENSITY_SCALE_UNKNOWN ? 1.0f : density);
- mBitmapState.mTargetDensityScale = density;
+ public void setTargetDensity(int density) {
+ mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
+ if (mBitmap != null) {
+ computeBitmapSize();
+ }
}
/** Get the gravity used to position/stretch the bitmap within its bounds.
- See android.view.Gravity
+ * See android.view.Gravity
* @return the gravity applied to the bitmap
*/
public int getGravity() {
@@ -302,7 +343,7 @@ public class BitmapDrawable extends Drawable {
}
mBitmapState.mBitmap = bitmap;
setBitmap(bitmap);
- setDensityScale(r.getDisplayMetrics());
+ setTargetDensity(r.getDisplayMetrics());
final Paint paint = mBitmapState.mPaint;
paint.setAntiAlias(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_antialias,
@@ -332,29 +373,12 @@ public class BitmapDrawable extends Drawable {
@Override
public int getIntrinsicWidth() {
- final Bitmap bitmap = mBitmap;
- final BitmapState state = mBitmapState;
-
- if (!state.mAutoScale || state.mBitmapScale == Bitmap.DENSITY_SCALE_UNKNOWN) {
- return mBitmapWidth;
- } else {
- return bitmap != null ? (int) (mBitmapWidth /
- (state.mBitmapScale / state.mTargetDensityScale) + 0.5f) : -1;
-
- }
+ return mBitmapWidth;
}
@Override
public int getIntrinsicHeight() {
- final Bitmap bitmap = mBitmap;
- final BitmapState state = mBitmapState;
-
- if (!state.mAutoScale || state.mBitmapScale == Bitmap.DENSITY_SCALE_UNKNOWN) {
- return mBitmapHeight;
- } else {
- return bitmap != null ? (int) (mBitmapHeight /
- (state.mBitmapScale / state.mTargetDensityScale) + 0.5f) : -1;
- }
+ return mBitmapHeight;
}
@Override
@@ -380,19 +404,10 @@ public class BitmapDrawable extends Drawable {
Paint mPaint = new Paint(DEFAULT_PAINT_FLAGS);
Shader.TileMode mTileModeX;
Shader.TileMode mTileModeY;
- boolean mAutoScale;
- float mBitmapScale;
- float mTargetDensityScale = 1.0f;
+ int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
BitmapState(Bitmap bitmap) {
mBitmap = bitmap;
- if (bitmap != null) {
- mBitmapScale = bitmap.getDensityScale();
- mAutoScale = bitmap.isAutoScalingEnabled();
- } else {
- mBitmapScale = 1.0f;
- mAutoScale = false;
- }
}
BitmapState(BitmapState bitmapState) {
@@ -401,7 +416,7 @@ public class BitmapDrawable extends Drawable {
mGravity = bitmapState.mGravity;
mTileModeX = bitmapState.mTileModeX;
mTileModeY = bitmapState.mTileModeY;
- mTargetDensityScale = bitmapState.mTargetDensityScale;
+ mTargetDensity = bitmapState.mTargetDensity;
mPaint = new Paint(bitmapState.mPaint);
}
@@ -418,6 +433,7 @@ public class BitmapDrawable extends Drawable {
private BitmapDrawable(BitmapState state) {
mBitmapState = state;
+ mTargetDensity = state.mTargetDensity;
setBitmap(state.mBitmap);
}
}
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 910e111..0a0e4eb 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -27,6 +27,7 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.*;
import android.util.AttributeSet;
+import android.util.DisplayMetrics;
import android.util.StateSet;
import android.util.Xml;
import android.util.TypedValue;
@@ -657,9 +658,8 @@ public abstract class Drawable {
}
/**
- * Create a drawable from an inputstream
- *
- * @hide pending API council approval
+ * Create a drawable from an inputstream, using the given resources and
+ * value to determine density information.
*/
public static Drawable createFromResourceStream(Resources res, TypedValue value,
InputStream is, String srcName) {
@@ -675,7 +675,17 @@ public abstract class Drawable {
Rects only to drop them on the floor.
*/
Rect pad = new Rect();
- Bitmap bm = BitmapFactory.decodeStream(res, value, is, pad, null);
+
+ // Special stuff for compatibility mode: if the target density is not
+ // the same as the display density, but the resource -is- the same as
+ // the display density, then don't scale it down to the target density.
+ // This allows us to load the system's density-correct resources into
+ // an application in compatibility mode, without scaling those down
+ // to the compatibility density only to have them scaled back up when
+ // drawn to the screen.
+ BitmapFactory.Options opts = new BitmapFactory.Options();
+ opts.inScreenDensity = DisplayMetrics.DENSITY_DEVICE;
+ Bitmap bm = BitmapFactory.decodeResourceStream(res, value, is, pad, opts);
if (bm != null) {
byte[] np = bm.getNinePatchChunk();
if (np == null || !NinePatch.isNinePatchChunk(np)) {
@@ -754,10 +764,13 @@ public abstract class Drawable {
} else if (name.equals("bitmap")) {
drawable = new BitmapDrawable();
if (r != null) {
- ((BitmapDrawable) drawable).setDensityScale(r.getDisplayMetrics());
+ ((BitmapDrawable) drawable).setTargetDensity(r.getDisplayMetrics());
}
} else if (name.equals("nine-patch")) {
drawable = new NinePatchDrawable();
+ if (r != null) {
+ ((NinePatchDrawable) drawable).setTargetDensity(r.getDisplayMetrics());
+ }
} else {
throw new XmlPullParserException(parser.getPositionDescription() +
": invalid drawable tag " + name);
@@ -812,15 +825,10 @@ public abstract class Drawable {
Rect pad, String srcName) {
if (np != null) {
- return new NinePatchDrawable(bm, np, pad, srcName);
+ return new NinePatchDrawable(res, bm, np, pad, srcName);
}
- final BitmapDrawable drawable = new BitmapDrawable(bm);
- if (res != null) {
- drawable.setDensityScale(res.getDisplayMetrics());
- }
-
- return drawable;
+ return new BitmapDrawable(res, bm);
}
}
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index dace96c..d5c8a08 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -20,6 +20,7 @@ import android.graphics.*;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.util.AttributeSet;
+import android.util.DisplayMetrics;
import android.util.TypedValue;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -41,24 +42,122 @@ public class NinePatchDrawable extends Drawable {
private Paint mPaint;
private boolean mMutated;
+ private int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
+
+ // These are scaled to match the target density.
+ private int mBitmapWidth;
+ private int mBitmapHeight;
+
NinePatchDrawable() {
}
+ /**
+ * Create drawable from raw nine-patch data, not dealing with density.
+ * @deprecated Use {@link #NinePatchDrawable(Resources, Bitmap, byte[], Rect, String)}
+ * to ensure that the drawable has correctly set its target density.
+ */
public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) {
this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding));
}
+ /**
+ * Create drawable from raw nine-patch data, setting initial target density
+ * based on the display metrics of the resources.
+ */
+ public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk,
+ Rect padding, String srcName) {
+ this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding));
+ if (res != null) {
+ setTargetDensity(res.getDisplayMetrics());
+ mNinePatchState.mTargetDensity = mTargetDensity;
+ }
+ }
+
+ /**
+ * Create drawable from existing nine-patch, not dealing with density.
+ * @deprecated Use {@link #NinePatchDrawable(Resources, NinePatch)}
+ * to ensure that the drawable has correctly set its target density.
+ */
public NinePatchDrawable(NinePatch patch) {
this(new NinePatchState(patch, null));
}
+ /**
+ * Create drawable from existing nine-patch, setting initial target density
+ * based on the display metrics of the resources.
+ */
+ public NinePatchDrawable(Resources res, NinePatch patch) {
+ this(new NinePatchState(patch, null));
+ if (res != null) {
+ setTargetDensity(res.getDisplayMetrics());
+ mNinePatchState.mTargetDensity = mTargetDensity;
+ }
+ }
+
private void setNinePatchState(NinePatchState state) {
mNinePatchState = state;
mNinePatch = state.mNinePatch;
mPadding = state.mPadding;
+ mTargetDensity = state.mTargetDensity;
if (state.mDither) setDither(state.mDither);
+ if (mNinePatch != null) {
+ computeBitmapSize();
+ }
}
+ /**
+ * Set the density scale at which this drawable will be rendered. This
+ * method assumes the drawable will be rendered at the same density as the
+ * specified canvas.
+ *
+ * @param canvas The Canvas from which the density scale must be obtained.
+ *
+ * @see android.graphics.Bitmap#setDensity(int)
+ * @see android.graphics.Bitmap#getDensity()
+ */
+ public void setTargetDensity(Canvas canvas) {
+ setTargetDensity(canvas.getDensity());
+ }
+
+ /**
+ * Set the density scale at which this drawable will be rendered.
+ *
+ * @param metrics The DisplayMetrics indicating the density scale for this drawable.
+ *
+ * @see android.graphics.Bitmap#setDensity(int)
+ * @see android.graphics.Bitmap#getDensity()
+ */
+ public void setTargetDensity(DisplayMetrics metrics) {
+ mTargetDensity = metrics.densityDpi;
+ if (mNinePatch != null) {
+ computeBitmapSize();
+ }
+ }
+
+ /**
+ * Set the density at which this drawable will be rendered.
+ *
+ * @param density The density scale for this drawable.
+ *
+ * @see android.graphics.Bitmap#setDensity(int)
+ * @see android.graphics.Bitmap#getDensity()
+ */
+ public void setTargetDensity(int density) {
+ mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
+ if (mNinePatch != null) {
+ computeBitmapSize();
+ }
+ }
+
+ private void computeBitmapSize() {
+ final int sdensity = mNinePatch.getDensity();
+ final int tdensity = mTargetDensity;
+ mBitmapWidth = Bitmap.scaleFromDensity(mNinePatch.getWidth(),
+ sdensity, tdensity);
+ mBitmapHeight = Bitmap.scaleFromDensity(mNinePatch.getHeight(),
+ sdensity, tdensity);
+ }
+
// overrides
@Override
@@ -111,6 +210,7 @@ public class NinePatchDrawable extends Drawable {
if (dither) {
options.inDither = false;
}
+ options.inScreenDensity = DisplayMetrics.DENSITY_DEVICE;
final Rect padding = new Rect();
Bitmap bitmap = null;
@@ -119,7 +219,7 @@ public class NinePatchDrawable extends Drawable {
final TypedValue value = new TypedValue();
final InputStream is = r.openRawResource(id, value);
- bitmap = BitmapFactory.decodeStream(r, value, is, padding, options);
+ bitmap = BitmapFactory.decodeResourceStream(r, value, is, padding, options);
is.close();
} catch (IOException e) {
@@ -136,6 +236,7 @@ public class NinePatchDrawable extends Drawable {
setNinePatchState(new NinePatchState(
new NinePatch(bitmap, bitmap.getNinePatchChunk(), "XML 9-patch"), padding, dither));
+ mNinePatchState.mTargetDensity = mTargetDensity;
a.recycle();
}
@@ -153,7 +254,7 @@ public class NinePatchDrawable extends Drawable {
*/
@Override
public int getIntrinsicWidth() {
- return mNinePatch.getWidth();
+ return mBitmapWidth;
}
/**
@@ -161,17 +262,17 @@ public class NinePatchDrawable extends Drawable {
*/
@Override
public int getIntrinsicHeight() {
- return mNinePatch.getHeight();
+ return mBitmapHeight;
}
@Override
public int getMinimumWidth() {
- return mNinePatch.getWidth();
+ return mBitmapWidth;
}
@Override
public int getMinimumHeight() {
- return mNinePatch.getHeight();
+ return mBitmapHeight;
}
/**
@@ -211,6 +312,7 @@ public class NinePatchDrawable extends Drawable {
final Rect mPadding;
final boolean mDither;
int mChangingConfigurations;
+ int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
NinePatchState(NinePatch ninePatch, Rect padding) {
this(ninePatch, padding, false);
@@ -225,8 +327,9 @@ public class NinePatchDrawable extends Drawable {
NinePatchState(NinePatchState state) {
mNinePatch = new NinePatch(state.mNinePatch);
mPadding = new Rect(state.mPadding);
- mChangingConfigurations = state.mChangingConfigurations;
mDither = state.mDither;
+ mChangingConfigurations = state.mChangingConfigurations;
+ mTargetDensity = state.mTargetDensity;
}
@Override
diff --git a/tests/DpiTest/res/drawable-hdpi/npatch240dpi.9.png b/tests/DpiTest/res/drawable-hdpi/npatch240dpi.9.png
new file mode 100644
index 0000000..a362b0f
--- /dev/null
+++ b/tests/DpiTest/res/drawable-hdpi/npatch240dpi.9.png
Binary files differ
diff --git a/tests/DpiTest/res/drawable-hdpi/smlnpatch240dpi.9.png b/tests/DpiTest/res/drawable-hdpi/smlnpatch240dpi.9.png
new file mode 100644
index 0000000..84bdcb0
--- /dev/null
+++ b/tests/DpiTest/res/drawable-hdpi/smlnpatch240dpi.9.png
Binary files differ
diff --git a/tests/DpiTest/res/drawable-ldpi/npatch120dpi.9.png b/tests/DpiTest/res/drawable-ldpi/npatch120dpi.9.png
new file mode 100644
index 0000000..0d8115b
--- /dev/null
+++ b/tests/DpiTest/res/drawable-ldpi/npatch120dpi.9.png
Binary files differ
diff --git a/tests/DpiTest/res/drawable-ldpi/smlnpatch120dpi.9.png b/tests/DpiTest/res/drawable-ldpi/smlnpatch120dpi.9.png
new file mode 100644
index 0000000..de8d607
--- /dev/null
+++ b/tests/DpiTest/res/drawable-ldpi/smlnpatch120dpi.9.png
Binary files differ
diff --git a/tests/DpiTest/res/drawable/npatch160dpi.9.png b/tests/DpiTest/res/drawable/npatch160dpi.9.png
new file mode 100644
index 0000000..44d89a9
--- /dev/null
+++ b/tests/DpiTest/res/drawable/npatch160dpi.9.png
Binary files differ
diff --git a/tests/DpiTest/res/drawable/smlnpatch160dpi.9.png b/tests/DpiTest/res/drawable/smlnpatch160dpi.9.png
new file mode 100644
index 0000000..76c4ae8
--- /dev/null
+++ b/tests/DpiTest/res/drawable/smlnpatch160dpi.9.png
Binary files differ
diff --git a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
index dd4fae3..68220a1 100644
--- a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
+++ b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
@@ -34,6 +34,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.CompatibilityInfo;
import android.util.DisplayMetrics;
+import android.util.Log;
public class DpiTestActivity extends Activity {
public DpiTestActivity() {
@@ -116,6 +117,13 @@ public class DpiTestActivity extends Activity {
addLabelToRoot(root, "No-dpi resource drawable");
addChildToRoot(root, layout);
+ layout = new LinearLayout(this);
+ addNinePatchResourceDrawable(layout, R.drawable.smlnpatch120dpi);
+ addNinePatchResourceDrawable(layout, R.drawable.smlnpatch160dpi);
+ addNinePatchResourceDrawable(layout, R.drawable.smlnpatch240dpi);
+ addLabelToRoot(root, "Prescaled 9-patch resource drawable");
+ addChildToRoot(root, layout);
+
setContentView(scrollWrap(root));
}
@@ -144,8 +152,8 @@ public class DpiTestActivity extends Activity {
View view = new View(this);
- final BitmapDrawable d = new BitmapDrawable(bitmap);
- if (!scale) d.setDensityScale(getResources().getDisplayMetrics());
+ final BitmapDrawable d = new BitmapDrawable(getResources(), bitmap);
+ if (!scale) d.setTargetDensity(getResources().getDisplayMetrics());
view.setBackgroundDrawable(d);
view.setLayoutParams(new LinearLayout.LayoutParams(d.getIntrinsicWidth(),
@@ -175,6 +183,19 @@ public class DpiTestActivity extends Activity {
layout.addView(view);
}
+ private void addNinePatchResourceDrawable(LinearLayout layout, int resource) {
+ View view = new View(this);
+
+ final Drawable d = getResources().getDrawable(resource);
+ view.setBackgroundDrawable(d);
+
+ Log.i("foo", "9-patch #" + Integer.toHexString(resource)
+ + " w=" + d.getIntrinsicWidth() + " h=" + d.getIntrinsicHeight());
+ view.setLayoutParams(new LinearLayout.LayoutParams(
+ d.getIntrinsicWidth()*2, d.getIntrinsicHeight()*2));
+ layout.addView(view);
+ }
+
private Bitmap loadAndPrintDpi(int id, boolean scale) {
Bitmap bitmap;
if (scale) {