summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/ViewDebug.java644
1 files changed, 252 insertions, 392 deletions
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 8a1fd62c0201..ad59ae5d2bee 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -32,6 +32,7 @@ import android.graphics.RenderNode;
import android.os.Debug;
import android.os.Handler;
import android.os.Looper;
+import android.os.Message;
import android.os.RemoteException;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -46,6 +47,7 @@ import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
+import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -53,12 +55,12 @@ import java.lang.annotation.Target;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.ArrayDeque;
-import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.concurrent.Callable;
-import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
@@ -68,6 +70,7 @@ import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;
+import java.util.stream.Stream;
/**
* Various debugging/tracing tools related to {@link View} and the view hierarchy.
@@ -331,11 +334,83 @@ public class ViewDebug {
public View findHierarchyView(String className, int hashCode);
}
- private static HashMap<Class<?>, Method[]> mCapturedViewMethodsForClasses = null;
- private static HashMap<Class<?>, Field[]> mCapturedViewFieldsForClasses = null;
+ private abstract static class PropertyInfo<T extends Annotation,
+ R extends AccessibleObject & Member> {
+
+ public final R member;
+ public final T property;
+ public final String name;
+ public final Class<?> returnType;
+
+ public String entrySuffix = "";
+ public String valueSuffix = "";
+
+ PropertyInfo(Class<T> property, R member, Class<?> returnType) {
+ this.member = member;
+ this.name = member.getName();
+ this.property = member.getAnnotation(property);
+ this.returnType = returnType;
+ }
+
+ public abstract Object invoke(Object target) throws Exception;
+
+ static <T extends Annotation> PropertyInfo<T, ?> forMethod(Method method,
+ Class<T> property) {
+ // Ensure the method return and parameter types can be resolved.
+ try {
+ if ((method.getReturnType() == Void.class)
+ || (method.getParameterTypes().length != 0)) {
+ return null;
+ }
+ } catch (NoClassDefFoundError e) {
+ return null;
+ }
+ if (!method.isAnnotationPresent(property)) {
+ return null;
+ }
+ method.setAccessible(true);
+
+ PropertyInfo info = new MethodPI(method, property);
+ info.entrySuffix = "()";
+ info.valueSuffix = ";";
+ return info;
+ }
+
+ static <T extends Annotation> PropertyInfo<T, ?> forField(Field field, Class<T> property) {
+ if (!field.isAnnotationPresent(property)) {
+ return null;
+ }
+ field.setAccessible(true);
+ return new FieldPI<>(field, property);
+ }
+ }
+
+ private static class MethodPI<T extends Annotation> extends PropertyInfo<T, Method> {
+
+ MethodPI(Method method, Class<T> property) {
+ super(property, method, method.getReturnType());
+ }
+
+ @Override
+ public Object invoke(Object target) throws Exception {
+ return member.invoke(target);
+ }
+ }
+
+ private static class FieldPI<T extends Annotation> extends PropertyInfo<T, Field> {
+
+ FieldPI(Field field, Class<T> property) {
+ super(property, field, field.getType());
+ }
+
+ @Override
+ public Object invoke(Object target) throws Exception {
+ return member.get(target);
+ }
+ }
// Maximum delay in ms after which we stop trying to capture a View's drawing
- private static final int CAPTURE_TIMEOUT = 4000;
+ private static final int CAPTURE_TIMEOUT = 6000;
private static final String REMOTE_COMMAND_CAPTURE = "CAPTURE";
private static final String REMOTE_COMMAND_DUMP = "DUMP";
@@ -346,9 +421,9 @@ public class ViewDebug {
private static final String REMOTE_COMMAND_CAPTURE_LAYERS = "CAPTURE_LAYERS";
private static final String REMOTE_COMMAND_OUTPUT_DISPLAYLIST = "OUTPUT_DISPLAYLIST";
- private static HashMap<Class<?>, Field[]> sFieldsForClasses;
- private static HashMap<Class<?>, Method[]> sMethodsForClasses;
- private static HashMap<AccessibleObject, ExportedProperty> sAnnotations;
+ private static HashMap<Class<?>, PropertyInfo<ExportedProperty, ?>[]> sExportProperties;
+ private static HashMap<Class<?>, PropertyInfo<CapturedViewProperty, ?>[]>
+ sCapturedViewProperties;
/**
* @deprecated This enum is now unused
@@ -1157,6 +1232,69 @@ public class ViewDebug {
private static void dumpViewHierarchy(Context context, ViewGroup group,
BufferedWriter out, int level, boolean skipChildren, boolean includeProperties) {
+ cacheExportedProperties(group.getClass());
+ if (!skipChildren) {
+ cacheExportedPropertiesForChildren(group);
+ }
+ // Try to use the handler provided by the view
+ Handler handler = group.getHandler();
+ // Fall back on using the main thread
+ if (handler == null) {
+ handler = new Handler(Looper.getMainLooper());
+ }
+
+ if (handler.getLooper() == Looper.myLooper()) {
+ dumpViewHierarchyOnUIThread(context, group, out, level, skipChildren,
+ includeProperties);
+ } else {
+ FutureTask task = new FutureTask(() ->
+ dumpViewHierarchyOnUIThread(context, group, out, level, skipChildren,
+ includeProperties), null);
+ Message msg = Message.obtain(handler, task);
+ msg.setAsynchronous(true);
+ handler.sendMessage(msg);
+ while (true) {
+ try {
+ task.get(CAPTURE_TIMEOUT, java.util.concurrent.TimeUnit.MILLISECONDS);
+ return;
+ } catch (InterruptedException e) {
+ // try again
+ } catch (ExecutionException | TimeoutException e) {
+ // Something unexpected happened.
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ }
+
+ private static void cacheExportedPropertiesForChildren(ViewGroup group) {
+ final int count = group.getChildCount();
+ for (int i = 0; i < count; i++) {
+ final View view = group.getChildAt(i);
+ cacheExportedProperties(view.getClass());
+ if (view instanceof ViewGroup) {
+ cacheExportedPropertiesForChildren((ViewGroup) view);
+ }
+ }
+ }
+
+ private static void cacheExportedProperties(Class<?> klass) {
+ if (sExportProperties != null && sExportProperties.containsKey(klass)) {
+ return;
+ }
+ do {
+ for (PropertyInfo<ExportedProperty, ?> info : getExportedProperties(klass)) {
+ if (!info.returnType.isPrimitive() && info.property.deepExport()) {
+ cacheExportedProperties(info.returnType);
+ }
+ }
+ klass = klass.getSuperclass();
+ } while (klass != Object.class);
+ }
+
+
+ private static void dumpViewHierarchyOnUIThread(Context context, ViewGroup group,
+ BufferedWriter out, int level, boolean skipChildren, boolean includeProperties) {
if (!dumpView(context, group, out, level, includeProperties)) {
return;
}
@@ -1169,16 +1307,16 @@ public class ViewDebug {
for (int i = 0; i < count; i++) {
final View view = group.getChildAt(i);
if (view instanceof ViewGroup) {
- dumpViewHierarchy(context, (ViewGroup) view, out, level + 1, skipChildren,
- includeProperties);
+ dumpViewHierarchyOnUIThread(context, (ViewGroup) view, out, level + 1,
+ skipChildren, includeProperties);
} else {
dumpView(context, view, out, level + 1, includeProperties);
}
if (view.mOverlay != null) {
ViewOverlay overlay = view.getOverlay();
ViewGroup overlayContainer = overlay.mOverlayViewGroup;
- dumpViewHierarchy(context, overlayContainer, out, level + 2, skipChildren,
- includeProperties);
+ dumpViewHierarchyOnUIThread(context, overlayContainer, out, level + 2,
+ skipChildren, includeProperties);
}
}
if (group instanceof HierarchyHandler) {
@@ -1212,81 +1350,28 @@ public class ViewDebug {
return true;
}
- private static Field[] getExportedPropertyFields(Class<?> klass) {
- if (sFieldsForClasses == null) {
- sFieldsForClasses = new HashMap<Class<?>, Field[]>();
- }
- if (sAnnotations == null) {
- sAnnotations = new HashMap<AccessibleObject, ExportedProperty>(512);
- }
-
- final HashMap<Class<?>, Field[]> map = sFieldsForClasses;
-
- Field[] fields = map.get(klass);
- if (fields != null) {
- return fields;
- }
-
- try {
- final Field[] declaredFields = klass.getDeclaredFieldsUnchecked(false);
- final ArrayList<Field> foundFields = new ArrayList<Field>();
- for (final Field field : declaredFields) {
- // Fields which can't be resolved have a null type.
- if (field.getType() != null && field.isAnnotationPresent(ExportedProperty.class)) {
- field.setAccessible(true);
- foundFields.add(field);
- sAnnotations.put(field, field.getAnnotation(ExportedProperty.class));
- }
- }
- fields = foundFields.toArray(new Field[foundFields.size()]);
- map.put(klass, fields);
- } catch (NoClassDefFoundError e) {
- throw new AssertionError(e);
- }
-
- return fields;
+ private static <T extends Annotation> PropertyInfo<T, ?>[] convertToPropertyInfos(
+ Method[] methods, Field[] fields, Class<T> property) {
+ return Stream.of(Arrays.stream(methods).map(m -> PropertyInfo.forMethod(m, property)),
+ Arrays.stream(fields).map(f -> PropertyInfo.forField(f, property)))
+ .flatMap(Function.identity())
+ .filter(i -> i != null)
+ .toArray(PropertyInfo[]::new);
}
- private static Method[] getExportedPropertyMethods(Class<?> klass) {
- if (sMethodsForClasses == null) {
- sMethodsForClasses = new HashMap<Class<?>, Method[]>(100);
- }
- if (sAnnotations == null) {
- sAnnotations = new HashMap<AccessibleObject, ExportedProperty>(512);
- }
-
- final HashMap<Class<?>, Method[]> map = sMethodsForClasses;
-
- Method[] methods = map.get(klass);
- if (methods != null) {
- return methods;
+ private static PropertyInfo<ExportedProperty, ?>[] getExportedProperties(Class<?> klass) {
+ if (sExportProperties == null) {
+ sExportProperties = new HashMap<>();
}
+ final HashMap<Class<?>, PropertyInfo<ExportedProperty, ?>[]> map = sExportProperties;
+ PropertyInfo<ExportedProperty, ?>[] properties = sExportProperties.get(klass);
- methods = klass.getDeclaredMethodsUnchecked(false);
-
- final ArrayList<Method> foundMethods = new ArrayList<Method>();
- for (final Method method : methods) {
- // Ensure the method return and parameter types can be resolved.
- try {
- method.getReturnType();
- method.getParameterTypes();
- } catch (NoClassDefFoundError e) {
- continue;
- }
-
- if (method.getParameterTypes().length == 0 &&
- method.isAnnotationPresent(ExportedProperty.class) &&
- method.getReturnType() != Void.class) {
- method.setAccessible(true);
- foundMethods.add(method);
- sAnnotations.put(method, method.getAnnotation(ExportedProperty.class));
- }
+ if (properties == null) {
+ properties = convertToPropertyInfos(klass.getDeclaredMethodsUnchecked(false),
+ klass.getDeclaredFieldsUnchecked(false), ExportedProperty.class);
+ map.put(klass, properties);
}
-
- methods = foundMethods.toArray(new Method[foundMethods.size()]);
- map.put(klass, methods);
-
- return methods;
+ return properties;
}
private static void dumpViewProperties(Context context, Object view,
@@ -1305,233 +1390,97 @@ public class ViewDebug {
Class<?> klass = view.getClass();
do {
- exportFields(context, view, out, klass, prefix);
- exportMethods(context, view, out, klass, prefix);
+ writeExportedProperties(context, view, out, klass, prefix);
klass = klass.getSuperclass();
} while (klass != Object.class);
}
- private static Object callMethodOnAppropriateTheadBlocking(final Method method,
- final Object object) throws IllegalAccessException, InvocationTargetException,
- TimeoutException {
- if (!(object instanceof View)) {
- return method.invoke(object, (Object[]) null);
- }
-
- final View view = (View) object;
- Callable<Object> callable = new Callable<Object>() {
- @Override
- public Object call() throws IllegalAccessException, InvocationTargetException {
- return method.invoke(view, (Object[]) null);
- }
- };
- FutureTask<Object> future = new FutureTask<Object>(callable);
- // Try to use the handler provided by the view
- Handler handler = view.getHandler();
- // Fall back on using the main thread
- if (handler == null) {
- handler = new Handler(android.os.Looper.getMainLooper());
- }
- handler.post(future);
- while (true) {
- try {
- return future.get(CAPTURE_TIMEOUT, java.util.concurrent.TimeUnit.MILLISECONDS);
- } catch (ExecutionException e) {
- Throwable t = e.getCause();
- if (t instanceof IllegalAccessException) {
- throw (IllegalAccessException)t;
- }
- if (t instanceof InvocationTargetException) {
- throw (InvocationTargetException)t;
- }
- throw new RuntimeException("Unexpected exception", t);
- } catch (InterruptedException e) {
- // Call get again
- } catch (CancellationException e) {
- throw new RuntimeException("Unexpected cancellation exception", e);
- }
- }
- }
-
private static String formatIntToHexString(int value) {
return "0x" + Integer.toHexString(value).toUpperCase();
}
- private static void exportMethods(Context context, Object view, BufferedWriter out,
+ private static void writeExportedProperties(Context context, Object view, BufferedWriter out,
Class<?> klass, String prefix) throws IOException {
-
- final Method[] methods = getExportedPropertyMethods(klass);
- int count = methods.length;
- for (int i = 0; i < count; i++) {
- final Method method = methods[i];
+ for (PropertyInfo<ExportedProperty, ?> info : getExportedProperties(klass)) {
//noinspection EmptyCatchBlock
+ Object value;
try {
- Object methodValue = callMethodOnAppropriateTheadBlocking(method, view);
- final Class<?> returnType = method.getReturnType();
- final ExportedProperty property = sAnnotations.get(method);
- String categoryPrefix =
- property.category().length() != 0 ? property.category() + ":" : "";
-
- if (returnType == int.class) {
- if (property.resolveId() && context != null) {
- final int id = (Integer) methodValue;
- methodValue = resolveId(context, id);
- } else {
- final FlagToString[] flagsMapping = property.flagMapping();
- if (flagsMapping.length > 0) {
- final int intValue = (Integer) methodValue;
- final String valuePrefix =
- categoryPrefix + prefix + method.getName() + '_';
- exportUnrolledFlags(out, flagsMapping, intValue, valuePrefix);
- }
-
- final IntToString[] mapping = property.mapping();
- if (mapping.length > 0) {
- final int intValue = (Integer) methodValue;
- boolean mapped = false;
- int mappingCount = mapping.length;
- for (int j = 0; j < mappingCount; j++) {
- final IntToString mapper = mapping[j];
- if (mapper.from() == intValue) {
- methodValue = mapper.to();
- mapped = true;
- break;
- }
- }
-
- if (!mapped) {
- methodValue = intValue;
- }
- }
- }
- } else if (returnType == int[].class) {
- final int[] array = (int[]) methodValue;
- final String valuePrefix = categoryPrefix + prefix + method.getName() + '_';
- final String suffix = "()";
+ value = info.invoke(view);
+ } catch (Exception e) {
+ // ignore
+ continue;
+ }
- exportUnrolledArray(context, out, property, array, valuePrefix, suffix);
+ String categoryPrefix =
+ info.property.category().length() != 0 ? info.property.category() + ":" : "";
- continue;
- } else if (returnType == String[].class) {
- final String[] array = (String[]) methodValue;
- if (property.hasAdjacentMapping() && array != null) {
- for (int j = 0; j < array.length; j += 2) {
- if (array[j] != null) {
- writeEntry(out, categoryPrefix + prefix, array[j], "()",
- array[j + 1] == null ? "null" : array[j + 1]);
- }
+ if (info.returnType == int.class || info.returnType == byte.class) {
+ if (info.property.resolveId() && context != null) {
+ final int id = (Integer) value;
+ value = resolveId(context, id);
- }
+ } else if (info.property.formatToHexString()) {
+ if (info.returnType == int.class) {
+ value = formatIntToHexString((Integer) value);
+ } else if (info.returnType == byte.class) {
+ value = "0x"
+ + HexEncoding.encodeToString((Byte) value, true);
}
-
- continue;
- } else if (!returnType.isPrimitive()) {
- if (property.deepExport()) {
- dumpViewProperties(context, methodValue, out, prefix + property.prefix());
- continue;
+ } else {
+ final ViewDebug.FlagToString[] flagsMapping = info.property.flagMapping();
+ if (flagsMapping.length > 0) {
+ final int intValue = (Integer) value;
+ final String valuePrefix =
+ categoryPrefix + prefix + info.name + '_';
+ exportUnrolledFlags(out, flagsMapping, intValue, valuePrefix);
}
- }
-
- writeEntry(out, categoryPrefix + prefix, method.getName(), "()", methodValue);
- } catch (IllegalAccessException e) {
- } catch (InvocationTargetException e) {
- } catch (TimeoutException e) {
- }
- }
- }
-
- private static void exportFields(Context context, Object view, BufferedWriter out,
- Class<?> klass, String prefix) throws IOException {
-
- final Field[] fields = getExportedPropertyFields(klass);
- int count = fields.length;
- for (int i = 0; i < count; i++) {
- final Field field = fields[i];
-
- //noinspection EmptyCatchBlock
- try {
- Object fieldValue = null;
- final Class<?> type = field.getType();
- final ExportedProperty property = sAnnotations.get(field);
- String categoryPrefix =
- property.category().length() != 0 ? property.category() + ":" : "";
-
- if (type == int.class || type == byte.class) {
- if (property.resolveId() && context != null) {
- final int id = field.getInt(view);
- fieldValue = resolveId(context, id);
- } else {
- final FlagToString[] flagsMapping = property.flagMapping();
- if (flagsMapping.length > 0) {
- final int intValue = field.getInt(view);
- final String valuePrefix =
- categoryPrefix + prefix + field.getName() + '_';
- exportUnrolledFlags(out, flagsMapping, intValue, valuePrefix);
- }
-
- final IntToString[] mapping = property.mapping();
- if (mapping.length > 0) {
- final int intValue = field.getInt(view);
- int mappingCount = mapping.length;
- for (int j = 0; j < mappingCount; j++) {
- final IntToString mapped = mapping[j];
- if (mapped.from() == intValue) {
- fieldValue = mapped.to();
- break;
- }
- }
-
- if (fieldValue == null) {
- fieldValue = intValue;
+ final ViewDebug.IntToString[] mapping = info.property.mapping();
+ if (mapping.length > 0) {
+ final int intValue = (Integer) value;
+ boolean mapped = false;
+ int mappingCount = mapping.length;
+ for (int j = 0; j < mappingCount; j++) {
+ final ViewDebug.IntToString mapper = mapping[j];
+ if (mapper.from() == intValue) {
+ value = mapper.to();
+ mapped = true;
+ break;
}
}
- if (property.formatToHexString()) {
- fieldValue = field.get(view);
- if (type == int.class) {
- fieldValue = formatIntToHexString((Integer) fieldValue);
- } else if (type == byte.class) {
- fieldValue = "0x"
- + HexEncoding.encodeToString((Byte) fieldValue, true);
- }
+ if (!mapped) {
+ value = intValue;
}
}
- } else if (type == int[].class) {
- final int[] array = (int[]) field.get(view);
- final String valuePrefix = categoryPrefix + prefix + field.getName() + '_';
- final String suffix = "";
-
- exportUnrolledArray(context, out, property, array, valuePrefix, suffix);
+ }
+ } else if (info.returnType == int[].class) {
+ final int[] array = (int[]) value;
+ final String valuePrefix = categoryPrefix + prefix + info.name + '_';
+ exportUnrolledArray(context, out, info.property, array, valuePrefix,
+ info.entrySuffix);
- continue;
- } else if (type == String[].class) {
- final String[] array = (String[]) field.get(view);
- if (property.hasAdjacentMapping() && array != null) {
- for (int j = 0; j < array.length; j += 2) {
- if (array[j] != null) {
- writeEntry(out, categoryPrefix + prefix, array[j], "",
- array[j + 1] == null ? "null" : array[j + 1]);
- }
+ continue;
+ } else if (info.returnType == String[].class) {
+ final String[] array = (String[]) value;
+ if (info.property.hasAdjacentMapping() && array != null) {
+ for (int j = 0; j < array.length; j += 2) {
+ if (array[j] != null) {
+ writeEntry(out, categoryPrefix + prefix, array[j],
+ info.entrySuffix, array[j + 1] == null ? "null" : array[j + 1]);
}
}
-
- continue;
- } else if (!type.isPrimitive()) {
- if (property.deepExport()) {
- dumpViewProperties(context, field.get(view), out, prefix +
- property.prefix());
- continue;
- }
}
- if (fieldValue == null) {
- fieldValue = field.get(view);
+ continue;
+ } else if (!info.returnType.isPrimitive()) {
+ if (info.property.deepExport()) {
+ dumpViewProperties(context, value, out, prefix + info.property.prefix());
+ continue;
}
-
- writeEntry(out, categoryPrefix + prefix, field.getName(), "", fieldValue);
- } catch (IllegalAccessException e) {
}
+
+ writeEntry(out, categoryPrefix + prefix, info.name, info.entrySuffix, value);
}
}
@@ -1721,91 +1670,40 @@ public class ViewDebug {
}
}
- private static Field[] capturedViewGetPropertyFields(Class<?> klass) {
- if (mCapturedViewFieldsForClasses == null) {
- mCapturedViewFieldsForClasses = new HashMap<Class<?>, Field[]>();
- }
- final HashMap<Class<?>, Field[]> map = mCapturedViewFieldsForClasses;
-
- Field[] fields = map.get(klass);
- if (fields != null) {
- return fields;
- }
-
- final ArrayList<Field> foundFields = new ArrayList<Field>();
- fields = klass.getFields();
-
- int count = fields.length;
- for (int i = 0; i < count; i++) {
- final Field field = fields[i];
- if (field.isAnnotationPresent(CapturedViewProperty.class)) {
- field.setAccessible(true);
- foundFields.add(field);
- }
- }
-
- fields = foundFields.toArray(new Field[foundFields.size()]);
- map.put(klass, fields);
-
- return fields;
- }
-
- private static Method[] capturedViewGetPropertyMethods(Class<?> klass) {
- if (mCapturedViewMethodsForClasses == null) {
- mCapturedViewMethodsForClasses = new HashMap<Class<?>, Method[]>();
- }
- final HashMap<Class<?>, Method[]> map = mCapturedViewMethodsForClasses;
-
- Method[] methods = map.get(klass);
- if (methods != null) {
- return methods;
+ private static PropertyInfo<CapturedViewProperty, ?>[] getCapturedViewProperties(
+ Class<?> klass) {
+ if (sCapturedViewProperties == null) {
+ sCapturedViewProperties = new HashMap<>();
}
+ final HashMap<Class<?>, PropertyInfo<CapturedViewProperty, ?>[]> map =
+ sCapturedViewProperties;
- final ArrayList<Method> foundMethods = new ArrayList<Method>();
- methods = klass.getMethods();
-
- int count = methods.length;
- for (int i = 0; i < count; i++) {
- final Method method = methods[i];
- if (method.getParameterTypes().length == 0 &&
- method.isAnnotationPresent(CapturedViewProperty.class) &&
- method.getReturnType() != Void.class) {
- method.setAccessible(true);
- foundMethods.add(method);
- }
+ PropertyInfo<CapturedViewProperty, ?>[] infos = map.get(klass);
+ if (infos == null) {
+ infos = convertToPropertyInfos(klass.getMethods(), klass.getFields(),
+ CapturedViewProperty.class);
+ map.put(klass, infos);
}
-
- methods = foundMethods.toArray(new Method[foundMethods.size()]);
- map.put(klass, methods);
-
- return methods;
+ return infos;
}
- private static String capturedViewExportMethods(Object obj, Class<?> klass,
- String prefix) {
-
+ private static String exportCapturedViewProperties(Object obj, Class<?> klass, String prefix) {
if (obj == null) {
return "null";
}
StringBuilder sb = new StringBuilder();
- final Method[] methods = capturedViewGetPropertyMethods(klass);
- int count = methods.length;
- for (int i = 0; i < count; i++) {
- final Method method = methods[i];
+ for (PropertyInfo<CapturedViewProperty, ?> pi : getCapturedViewProperties(klass)) {
try {
- Object methodValue = method.invoke(obj, (Object[]) null);
- final Class<?> returnType = method.getReturnType();
+ Object methodValue = pi.invoke(obj);
- CapturedViewProperty property = method.getAnnotation(CapturedViewProperty.class);
- if (property.retrieveReturn()) {
+ if (pi.property.retrieveReturn()) {
//we are interested in the second level data only
- sb.append(capturedViewExportMethods(methodValue, returnType, method.getName() + "#"));
+ sb.append(exportCapturedViewProperties(methodValue, pi.returnType,
+ pi.name + "#"));
} else {
- sb.append(prefix);
- sb.append(method.getName());
- sb.append("()=");
+ sb.append(prefix).append(pi.name).append(pi.entrySuffix).append("=");
if (methodValue != null) {
final String value = methodValue.toString().replace("\n", "\\n");
@@ -1813,47 +1711,10 @@ public class ViewDebug {
} else {
sb.append("null");
}
- sb.append("; ");
- }
- } catch (IllegalAccessException e) {
- //Exception IllegalAccess, it is OK here
- //we simply ignore this method
- } catch (InvocationTargetException e) {
- //Exception InvocationTarget, it is OK here
- //we simply ignore this method
- }
- }
- return sb.toString();
- }
-
- private static String capturedViewExportFields(Object obj, Class<?> klass, String prefix) {
- if (obj == null) {
- return "null";
- }
-
- StringBuilder sb = new StringBuilder();
- final Field[] fields = capturedViewGetPropertyFields(klass);
-
- int count = fields.length;
- for (int i = 0; i < count; i++) {
- final Field field = fields[i];
- try {
- Object fieldValue = field.get(obj);
-
- sb.append(prefix);
- sb.append(field.getName());
- sb.append("=");
-
- if (fieldValue != null) {
- final String value = fieldValue.toString().replace("\n", "\\n");
- sb.append(value);
- } else {
- sb.append("null");
+ sb.append(pi.valueSuffix).append(" ");
}
- sb.append(' ');
- } catch (IllegalAccessException e) {
- //Exception IllegalAccess, it is OK here
- //we simply ignore this field
+ } catch (Exception e) {
+ //It is OK here, we simply ignore this property
}
}
return sb.toString();
@@ -1869,8 +1730,7 @@ public class ViewDebug {
public static void dumpCapturedView(String tag, Object view) {
Class<?> klass = view.getClass();
StringBuilder sb = new StringBuilder(klass.getName() + ": ");
- sb.append(capturedViewExportFields(view, klass, ""));
- sb.append(capturedViewExportMethods(view, klass, ""));
+ sb.append(exportCapturedViewProperties(view, klass, ""));
Log.d(tag, sb.toString());
}