();
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
public boolean dispose() {
BridgeAssetManager.clearSystem();
// dispose of the default typeface.
Typeface_Delegate.resetDefaults();
return true;
}
/**
* Starts a layout session by inflating and rendering it. The method returns a
* {@link RenderSession} on which further actions can be taken.
*
* @param params the {@link SessionParams} object with all the information necessary to create
* the scene.
* @return a new {@link RenderSession} object that contains the result of the layout.
* @since 5
*/
@Override
public RenderSession createSession(SessionParams params) {
try {
Result lastResult = SUCCESS.createResult();
RenderSessionImpl scene = new RenderSessionImpl(params);
try {
prepareThread();
lastResult = scene.init(params.getTimeout());
if (lastResult.isSuccess()) {
lastResult = scene.inflate();
if (lastResult.isSuccess()) {
lastResult = scene.render(true /*freshRender*/);
}
}
} finally {
scene.release();
cleanupThread();
}
return new BridgeRenderSession(scene, lastResult);
} catch (Throwable t) {
// get the real cause of the exception.
Throwable t2 = t;
while (t2.getCause() != null) {
t2 = t.getCause();
}
return new BridgeRenderSession(null,
ERROR_UNKNOWN.createResult(t2.getMessage(), t));
}
}
@Override
public Result renderDrawable(DrawableParams params) {
try {
Result lastResult = SUCCESS.createResult();
RenderDrawable action = new RenderDrawable(params);
try {
prepareThread();
lastResult = action.init(params.getTimeout());
if (lastResult.isSuccess()) {
lastResult = action.render();
}
} finally {
action.release();
cleanupThread();
}
return lastResult;
} catch (Throwable t) {
// get the real cause of the exception.
Throwable t2 = t;
while (t2.getCause() != null) {
t2 = t.getCause();
}
return ERROR_UNKNOWN.createResult(t2.getMessage(), t);
}
}
@Override
public void clearCaches(Object projectKey) {
if (projectKey != null) {
sProjectBitmapCache.remove(projectKey);
sProject9PatchCache.remove(projectKey);
}
}
@Override
public Result getViewParent(Object viewObject) {
if (viewObject instanceof View) {
return Status.SUCCESS.createResult(((View)viewObject).getParent());
}
throw new IllegalArgumentException("viewObject is not a View");
}
@Override
public Result getViewIndex(Object viewObject) {
if (viewObject instanceof View) {
View view = (View) viewObject;
ViewParent parentView = view.getParent();
if (parentView instanceof ViewGroup) {
Status.SUCCESS.createResult(((ViewGroup) parentView).indexOfChild(view));
}
return Status.SUCCESS.createResult();
}
throw new IllegalArgumentException("viewObject is not a View");
}
@Override
public boolean isRtl(String locale) {
return isLocaleRtl(locale);
}
public static boolean isLocaleRtl(String locale) {
if (locale == null) {
locale = "";
}
ULocale uLocale = new ULocale(locale);
return uLocale.getCharacterOrientation().equals(ICU_LOCALE_DIRECTION_RTL);
}
/**
* Returns the lock for the bridge
*/
public static ReentrantLock getLock() {
return sLock;
}
/**
* Prepares the current thread for rendering.
*
* Note that while this can be called several time, the first call to {@link #cleanupThread()}
* will do the clean-up, and make the thread unable to do further scene actions.
*/
public static void prepareThread() {
// we need to make sure the Looper has been initialized for this thread.
// this is required for View that creates Handler objects.
if (Looper.myLooper() == null) {
Looper.prepareMainLooper();
}
}
/**
* Cleans up thread-specific data. After this, the thread cannot be used for scene actions.
*
* Note that it doesn't matter how many times {@link #prepareThread()} was called, a single
* call to this will prevent the thread from doing further scene actions
*/
public static void cleanupThread() {
// clean up the looper
Looper_Accessor.cleanupThread();
}
public static LayoutLog getLog() {
return sCurrentLog;
}
public static void setLog(LayoutLog log) {
// check only the thread currently owning the lock can do this.
if (!sLock.isHeldByCurrentThread()) {
throw new IllegalStateException("scene must be acquired first. see #acquire(long)");
}
if (log != null) {
sCurrentLog = log;
} else {
sCurrentLog = sDefaultLog;
}
}
/**
* Returns details of a framework resource from its integer value.
* @param value the integer value
* @return a Pair containing the resource type and name, or null if the id
* does not match any resource.
*/
public static Pair resolveResourceId(int value) {
Pair pair = sRMap.get(value);
if (pair == null) {
pair = sDynamicIds.resolveId(value);
if (pair == null) {
//System.out.println(String.format("Missing id: %1$08X (%1$d)", value));
}
}
return pair;
}
/**
* Returns the name of a framework resource whose value is an int array.
*/
public static String resolveResourceId(int[] array) {
sIntArrayWrapper.set(array);
return sRArrayMap.get(sIntArrayWrapper);
}
/**
* Returns the integer id of a framework resource, from a given resource type and resource name.
*
* If no resource is found, it creates a dynamic id for the resource.
*
* @param type the type of the resource
* @param name the name of the resource.
*
* @return an {@link Integer} containing the resource id.
*/
@NonNull
public static Integer getResourceId(ResourceType type, String name) {
Map map = sRevRMap.get(type);
Integer value = null;
if (map != null) {
value = map.get(name);
}
return value == null ? sDynamicIds.getId(type, name) : value;
}
/**
* Returns the list of possible enums for a given attribute name.
*/
public static Map getEnumValues(String attributeName) {
if (sEnumValueMap != null) {
return sEnumValueMap.get(attributeName);
}
return null;
}
/**
* Returns the platform build properties.
*/
public static Map getPlatformProperties() {
return sPlatformProperties;
}
/**
* Returns the bitmap for a specific path, from a specific project cache, or from the
* framework cache.
* @param value the path of the bitmap
* @param projectKey the key of the project, or null to query the framework cache.
* @return the cached Bitmap or null if not found.
*/
public static Bitmap getCachedBitmap(String value, Object projectKey) {
if (projectKey != null) {
Map> map = sProjectBitmapCache.get(projectKey);
if (map != null) {
SoftReference ref = map.get(value);
if (ref != null) {
return ref.get();
}
}
} else {
SoftReference ref = sFrameworkBitmapCache.get(value);
if (ref != null) {
return ref.get();
}
}
return null;
}
/**
* Sets a bitmap in a project cache or in the framework cache.
* @param value the path of the bitmap
* @param bmp the Bitmap object
* @param projectKey the key of the project, or null to put the bitmap in the framework cache.
*/
public static void setCachedBitmap(String value, Bitmap bmp, Object projectKey) {
if (projectKey != null) {
Map> map = sProjectBitmapCache.get(projectKey);
if (map == null) {
map = new HashMap>();
sProjectBitmapCache.put(projectKey, map);
}
map.put(value, new SoftReference(bmp));
} else {
sFrameworkBitmapCache.put(value, new SoftReference(bmp));
}
}
/**
* Returns the 9 patch chunk for a specific path, from a specific project cache, or from the
* framework cache.
* @param value the path of the 9 patch
* @param projectKey the key of the project, or null to query the framework cache.
* @return the cached 9 patch or null if not found.
*/
public static NinePatchChunk getCached9Patch(String value, Object projectKey) {
if (projectKey != null) {
Map> map = sProject9PatchCache.get(projectKey);
if (map != null) {
SoftReference ref = map.get(value);
if (ref != null) {
return ref.get();
}
}
} else {
SoftReference ref = sFramework9PatchCache.get(value);
if (ref != null) {
return ref.get();
}
}
return null;
}
/**
* Sets a 9 patch chunk in a project cache or in the framework cache.
* @param value the path of the 9 patch
* @param ninePatch the 9 patch object
* @param projectKey the key of the project, or null to put the bitmap in the framework cache.
*/
public static void setCached9Patch(String value, NinePatchChunk ninePatch, Object projectKey) {
if (projectKey != null) {
Map> map = sProject9PatchCache.get(projectKey);
if (map == null) {
map = new HashMap>();
sProject9PatchCache.put(projectKey, map);
}
map.put(value, new SoftReference(ninePatch));
} else {
sFramework9PatchCache.put(value, new SoftReference(ninePatch));
}
}
}