diff options
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 Binary files differnew file mode 100644 index 0000000..a362b0f --- /dev/null +++ b/tests/DpiTest/res/drawable-hdpi/npatch240dpi.9.png diff --git a/tests/DpiTest/res/drawable-hdpi/smlnpatch240dpi.9.png b/tests/DpiTest/res/drawable-hdpi/smlnpatch240dpi.9.png Binary files differnew file mode 100644 index 0000000..84bdcb0 --- /dev/null +++ b/tests/DpiTest/res/drawable-hdpi/smlnpatch240dpi.9.png diff --git a/tests/DpiTest/res/drawable-ldpi/npatch120dpi.9.png b/tests/DpiTest/res/drawable-ldpi/npatch120dpi.9.png Binary files differnew file mode 100644 index 0000000..0d8115b --- /dev/null +++ b/tests/DpiTest/res/drawable-ldpi/npatch120dpi.9.png diff --git a/tests/DpiTest/res/drawable-ldpi/smlnpatch120dpi.9.png b/tests/DpiTest/res/drawable-ldpi/smlnpatch120dpi.9.png Binary files differnew file mode 100644 index 0000000..de8d607 --- /dev/null +++ b/tests/DpiTest/res/drawable-ldpi/smlnpatch120dpi.9.png diff --git a/tests/DpiTest/res/drawable/npatch160dpi.9.png b/tests/DpiTest/res/drawable/npatch160dpi.9.png Binary files differnew file mode 100644 index 0000000..44d89a9 --- /dev/null +++ b/tests/DpiTest/res/drawable/npatch160dpi.9.png diff --git a/tests/DpiTest/res/drawable/smlnpatch160dpi.9.png b/tests/DpiTest/res/drawable/smlnpatch160dpi.9.png Binary files differnew file mode 100644 index 0000000..76c4ae8 --- /dev/null +++ b/tests/DpiTest/res/drawable/smlnpatch160dpi.9.png 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) { |