Loading core/java/android/view/ViewDebug.java +164 −1 Original line number Diff line number Diff line Loading @@ -89,6 +89,15 @@ public class ViewDebug { */ public static final boolean TRACE_RECYCLER = false; /** * Enables or disables motion events tracing. Any invoker of * {@link #trace(View, MotionEvent, MotionEventTraceType)} should first check * that this value is set to true as not to affect performance. * * @hide */ public static final boolean TRACE_MOTION_EVENTS = false; /** * The system property of dynamic switch for capturing view information * when it is set, we dump interested fields and methods for the view on focus Loading Loading @@ -367,7 +376,6 @@ public class ViewDebug { BIND_VIEW, RECYCLE_FROM_ACTIVE_HEAP, RECYCLE_FROM_SCRAP_HEAP, MOVE_TO_ACTIVE_HEAP, MOVE_TO_SCRAP_HEAP, MOVE_FROM_ACTIVE_TO_SCRAP_HEAP } Loading @@ -384,6 +392,21 @@ public class ViewDebug { private static List<RecyclerTrace> sRecyclerTraces; private static String sRecyclerTracePrefix; /** * Defines the type of motion events trace to output to the motion events traces file. * * @hide */ public enum MotionEventTraceType { DISPATCH, ON_INTERCEPT, ON_TOUCH } private static BufferedWriter sMotionEventTraces; private static ViewRoot sMotionEventRoot; private static String sMotionEventTracePrefix; /** * Returns the number of instanciated Views. * Loading Loading @@ -675,6 +698,146 @@ public class ViewDebug { sHierarhcyRoot = null; } /** * Outputs a trace to the currently opened traces file. The trace contains the class name * and instance's hashcode of the specified view as well as the supplied trace type. * * @param view the view to trace * @param event the event of the trace * @param type the type of the trace * * @hide */ public static void trace(View view, MotionEvent event, MotionEventTraceType type) { if (sMotionEventTraces == null) { return; } try { sMotionEventTraces.write(type.name()); sMotionEventTraces.write(' '); sMotionEventTraces.write(event.getAction()); sMotionEventTraces.write(' '); sMotionEventTraces.write(view.getClass().getName()); sMotionEventTraces.write('@'); sMotionEventTraces.write(Integer.toHexString(view.hashCode())); sHierarchyTraces.newLine(); } catch (IOException e) { Log.w("View", "Error while dumping trace of event " + event + " for view " + view); } } /** * Starts tracing the motion events for the hierarchy of the specificy view. * The trace is identified by a prefix, used to build the traces files names: * <code>/EXTERNAL/motion-events/PREFIX.traces</code> and * <code>/EXTERNAL/motion-events/PREFIX.tree</code>. * * Only one view hierarchy can be traced at the same time. After calling this method, any * other invocation will result in a <code>IllegalStateException</code> unless * {@link #stopMotionEventTracing()} is invoked before. * * Calling this method creates the file <code>/EXTERNAL/motion-events/PREFIX.traces</code> * containing all the traces (or method calls) relative to the specified view's hierarchy. * * This method will return immediately if TRACE_HIERARCHY is false. * * @param prefix the traces files name prefix * @param view the view whose hierarchy must be traced * * @see #stopMotionEventTracing() * @see #trace(View, MotionEvent, android.view.ViewDebug.MotionEventTraceType) * * @hide */ public static void startMotionEventTracing(String prefix, View view) { //noinspection PointlessBooleanExpression,ConstantConditions if (!TRACE_MOTION_EVENTS) { return; } if (sMotionEventRoot != null) { throw new IllegalStateException("You must call stopMotionEventTracing() before running" + " a new trace!"); } File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "motion-events/"); //noinspection ResultOfMethodCallIgnored hierarchyDump.mkdirs(); hierarchyDump = new File(hierarchyDump, prefix + ".traces"); sMotionEventTracePrefix = prefix; try { sMotionEventTraces = new BufferedWriter(new FileWriter(hierarchyDump), 32 * 1024); } catch (IOException e) { Log.e("View", "Could not dump view hierarchy"); return; } sMotionEventRoot = (ViewRoot) view.getRootView().getParent(); } /** * Stops the current motion events tracing. This method closes the file * <code>/EXTERNAL/motion-events/PREFIX.traces</code>. * * Calling this method creates the file <code>/EXTERNAL/motion-events/PREFIX.tree</code> * containing the view hierarchy of the view supplied to * {@link #startMotionEventTracing(String, View)}. * * This method will return immediately if TRACE_HIERARCHY is false. * * @see #startMotionEventTracing(String, View) * @see #trace(View, MotionEvent, android.view.ViewDebug.MotionEventTraceType) * * @hide */ public static void stopMotionEventTracing() { //noinspection PointlessBooleanExpression,ConstantConditions if (!TRACE_MOTION_EVENTS) { return; } if (sMotionEventRoot == null || sMotionEventTraces == null) { throw new IllegalStateException("You must call startMotionEventTracing() before" + " stopMotionEventTracing()!"); } try { sMotionEventTraces.close(); } catch (IOException e) { Log.e("View", "Could not write view traces"); } sMotionEventTraces = null; File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "motion-events/"); //noinspection ResultOfMethodCallIgnored hierarchyDump.mkdirs(); hierarchyDump = new File(hierarchyDump, sMotionEventTracePrefix + ".tree"); BufferedWriter out; try { out = new BufferedWriter(new FileWriter(hierarchyDump), 8 * 1024); } catch (IOException e) { Log.e("View", "Could not dump view hierarchy"); return; } View view = sMotionEventRoot.getView(); if (view instanceof ViewGroup) { ViewGroup group = (ViewGroup) view; dumpViewHierarchy(group, out, 0); try { out.close(); } catch (IOException e) { Log.e("View", "Could not dump view hierarchy"); } } sHierarhcyRoot = null; } static void dispatchCommand(View view, String command, String parameters, OutputStream clientStream) throws IOException { Loading core/java/android/widget/LinearLayout.java +1 −1 Original line number Diff line number Diff line Loading @@ -754,7 +754,7 @@ public class LinearLayout extends ViewGroup { maxHeight = Math.max(maxHeight, ascent + descent); } if (useLargestChild) { if (useLargestChild && widthMode == MeasureSpec.AT_MOST) { mTotalLength = 0; for (int i = 0; i < count; ++i) { Loading Loading
core/java/android/view/ViewDebug.java +164 −1 Original line number Diff line number Diff line Loading @@ -89,6 +89,15 @@ public class ViewDebug { */ public static final boolean TRACE_RECYCLER = false; /** * Enables or disables motion events tracing. Any invoker of * {@link #trace(View, MotionEvent, MotionEventTraceType)} should first check * that this value is set to true as not to affect performance. * * @hide */ public static final boolean TRACE_MOTION_EVENTS = false; /** * The system property of dynamic switch for capturing view information * when it is set, we dump interested fields and methods for the view on focus Loading Loading @@ -367,7 +376,6 @@ public class ViewDebug { BIND_VIEW, RECYCLE_FROM_ACTIVE_HEAP, RECYCLE_FROM_SCRAP_HEAP, MOVE_TO_ACTIVE_HEAP, MOVE_TO_SCRAP_HEAP, MOVE_FROM_ACTIVE_TO_SCRAP_HEAP } Loading @@ -384,6 +392,21 @@ public class ViewDebug { private static List<RecyclerTrace> sRecyclerTraces; private static String sRecyclerTracePrefix; /** * Defines the type of motion events trace to output to the motion events traces file. * * @hide */ public enum MotionEventTraceType { DISPATCH, ON_INTERCEPT, ON_TOUCH } private static BufferedWriter sMotionEventTraces; private static ViewRoot sMotionEventRoot; private static String sMotionEventTracePrefix; /** * Returns the number of instanciated Views. * Loading Loading @@ -675,6 +698,146 @@ public class ViewDebug { sHierarhcyRoot = null; } /** * Outputs a trace to the currently opened traces file. The trace contains the class name * and instance's hashcode of the specified view as well as the supplied trace type. * * @param view the view to trace * @param event the event of the trace * @param type the type of the trace * * @hide */ public static void trace(View view, MotionEvent event, MotionEventTraceType type) { if (sMotionEventTraces == null) { return; } try { sMotionEventTraces.write(type.name()); sMotionEventTraces.write(' '); sMotionEventTraces.write(event.getAction()); sMotionEventTraces.write(' '); sMotionEventTraces.write(view.getClass().getName()); sMotionEventTraces.write('@'); sMotionEventTraces.write(Integer.toHexString(view.hashCode())); sHierarchyTraces.newLine(); } catch (IOException e) { Log.w("View", "Error while dumping trace of event " + event + " for view " + view); } } /** * Starts tracing the motion events for the hierarchy of the specificy view. * The trace is identified by a prefix, used to build the traces files names: * <code>/EXTERNAL/motion-events/PREFIX.traces</code> and * <code>/EXTERNAL/motion-events/PREFIX.tree</code>. * * Only one view hierarchy can be traced at the same time. After calling this method, any * other invocation will result in a <code>IllegalStateException</code> unless * {@link #stopMotionEventTracing()} is invoked before. * * Calling this method creates the file <code>/EXTERNAL/motion-events/PREFIX.traces</code> * containing all the traces (or method calls) relative to the specified view's hierarchy. * * This method will return immediately if TRACE_HIERARCHY is false. * * @param prefix the traces files name prefix * @param view the view whose hierarchy must be traced * * @see #stopMotionEventTracing() * @see #trace(View, MotionEvent, android.view.ViewDebug.MotionEventTraceType) * * @hide */ public static void startMotionEventTracing(String prefix, View view) { //noinspection PointlessBooleanExpression,ConstantConditions if (!TRACE_MOTION_EVENTS) { return; } if (sMotionEventRoot != null) { throw new IllegalStateException("You must call stopMotionEventTracing() before running" + " a new trace!"); } File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "motion-events/"); //noinspection ResultOfMethodCallIgnored hierarchyDump.mkdirs(); hierarchyDump = new File(hierarchyDump, prefix + ".traces"); sMotionEventTracePrefix = prefix; try { sMotionEventTraces = new BufferedWriter(new FileWriter(hierarchyDump), 32 * 1024); } catch (IOException e) { Log.e("View", "Could not dump view hierarchy"); return; } sMotionEventRoot = (ViewRoot) view.getRootView().getParent(); } /** * Stops the current motion events tracing. This method closes the file * <code>/EXTERNAL/motion-events/PREFIX.traces</code>. * * Calling this method creates the file <code>/EXTERNAL/motion-events/PREFIX.tree</code> * containing the view hierarchy of the view supplied to * {@link #startMotionEventTracing(String, View)}. * * This method will return immediately if TRACE_HIERARCHY is false. * * @see #startMotionEventTracing(String, View) * @see #trace(View, MotionEvent, android.view.ViewDebug.MotionEventTraceType) * * @hide */ public static void stopMotionEventTracing() { //noinspection PointlessBooleanExpression,ConstantConditions if (!TRACE_MOTION_EVENTS) { return; } if (sMotionEventRoot == null || sMotionEventTraces == null) { throw new IllegalStateException("You must call startMotionEventTracing() before" + " stopMotionEventTracing()!"); } try { sMotionEventTraces.close(); } catch (IOException e) { Log.e("View", "Could not write view traces"); } sMotionEventTraces = null; File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "motion-events/"); //noinspection ResultOfMethodCallIgnored hierarchyDump.mkdirs(); hierarchyDump = new File(hierarchyDump, sMotionEventTracePrefix + ".tree"); BufferedWriter out; try { out = new BufferedWriter(new FileWriter(hierarchyDump), 8 * 1024); } catch (IOException e) { Log.e("View", "Could not dump view hierarchy"); return; } View view = sMotionEventRoot.getView(); if (view instanceof ViewGroup) { ViewGroup group = (ViewGroup) view; dumpViewHierarchy(group, out, 0); try { out.close(); } catch (IOException e) { Log.e("View", "Could not dump view hierarchy"); } } sHierarhcyRoot = null; } static void dispatchCommand(View view, String command, String parameters, OutputStream clientStream) throws IOException { Loading
core/java/android/widget/LinearLayout.java +1 −1 Original line number Diff line number Diff line Loading @@ -754,7 +754,7 @@ public class LinearLayout extends ViewGroup { maxHeight = Math.max(maxHeight, ascent + descent); } if (useLargestChild) { if (useLargestChild && widthMode == MeasureSpec.AT_MOST) { mTotalLength = 0; for (int i = 0; i < count; ++i) { Loading