Distinguish unspecified and explicit null values in resources
BUG: 17919345 Change-Id: Ic4f04f7dd0f986f58a749b5950d80c1cfdb074ea
This commit is contained in:
@@ -9260,6 +9260,7 @@ package android.content.res {
|
||||
method public int getType(int);
|
||||
method public boolean getValue(int, android.util.TypedValue);
|
||||
method public boolean hasValue(int);
|
||||
method public boolean hasValueOrEmpty(int);
|
||||
method public int length();
|
||||
method public android.util.TypedValue peekValue(int);
|
||||
method public void recycle();
|
||||
@@ -32172,6 +32173,8 @@ package android.util {
|
||||
field public static final int COMPLEX_UNIT_PX = 0; // 0x0
|
||||
field public static final int COMPLEX_UNIT_SHIFT = 0; // 0x0
|
||||
field public static final int COMPLEX_UNIT_SP = 2; // 0x2
|
||||
field public static final int DATA_NULL_EMPTY = 1; // 0x1
|
||||
field public static final int DATA_NULL_UNDEFINED = 0; // 0x0
|
||||
field public static final int DENSITY_DEFAULT = 0; // 0x0
|
||||
field public static final int DENSITY_NONE = 65535; // 0xffff
|
||||
field public static final int TYPE_ATTRIBUTE = 2; // 0x2
|
||||
|
||||
@@ -807,6 +807,9 @@ public class TypedArray {
|
||||
|
||||
/**
|
||||
* Determines whether there is an attribute at <var>index</var>.
|
||||
* <p>
|
||||
* <strong>Note:</strong> If the attribute was set to {@code @empty} or
|
||||
* {@code @undefined}, this method returns {@code false}.
|
||||
*
|
||||
* @param index Index of attribute to retrieve.
|
||||
*
|
||||
@@ -823,6 +826,27 @@ public class TypedArray {
|
||||
return type != TypedValue.TYPE_NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether there is an attribute at <var>index</var>, returning
|
||||
* {@code true} if the attribute was explicitly set to {@code @empty} and
|
||||
* {@code false} only if the attribute was undefined.
|
||||
*
|
||||
* @param index Index of attribute to retrieve.
|
||||
*
|
||||
* @return True if the attribute has a value or is empty, false otherwise.
|
||||
*/
|
||||
public boolean hasValueOrEmpty(int index) {
|
||||
if (mRecycled) {
|
||||
throw new RuntimeException("Cannot make calls to a recycled instance!");
|
||||
}
|
||||
|
||||
index *= AssetManager.STYLE_NUM_ENTRIES;
|
||||
final int[] data = mData;
|
||||
final int type = data[index+AssetManager.STYLE_TYPE];
|
||||
return type != TypedValue.TYPE_NULL
|
||||
|| data[index+AssetManager.STYLE_DATA] == TypedValue.DATA_NULL_EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the raw TypedValue for the attribute at <var>index</var>
|
||||
* and return a temporary object holding its data. This object is only
|
||||
|
||||
@@ -138,6 +138,17 @@ public class TypedValue {
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* {@link #TYPE_NULL} data indicating the value was not specified.
|
||||
*/
|
||||
public static final int DATA_NULL_UNDEFINED = 0;
|
||||
/**
|
||||
* {@link #TYPE_NULL} data indicating the value was explicitly set to null.
|
||||
*/
|
||||
public static final int DATA_NULL_EMPTY = 1;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* If {@link #density} is equal to this value, then the density should be
|
||||
* treated as the system's default density value: {@link DisplayMetrics#DENSITY_DEFAULT}.
|
||||
|
||||
@@ -1095,7 +1095,7 @@ static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject c
|
||||
// coming from, first XML attributes, then XML style, then default
|
||||
// style, and finally the theme.
|
||||
value.dataType = Res_value::TYPE_NULL;
|
||||
value.data = 0;
|
||||
value.data = Res_value::DATA_NULL_UNDEFINED;
|
||||
typeSetFlags = 0;
|
||||
config.density = 0;
|
||||
|
||||
@@ -1157,6 +1157,7 @@ static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject c
|
||||
if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
|
||||
DEBUG_STYLES(ALOGI("-> Setting to @null!"));
|
||||
value.dataType = Res_value::TYPE_NULL;
|
||||
value.data = Res_value::DATA_NULL_UNDEFINED;
|
||||
block = -1;
|
||||
}
|
||||
|
||||
@@ -1319,7 +1320,7 @@ static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject cla
|
||||
// coming from, first XML attributes, then XML style, then default
|
||||
// style, and finally the theme.
|
||||
value.dataType = Res_value::TYPE_NULL;
|
||||
value.data = 0;
|
||||
value.data = Res_value::DATA_NULL_UNDEFINED;
|
||||
typeSetFlags = 0;
|
||||
config.density = 0;
|
||||
|
||||
@@ -1403,6 +1404,7 @@ static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject cla
|
||||
if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
|
||||
DEBUG_STYLES(ALOGI("-> Setting to @null!"));
|
||||
value.dataType = Res_value::TYPE_NULL;
|
||||
value.data = Res_value::DATA_NULL_UNDEFINED;
|
||||
block = kXmlBlock;
|
||||
}
|
||||
|
||||
@@ -1512,7 +1514,7 @@ static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, job
|
||||
|
||||
// Try to find a value for this attribute...
|
||||
value.dataType = Res_value::TYPE_NULL;
|
||||
value.data = 0;
|
||||
value.data = Res_value::DATA_NULL_UNDEFINED;
|
||||
typeSetFlags = 0;
|
||||
config.density = 0;
|
||||
|
||||
@@ -1548,6 +1550,7 @@ static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, job
|
||||
// Deal with the special @null value -- it turns back to TYPE_NULL.
|
||||
if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
|
||||
value.dataType = Res_value::TYPE_NULL;
|
||||
value.data = Res_value::DATA_NULL_UNDEFINED;
|
||||
}
|
||||
|
||||
//printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
|
||||
@@ -1661,6 +1664,7 @@ static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject claz
|
||||
// Deal with the special @null value -- it turns back to TYPE_NULL.
|
||||
if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
|
||||
value.dataType = Res_value::TYPE_NULL;
|
||||
value.data = Res_value::DATA_NULL_UNDEFINED;
|
||||
}
|
||||
|
||||
//printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
|
||||
|
||||
@@ -1091,16 +1091,16 @@ please see styles_device_defaults.xml.
|
||||
<!-- Dialog styles -->
|
||||
|
||||
<style name="AlertDialog.Material" parent="AlertDialog">
|
||||
<item name="fullDark">@null</item>
|
||||
<item name="topDark">@null</item>
|
||||
<item name="centerDark">@null</item>
|
||||
<item name="bottomDark">@null</item>
|
||||
<item name="fullBright">@null</item>
|
||||
<item name="topBright">@null</item>
|
||||
<item name="centerBright">@null</item>
|
||||
<item name="bottomBright">@null</item>
|
||||
<item name="bottomMedium">@null</item>
|
||||
<item name="centerMedium">@null</item>
|
||||
<item name="fullDark">@empty</item>
|
||||
<item name="topDark">@empty</item>
|
||||
<item name="centerDark">@empty</item>
|
||||
<item name="bottomDark">@empty</item>
|
||||
<item name="fullBright">@empty</item>
|
||||
<item name="topBright">@empty</item>
|
||||
<item name="centerBright">@empty</item>
|
||||
<item name="bottomBright">@empty</item>
|
||||
<item name="bottomMedium">@empty</item>
|
||||
<item name="centerMedium">@empty</item>
|
||||
<item name="layout">@layout/alert_dialog_material</item>
|
||||
<item name="listLayout">@layout/select_dialog_material</item>
|
||||
<item name="progressLayout">@layout/progress_dialog_material</item>
|
||||
|
||||
@@ -253,7 +253,8 @@ struct Res_value
|
||||
|
||||
// Type of the data value.
|
||||
enum {
|
||||
// Contains no data.
|
||||
// The 'data' is either 0 or 1, specifying this resource is either
|
||||
// undefined or empty, respectively.
|
||||
TYPE_NULL = 0x00,
|
||||
// The 'data' holds a ResTable_ref, a reference to another resource
|
||||
// table entry.
|
||||
@@ -351,6 +352,14 @@ struct Res_value
|
||||
COMPLEX_MANTISSA_MASK = 0xffffff
|
||||
};
|
||||
|
||||
// Possible data values for TYPE_NULL.
|
||||
enum {
|
||||
// The value is not defined.
|
||||
DATA_NULL_UNDEFINED = 0,
|
||||
// The value is explicitly defined as empty.
|
||||
DATA_NULL_EMPTY = 1
|
||||
};
|
||||
|
||||
// The data for this item, as interpreted according to dataType.
|
||||
uint32_t data;
|
||||
|
||||
|
||||
@@ -4639,8 +4639,15 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
|
||||
|
||||
// It's a reference!
|
||||
if (len == 5 && s[1]=='n' && s[2]=='u' && s[3]=='l' && s[4]=='l') {
|
||||
// Special case @null as undefined. This will be converted by
|
||||
// AssetManager to TYPE_NULL with data DATA_NULL_UNDEFINED.
|
||||
outValue->data = 0;
|
||||
return true;
|
||||
} else if (len == 6 && s[1]=='e' && s[2]=='m' && s[3]=='p' && s[4]=='t' && s[5]=='y') {
|
||||
// Special case @empty as explicitly defined empty value.
|
||||
outValue->dataType = Res_value::TYPE_NULL;
|
||||
outValue->data = Res_value::DATA_NULL_EMPTY;
|
||||
return true;
|
||||
} else {
|
||||
bool createIfNotFound = false;
|
||||
const char16_t* resourceRefName;
|
||||
@@ -6251,7 +6258,14 @@ String8 ResTable::normalizeForOutput( const char *input )
|
||||
void ResTable::print_value(const Package* pkg, const Res_value& value) const
|
||||
{
|
||||
if (value.dataType == Res_value::TYPE_NULL) {
|
||||
printf("(null)\n");
|
||||
if (value.data == Res_value::DATA_NULL_UNDEFINED) {
|
||||
printf("(null)\n");
|
||||
} else if (value.data == Res_value::DATA_NULL_EMPTY) {
|
||||
printf("(null empty)\n");
|
||||
} else {
|
||||
// This should never happen.
|
||||
printf("(null) 0x%08x\n", value.data);
|
||||
}
|
||||
} else if (value.dataType == Res_value::TYPE_REFERENCE) {
|
||||
printf("(reference) 0x%08x\n", value.data);
|
||||
} else if (value.dataType == Res_value::TYPE_DYNAMIC_REFERENCE) {
|
||||
|
||||
Reference in New Issue
Block a user