summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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) {