summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Kenny Root <kroot@google.com> 2010-10-28 14:47:01 -0700
committer Kenny Root <kroot@google.com> 2010-10-29 12:47:07 -0700
commit55fc850cf992cdcb0993cb109d2f716613c0dbdd (patch)
tree2277f806e14fb8a6b422dde687ac9779176ae83b
parent490d7c5deda8d602f916942d7002757082274b9b (diff)
Add path to get different DPI drawables
Allow a caller to request a different density than their current display allows. This can mean a device displaying mdpi can get a resource that's in hdpi and have it pretend to be in mdpi resolution. If a drawable that's returned is not in the requested density, it will set it at the appropriate density to be scaled up later on. The API for this is hidden currently. Bug: 3134688 Change-Id: I6c3908cbdef4907b8d3f1576df9e3b0e7af1755a
-rw-r--r--core/java/android/content/res/AssetManager.java9
-rwxr-xr-xcore/java/android/content/res/Resources.java69
-rw-r--r--core/jni/android_util_AssetManager.cpp5
-rw-r--r--include/utils/ResourceTypes.h8
-rw-r--r--libs/utils/ResourceTypes.cpp44
5 files changed, 115 insertions, 20 deletions
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 73d9458fbec3..e279f64fb7bc 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -149,7 +149,7 @@ public final class AssetManager {
/*package*/ final CharSequence getResourceText(int ident) {
synchronized (this) {
TypedValue tmpValue = mValue;
- int block = loadResourceValue(ident, tmpValue, true);
+ int block = loadResourceValue(ident, (short) 0, tmpValue, true);
if (block >= 0) {
if (tmpValue.type == TypedValue.TYPE_STRING) {
return mStringBlocks[block].get(tmpValue.data);
@@ -190,10 +190,11 @@ public final class AssetManager {
/*package*/ final boolean getResourceValue(int ident,
+ int density,
TypedValue outValue,
boolean resolveRefs)
{
- int block = loadResourceValue(ident, outValue, resolveRefs);
+ int block = loadResourceValue(ident, (short) density, outValue, resolveRefs);
if (block >= 0) {
if (outValue.type != TypedValue.TYPE_STRING) {
return true;
@@ -681,8 +682,8 @@ public final class AssetManager {
/** Returns true if the resource was found, filling in mRetStringBlock and
* mRetData. */
- private native final int loadResourceValue(int ident, TypedValue outValue,
- boolean resolve);
+ private native final int loadResourceValue(int ident, short density, TypedValue outValue,
+ boolean resolve);
/** Returns true if the resource was found, filling in mRetStringBlock and
* mRetData. */
private native final int loadResourceBagValue(int ident, int bagEntryId, TypedValue outValue,
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 9b23c1ea8965..e6fd039c839f 100755
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -628,6 +628,50 @@ public class Resources {
}
/**
+ * Return a drawable object associated with a particular resource ID for the
+ * given screen density in DPI. This will set the drawable's density to be
+ * the device's density multiplied by the ratio of actual drawable density
+ * to requested density. This allows the drawable to be scaled up to the
+ * correct size if needed. Various types of objects will be returned
+ * depending on the underlying resource -- for example, a solid color, PNG
+ * image, scalable image, etc. The Drawable API hides these implementation
+ * details.
+ *
+ * @param id The desired resource identifier, as generated by the aapt tool.
+ * This integer encodes the package, type, and resource entry.
+ * The value 0 is an invalid identifier.
+ * @param density the desired screen density indicated by the resource as
+ * found in {@link DisplayMetrics}.
+ * @throws NotFoundException Throws NotFoundException if the given ID does
+ * not exist.
+ * @return Drawable An object that can be used to draw this resource.
+ * @hide
+ */
+ public Drawable getDrawableForDensity(int id, int density) throws NotFoundException {
+ synchronized (mTmpValue) {
+ TypedValue value = mTmpValue;
+ getValueForDensity(id, density, value, true);
+
+ /*
+ * Pretend the requested density is actually the display density. If
+ * the drawable returned is not the requested density, then force it
+ * to be scaled later by dividing its density by the ratio of
+ * requested density to actual device density. Drawables that have
+ * undefined density or no density don't need to be handled here.
+ */
+ if (value.density > 0 && value.density != TypedValue.DENSITY_NONE) {
+ if (value.density == density) {
+ value.density = DisplayMetrics.DENSITY_DEVICE;
+ } else {
+ value.density = (value.density * DisplayMetrics.DENSITY_DEVICE) / density;
+ }
+ }
+
+ return loadDrawable(value, id);
+ }
+ }
+
+ /**
* Return a movie object associated with the particular resource ID.
* @param id The desired resource identifier, as generated by the aapt
* tool. This integer encodes the package, type, and resource
@@ -930,7 +974,7 @@ public class Resources {
*/
public void getValue(int id, TypedValue outValue, boolean resolveRefs)
throws NotFoundException {
- boolean found = mAssets.getResourceValue(id, outValue, resolveRefs);
+ boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs);
if (found) {
return;
}
@@ -939,6 +983,29 @@ public class Resources {
}
/**
+ * Get the raw value associated with a resource with associated density.
+ *
+ * @param id resource identifier
+ * @param density density in DPI
+ * @param resolveRefs If true, a resource that is a reference to another
+ * resource will be followed so that you receive the actual final
+ * resource data. If false, the TypedValue will be filled in with
+ * the reference itself.
+ * @throws NotFoundException Throws NotFoundException if the given ID does
+ * not exist.
+ * @see #getValue(String, TypedValue, boolean)
+ * @hide
+ */
+ public void getValueForDensity(int id, int density, TypedValue outValue, boolean resolveRefs)
+ throws NotFoundException {
+ boolean found = mAssets.getResourceValue(id, density, outValue, resolveRefs);
+ if (found) {
+ return;
+ }
+ throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
+ }
+
+ /**
* Return the raw data associated with a particular resource ID.
* See getIdentifier() for information on how names are mapped to resource
* IDs, and getString(int) for information on how string resources are
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index f3b935733b28..c4056a44ee79 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -701,6 +701,7 @@ static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jo
static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
jint ident,
+ jshort density,
jobject outValue,
jboolean resolve)
{
@@ -713,7 +714,7 @@ static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject
Res_value value;
ResTable_config config;
uint32_t typeSpecFlags;
- ssize_t block = res.getResource(ident, &value, false, &typeSpecFlags, &config);
+ ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);
#if THROW_ON_BAD_ID
if (block == BAD_INDEX) {
jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
@@ -1703,7 +1704,7 @@ static JNINativeMethod gAssetManagerMethods[] = {
(void*) android_content_AssetManager_getResourceTypeName },
{ "getResourceEntryName","(I)Ljava/lang/String;",
(void*) android_content_AssetManager_getResourceEntryName },
- { "loadResourceValue","(ILandroid/util/TypedValue;Z)I",
+ { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
(void*) android_content_AssetManager_loadResourceValue },
{ "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
(void*) android_content_AssetManager_loadResourceBagValue },
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index da86da41006d..ed7f53d17128 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -1771,12 +1771,14 @@ public:
*
* @return ssize_t Either a >= 0 table index or a negative error code.
*/
- ssize_t getResource(uint32_t resID, Res_value* outValue, bool mayBeBag=false,
- uint32_t* outSpecFlags=NULL, ResTable_config* outConfig=NULL) const;
+ ssize_t getResource(uint32_t resID, Res_value* outValue, bool mayBeBag = false,
+ uint16_t density = 0,
+ uint32_t* outSpecFlags = NULL,
+ ResTable_config* outConfig = NULL) const;
inline ssize_t getResource(const ResTable_ref& res, Res_value* outValue,
uint32_t* outSpecFlags=NULL) const {
- return getResource(res.ident, outValue, false, outSpecFlags, NULL);
+ return getResource(res.ident, outValue, false, 0, outSpecFlags, NULL);
}
ssize_t resolveReference(Res_value* inOutValue,
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 91e7df3ef5b7..03d2e217a7fa 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -1896,7 +1896,7 @@ bool ResTable::getResourceName(uint32_t resID, resource_name* outName) const
return false;
}
-ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag,
+ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag, uint16_t density,
uint32_t* outSpecFlags, ResTable_config* outConfig) const
{
if (mError != NO_ERROR) {
@@ -1926,7 +1926,7 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag
memset(&bestItem, 0, sizeof(bestItem)); // make the compiler shut up
if (outSpecFlags != NULL) *outSpecFlags = 0;
-
+
// Look through all resource packages, starting with the most
// recently added.
const PackageGroup* const grp = mPackageGroups[p];
@@ -1934,6 +1934,22 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag
LOGW("Bad identifier when getting value for resource number 0x%08x", resID);
return BAD_INDEX;
}
+
+ // Allow overriding density
+ const ResTable_config* desiredConfig = &mParams;
+ ResTable_config* overrideConfig = NULL;
+ if (density > 0) {
+ overrideConfig = (ResTable_config*) malloc(sizeof(ResTable_config));
+ if (overrideConfig == NULL) {
+ LOGE("Couldn't malloc ResTable_config for overrides: %s", strerror(errno));
+ return BAD_INDEX;
+ }
+ memcpy(overrideConfig, &mParams, sizeof(ResTable_config));
+ overrideConfig->density = density;
+ desiredConfig = overrideConfig;
+ }
+
+ ssize_t rc = BAD_INDEX;
size_t ip = grp->packages.size();
while (ip > 0) {
ip--;
@@ -1943,12 +1959,13 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag
const ResTable_type* type;
const ResTable_entry* entry;
const Type* typeClass;
- ssize_t offset = getEntry(package, t, e, &mParams, &type, &entry, &typeClass);
+ ssize_t offset = getEntry(package, t, e, desiredConfig, &type, &entry, &typeClass);
if (offset <= 0) {
if (offset < 0) {
LOGW("Failure getting entry for 0x%08x (t=%d e=%d) in package %zd (error %d)\n",
resID, t, e, ip, (int)offset);
- return offset;
+ rc = offset;
+ goto out;
}
continue;
}
@@ -1963,13 +1980,14 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag
TABLE_NOISY(aout << "Resource type data: "
<< HexDump(type, dtohl(type->header.size)) << endl);
-
+
if ((size_t)offset > (dtohl(type->header.size)-sizeof(Res_value))) {
LOGW("ResTable_item at %d is beyond type chunk data %d",
(int)offset, dtohl(type->header.size));
- return BAD_TYPE;
+ rc = BAD_TYPE;
+ goto out;
}
-
+
const Res_value* item =
(const Res_value*)(((const uint8_t*)type) + offset);
ResTable_config thisConfig;
@@ -2011,10 +2029,16 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag
outValue->data, &len)).string()
: "",
outValue->data));
- return bestPackage->header->index;
+ rc = bestPackage->header->index;
+ goto out;
+ }
+
+out:
+ if (overrideConfig != NULL) {
+ free(overrideConfig);
}
- return BAD_VALUE;
+ return rc;
}
ssize_t ResTable::resolveReference(Res_value* value, ssize_t blockIndex,
@@ -2027,7 +2051,7 @@ ssize_t ResTable::resolveReference(Res_value* value, ssize_t blockIndex,
if (outLastRef) *outLastRef = value->data;
uint32_t lastRef = value->data;
uint32_t newFlags = 0;
- const ssize_t newIndex = getResource(value->data, value, true, &newFlags,
+ const ssize_t newIndex = getResource(value->data, value, true, 0, &newFlags,
outConfig);
if (newIndex == BAD_INDEX) {
return BAD_INDEX;