diff options
| -rw-r--r-- | core/java/android/view/ViewDebug.java | 644 |
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()); } |