am f33c0f85: Merge "CalendarView rendering: use R.styleable to find attr." into mnc-dev
* commit 'f33c0f8516768b0259c750fdb14946f5a9b68647': CalendarView rendering: use R.styleable to find attr.
This commit is contained in:
@@ -50,6 +50,7 @@ import java.lang.ref.SoftReference;
|
|||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -93,7 +94,7 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
|
|||||||
/**
|
/**
|
||||||
* Same as sRMap except for int[] instead of int resources. This is for android.R only.
|
* Same as sRMap except for int[] instead of int resources. This is for android.R only.
|
||||||
*/
|
*/
|
||||||
private final static Map<IntArray, String> sRArrayMap = new HashMap<IntArray, String>();
|
private final static Map<IntArray, String> sRArrayMap = new HashMap<IntArray, String>(384);
|
||||||
/**
|
/**
|
||||||
* Reverse map compared to sRMap, resource type -> (resource name -> id).
|
* Reverse map compared to sRMap, resource type -> (resource name -> id).
|
||||||
* This is for com.android.internal.R.
|
* This is for com.android.internal.R.
|
||||||
@@ -249,37 +250,56 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
|
|||||||
// the internal version), and put the content in the maps.
|
// the internal version), and put the content in the maps.
|
||||||
try {
|
try {
|
||||||
Class<?> r = com.android.internal.R.class;
|
Class<?> r = com.android.internal.R.class;
|
||||||
|
// Parse the styleable class first, since it may contribute to attr values.
|
||||||
|
parseStyleable();
|
||||||
|
|
||||||
for (Class<?> inner : r.getDeclaredClasses()) {
|
for (Class<?> inner : r.getDeclaredClasses()) {
|
||||||
|
if (inner == com.android.internal.R.styleable.class) {
|
||||||
|
// Already handled the styleable case. Not skipping attr, as there may be attrs
|
||||||
|
// that are not referenced from styleables.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
String resTypeName = inner.getSimpleName();
|
String resTypeName = inner.getSimpleName();
|
||||||
ResourceType resType = ResourceType.getEnum(resTypeName);
|
ResourceType resType = ResourceType.getEnum(resTypeName);
|
||||||
if (resType != null) {
|
if (resType != null) {
|
||||||
Map<String, Integer> fullMap = new HashMap<String, Integer>();
|
Map<String, Integer> fullMap = null;
|
||||||
sRevRMap.put(resType, fullMap);
|
switch (resType) {
|
||||||
|
case ATTR:
|
||||||
|
fullMap = sRevRMap.get(ResourceType.ATTR);
|
||||||
|
break;
|
||||||
|
case STRING:
|
||||||
|
case STYLE:
|
||||||
|
// Slightly less than thousand entries in each.
|
||||||
|
fullMap = new HashMap<String, Integer>(1280);
|
||||||
|
// no break.
|
||||||
|
default:
|
||||||
|
if (fullMap == null) {
|
||||||
|
fullMap = new HashMap<String, Integer>();
|
||||||
|
}
|
||||||
|
sRevRMap.put(resType, fullMap);
|
||||||
|
}
|
||||||
|
|
||||||
for (Field f : inner.getDeclaredFields()) {
|
for (Field f : inner.getDeclaredFields()) {
|
||||||
// only process static final fields. Since the final attribute may have
|
// only process static final fields. Since the final attribute may have
|
||||||
// been altered by layoutlib_create, we only check static
|
// been altered by layoutlib_create, we only check static
|
||||||
int modifiers = f.getModifiers();
|
if (!isValidRField(f)) {
|
||||||
if (Modifier.isStatic(modifiers)) {
|
continue;
|
||||||
Class<?> type = f.getType();
|
}
|
||||||
if (type.isArray() && type.getComponentType() == int.class) {
|
Class<?> type = f.getType();
|
||||||
// if the object is an int[] we put it in sRArrayMap using an IntArray
|
if (type.isArray()) {
|
||||||
// wrapper that properly implements equals and hashcode for the array
|
// if the object is an int[] we put it in sRArrayMap using an IntArray
|
||||||
// objects, as required by the map contract.
|
// wrapper that properly implements equals and hashcode for the array
|
||||||
sRArrayMap.put(new IntArray((int[]) f.get(null)), f.getName());
|
// objects, as required by the map contract.
|
||||||
} else if (type == int.class) {
|
sRArrayMap.put(new IntArray((int[]) f.get(null)), f.getName());
|
||||||
Integer value = (Integer) f.get(null);
|
} else {
|
||||||
sRMap.put(value, Pair.of(resType, f.getName()));
|
Integer value = (Integer) f.get(null);
|
||||||
fullMap.put(f.getName(), value);
|
sRMap.put(value, Pair.of(resType, f.getName()));
|
||||||
} else {
|
fullMap.put(f.getName(), value);
|
||||||
assert false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable throwable) {
|
} catch (Exception throwable) {
|
||||||
if (log != null) {
|
if (log != null) {
|
||||||
log.error(LayoutLog.TAG_BROKEN,
|
log.error(LayoutLog.TAG_BROKEN,
|
||||||
"Failed to load com.android.internal.R from the layout library jar",
|
"Failed to load com.android.internal.R from the layout library jar",
|
||||||
@@ -291,6 +311,90 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if the field is pubic, static and one of int or int[].
|
||||||
|
*/
|
||||||
|
private static boolean isValidRField(Field field) {
|
||||||
|
int modifiers = field.getModifiers();
|
||||||
|
boolean isAcceptable = Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers);
|
||||||
|
Class<?> type = field.getType();
|
||||||
|
return isAcceptable && type == int.class ||
|
||||||
|
(type.isArray() && type.getComponentType() == int.class);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void parseStyleable() throws Exception {
|
||||||
|
// R.attr doesn't contain all the needed values. There are too many resources in the
|
||||||
|
// framework for all to be in the R class. Only the ones specified manually in
|
||||||
|
// res/values/symbols.xml are put in R class. Since, we need to create a map of all attr
|
||||||
|
// values, we try and find them from the styleables.
|
||||||
|
|
||||||
|
// There were 1500 elements in this map at M timeframe.
|
||||||
|
Map<String, Integer> revRAttrMap = new HashMap<String, Integer>(2048);
|
||||||
|
sRevRMap.put(ResourceType.ATTR, revRAttrMap);
|
||||||
|
// There were 2000 elements in this map at M timeframe.
|
||||||
|
Map<String, Integer> revRStyleableMap = new HashMap<String, Integer>(3072);
|
||||||
|
sRevRMap.put(ResourceType.STYLEABLE, revRStyleableMap);
|
||||||
|
Class<?> c = com.android.internal.R.styleable.class;
|
||||||
|
Field[] fields = c.getDeclaredFields();
|
||||||
|
// Sort the fields to bring all arrays to the beginning, so that indices into the array are
|
||||||
|
// able to refer back to the arrays (i.e. no forward references).
|
||||||
|
Arrays.sort(fields, new Comparator<Field>() {
|
||||||
|
@Override
|
||||||
|
public int compare(Field o1, Field o2) {
|
||||||
|
if (o1 == o2) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Class<?> t1 = o1.getType();
|
||||||
|
Class<?> t2 = o2.getType();
|
||||||
|
if (t1.isArray() && !t2.isArray()) {
|
||||||
|
return -1;
|
||||||
|
} else if (t2.isArray() && !t1.isArray()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return o1.getName().compareTo(o2.getName());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Map<String, int[]> styleables = new HashMap<String, int[]>();
|
||||||
|
for (Field field : fields) {
|
||||||
|
if (!isValidRField(field)) {
|
||||||
|
// Only consider public static fields that are int or int[].
|
||||||
|
// Don't check the final flag as it may have been modified by layoutlib_create.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String name = field.getName();
|
||||||
|
if (field.getType().isArray()) {
|
||||||
|
int[] styleableValue = (int[]) field.get(null);
|
||||||
|
sRArrayMap.put(new IntArray(styleableValue), name);
|
||||||
|
styleables.put(name, styleableValue);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Not an array.
|
||||||
|
String arrayName = name;
|
||||||
|
int[] arrayValue = null;
|
||||||
|
int index;
|
||||||
|
while ((index = arrayName.lastIndexOf('_')) >= 0) {
|
||||||
|
// Find the name of the corresponding styleable.
|
||||||
|
// Search in reverse order so that attrs like LinearLayout_Layout_layout_gravity
|
||||||
|
// are mapped to LinearLayout_Layout and not to LinearLayout.
|
||||||
|
arrayName = arrayName.substring(0, index);
|
||||||
|
arrayValue = styleables.get(arrayName);
|
||||||
|
if (arrayValue != null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index = (Integer) field.get(null);
|
||||||
|
if (arrayValue != null) {
|
||||||
|
String attrName = name.substring(arrayName.length() + 1);
|
||||||
|
int attrValue = arrayValue[index];
|
||||||
|
sRMap.put(attrValue, Pair.of(ResourceType.ATTR, attrName));
|
||||||
|
revRAttrMap.put(attrName, attrValue);
|
||||||
|
}
|
||||||
|
sRMap.put(index, Pair.of(ResourceType.STYLEABLE, name));
|
||||||
|
revRStyleableMap.put(name, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean dispose() {
|
public boolean dispose() {
|
||||||
BridgeAssetManager.clearSystem();
|
BridgeAssetManager.clearSystem();
|
||||||
|
|||||||
Reference in New Issue
Block a user