summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/os/Debug.java54
-rw-r--r--core/java/android/view/View.java57
-rw-r--r--core/java/android/view/ViewDebug.java64
-rw-r--r--core/java/android/view/ViewGroup.java60
-rw-r--r--core/java/android/view/ViewRoot.java52
-rw-r--r--core/java/android/widget/AbsListView.java59
-rw-r--r--services/java/com/android/server/status/IconMerger.java8
7 files changed, 317 insertions, 37 deletions
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 9cf7a222c186..cd52bf3de7ea 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -30,6 +30,10 @@ import java.io.PrintWriter;
import java.io.Reader;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import org.apache.harmony.dalvik.ddmc.Chunk;
import org.apache.harmony.dalvik.ddmc.ChunkHandler;
@@ -857,6 +861,15 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
/**
+ * Equivalent to <code>setFieldsOn(cl, false)</code>.
+ *
+ * @see #setFieldsOn(Class, boolean)
+ */
+ public static void setFieldsOn(Class<?> cl) {
+ setFieldsOn(cl, false);
+ }
+
+ /**
* Reflectively sets static fields of a class based on internal debugging
* properties. This method is a no-op if android.util.Config.DEBUG is
* false.
@@ -868,7 +881,7 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
* Class setup: define a class whose only fields are non-final, static
* primitive types (except for "char") or Strings. In a static block
* after the field definitions/initializations, pass the class to
- * this method, Debug.setFieldsOn(). Example:
+ * this method, Debug.setFieldsOn(). Example:
* <pre>
* package com.example;
*
@@ -880,12 +893,18 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
* public static String ns = null;
* public static boolean b = false;
* public static int i = 5;
+ * @Debug.DebugProperty
* public static float f = 0.1f;
+ * @@Debug.DebugProperty
* public static double d = 0.5d;
*
* // This MUST appear AFTER all fields are defined and initialized!
* static {
+ * // Sets all the fields
* Debug.setFieldsOn(MyDebugVars.class);
+ *
+ * // Sets only the fields annotated with @Debug.DebugProperty
+ * // Debug.setFieldsOn(MyDebugVars.class, true);
* }
* }
* </pre>
@@ -898,25 +917,31 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
* {@hide}
*
* @param cl The class to (possibly) modify
+ * @param partial If false, sets all static fields, otherwise, only set
+ * fields with the {@link android.os.Debug.DebugProperty}
+ * annotation
* @throws IllegalArgumentException if any fields are final or non-static,
* or if the type of the field does not match the type of
* the internal debugging property value.
*/
- public static void setFieldsOn(Class<?> cl) {
+ public static void setFieldsOn(Class<?> cl, boolean partial) {
if (Config.DEBUG) {
if (debugProperties != null) {
/* Only look for fields declared directly by the class,
* so we don't mysteriously change static fields in superclasses.
*/
for (Field field : cl.getDeclaredFields()) {
- final String propertyName = cl.getName() + "." + field.getName();
- boolean isStatic = Modifier.isStatic(field.getModifiers());
- boolean isFinal = Modifier.isFinal(field.getModifiers());
- if (!isStatic || isFinal) {
- throw new IllegalArgumentException(propertyName +
- " must be static and non-final");
+ if (!partial || field.getAnnotation(DebugProperty.class) != null) {
+ final String propertyName = cl.getName() + "." + field.getName();
+ boolean isStatic = Modifier.isStatic(field.getModifiers());
+ boolean isFinal = Modifier.isFinal(field.getModifiers());
+
+ if (!isStatic || isFinal) {
+ throw new IllegalArgumentException(propertyName +
+ " must be static and non-final");
+ }
+ modifyFieldIfSet(field, debugProperties, propertyName);
}
- modifyFieldIfSet(field, debugProperties, propertyName);
}
}
} else {
@@ -925,4 +950,15 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
") called in non-DEBUG build");
}
}
+
+ /**
+ * Annotation to put on fields you want to set with
+ * {@link Debug#setFieldsOn(Class, boolean)}.
+ *
+ * @hide
+ */
+ @Target({ ElementType.FIELD })
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface DebugProperty {
+ }
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 335b43c7c6e4..af5dca6ee817 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -49,6 +49,7 @@ import android.util.Poolable;
import android.util.Pool;
import android.util.Pools;
import android.util.PoolableManager;
+import android.util.Config;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.animation.Animation;
import android.view.inputmethod.InputConnection;
@@ -5641,7 +5642,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
if (ViewDebug.TRACE_HIERARCHY) {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.BUILD_CACHE);
}
- if (ViewRoot.PROFILE_DRAWING) {
+ if (Config.DEBUG && ViewDebug.profileDrawing) {
EventLog.writeEvent(60002, hashCode());
}
@@ -7166,6 +7167,60 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
}
/**
+ * @param consistency The type of consistency. See ViewDebug for more information.
+ *
+ * @hide
+ */
+ protected boolean dispatchConsistencyCheck(int consistency) {
+ return onConsistencyCheck(consistency);
+ }
+
+ /**
+ * Method that subclasses should implement to check their consistency. The type of
+ * consistency check is indicated by the bit field passed as a parameter.
+ *
+ * @param consistency The type of consistency. See ViewDebug for more information.
+ *
+ * @throws IllegalStateException if the view is in an inconsistent state.
+ *
+ * @hide
+ */
+ protected boolean onConsistencyCheck(int consistency) {
+ boolean result = true;
+
+ final boolean checkLayout = (consistency & ViewDebug.CONSISTENCY_LAYOUT) != 0;
+ final boolean checkDrawing = (consistency & ViewDebug.CONSISTENCY_DRAWING) != 0;
+
+ if (checkLayout) {
+ if (getParent() == null) {
+ result = false;
+ android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
+ "View " + this + " does not have a parent.");
+ }
+
+ if (mAttachInfo == null) {
+ result = false;
+ android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
+ "View " + this + " is not attached to a window.");
+ }
+ }
+
+ if (checkDrawing) {
+ // Do not check the DIRTY/DRAWN flags because views can call invalidate()
+ // from their draw() method
+
+ if ((mPrivateFlags & DRAWN) != DRAWN &&
+ (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) {
+ result = false;
+ android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
+ "View " + this + " was invalidated but its drawing cache is valid.");
+ }
+ }
+
+ return result;
+ }
+
+ /**
* Prints information about this view in the log output, with the tag
* {@link #VIEW_LOG_TAG}.
*
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 367c9a22d953..4436f4b6e62c 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -54,6 +54,27 @@ import java.lang.reflect.AccessibleObject;
*/
public class ViewDebug {
/**
+ * Log tag used to log errors related to the consistency of the view hierarchy.
+ *
+ * @hide
+ */
+ public static final String CONSISTENCY_LOG_TAG = "ViewConsistency";
+
+ /**
+ * Flag indicating the consistency check should check layout-related properties.
+ *
+ * @hide
+ */
+ public static final int CONSISTENCY_LAYOUT = 0x1;
+
+ /**
+ * Flag indicating the consistency check should check drawing-related properties.
+ *
+ * @hide
+ */
+ public static final int CONSISTENCY_DRAWING = 0x2;
+
+ /**
* Enables or disables view hierarchy tracing. Any invoker of
* {@link #trace(View, android.view.ViewDebug.HierarchyTraceType)} should first
* check that this value is set to true as not to affect performance.
@@ -80,6 +101,49 @@ public class ViewDebug {
static final String SYSTEM_PROPERTY_CAPTURE_EVENT = "debug.captureevent";
/**
+ * Profiles drawing times in the events log.
+ *
+ * @hide
+ */
+ @Debug.DebugProperty
+ public static boolean profileDrawing = false;
+
+ /**
+ * Profiles layout times in the events log.
+ *
+ * @hide
+ */
+ @Debug.DebugProperty
+ public static boolean profileLayout = false;
+
+ /**
+ * Profiles real fps (times between draws) and displays the result.
+ *
+ * @hide
+ */
+ @Debug.DebugProperty
+ public static boolean showFps = false;
+
+ /**
+ * <p>Enables or disables views consistency check. Even when this property is enabled,
+ * view consistency checks happen only if {@link android.util.Config#DEBUG} is set
+ * to true. The value of this property can be configured externally in one of the
+ * following files:</p>
+ * <ul>
+ * <li>/system/debug.prop</li>
+ * <li>/debug.prop</li>
+ * <li>/data/debug.prop</li>
+ * </ul>
+ * @hide
+ */
+ @Debug.DebugProperty
+ public static boolean consistencyCheckEnabled = false;
+
+ static {
+ Debug.setFieldsOn(ViewDebug.class, true);
+ }
+
+ /**
* This annotation can be used to mark fields and methods to be dumped by
* the view server. Only non-void methods with no arguments can be annotated
* by this annotation.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 31159d722d75..26fe776ba350 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -32,6 +32,7 @@ import android.util.AttributeSet;
import android.util.EventLog;
import android.util.Log;
import android.util.SparseArray;
+import android.util.Config;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.LayoutAnimationController;
@@ -1404,7 +1405,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
// Clear the flag as early as possible to allow draw() implementations
// to call invalidate() successfully when doing animations
- child.mPrivateFlags |= DRAWN;
+ child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK) | DRAWN;
if (!concatMatrix && canvas.quickReject(cl, ct, cr, cb, Canvas.EdgeType.BW) &&
(child.mPrivateFlags & DRAW_ANIMATION) == 0) {
@@ -1494,7 +1495,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
cachePaint.setAlpha(255);
mGroupFlags &= ~FLAG_ALPHA_LOWER_THAN_ONE;
}
- if (ViewRoot.PROFILE_DRAWING) {
+ if (Config.DEBUG && ViewDebug.profileDrawing) {
EventLog.writeEvent(60003, hashCode());
}
canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
@@ -2750,6 +2751,61 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
/**
+ * @hide
+ */
+ @Override
+ protected boolean dispatchConsistencyCheck(int consistency) {
+ boolean result = super.dispatchConsistencyCheck(consistency);
+
+ final int count = mChildrenCount;
+ final View[] children = mChildren;
+ for (int i = 0; i < count; i++) {
+ if (!children[i].dispatchConsistencyCheck(consistency)) result = false;
+ }
+
+ return result;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ protected boolean onConsistencyCheck(int consistency) {
+ boolean result = super.onConsistencyCheck(consistency);
+
+ final boolean checkLayout = (consistency & ViewDebug.CONSISTENCY_LAYOUT) != 0;
+ final boolean checkDrawing = (consistency & ViewDebug.CONSISTENCY_DRAWING) != 0;
+
+ if (checkLayout) {
+ final int count = mChildrenCount;
+ final View[] children = mChildren;
+ for (int i = 0; i < count; i++) {
+ if (children[i].getParent() != this) {
+ result = false;
+ android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
+ "View " + children[i] + " has no parent/a parent that is not " + this);
+ }
+ }
+ }
+
+ if (checkDrawing) {
+ // If this group is dirty, check that the parent is dirty as well
+ if ((mPrivateFlags & DIRTY_MASK) != 0) {
+ final ViewParent parent = getParent();
+ if (parent != null && !(parent instanceof ViewRoot)) {
+ if ((((View) parent).mPrivateFlags & DIRTY_MASK) == 0) {
+ result = false;
+ android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
+ "ViewGroup " + this + " is dirty but its parent is not: " + this);
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
* {@inheritDoc}
*/
@Override
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 8494d5e0c2c4..90453ba5d542 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -75,13 +75,6 @@ public final class ViewRoot extends Handler implements ViewParent,
private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
private static final boolean WATCH_POINTER = false;
- static final boolean PROFILE_DRAWING = false;
- private static final boolean PROFILE_LAYOUT = false;
- // profiles real fps (times between draws) and displays the result
- private static final boolean SHOW_FPS = false;
- // used by SHOW_FPS
- private static int sDrawTime;
-
/**
* Maximum time we allow the user to roll the trackball enough to generate
* a key event, before resetting the counters.
@@ -97,6 +90,8 @@ public final class ViewRoot extends Handler implements ViewParent,
static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<RunQueue>();
+ private static int sDrawTime;
+
long mLastTrackballTime = 0;
final TrackballAxis mTrackballAxisX = new TrackballAxis();
final TrackballAxis mTrackballAxisY = new TrackballAxis();
@@ -796,7 +791,7 @@ public final class ViewRoot extends Handler implements ViewParent,
final Rect frame = mWinFrame;
boolean initialized = false;
boolean contentInsetsChanged = false;
- boolean visibleInsetsChanged = false;
+ boolean visibleInsetsChanged;
try {
boolean hadSurface = mSurface.isValid();
int fl = 0;
@@ -937,14 +932,22 @@ public final class ViewRoot extends Handler implements ViewParent,
if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(
"ViewRoot", "Laying out " + host + " to (" +
host.mMeasuredWidth + ", " + host.mMeasuredHeight + ")");
- long startTime;
- if (PROFILE_LAYOUT) {
+ long startTime = 0L;
+ if (Config.DEBUG && ViewDebug.profileLayout) {
startTime = SystemClock.elapsedRealtime();
}
host.layout(0, 0, host.mMeasuredWidth, host.mMeasuredHeight);
- if (PROFILE_LAYOUT) {
+ if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
+ if (!host.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_LAYOUT)) {
+ throw new IllegalStateException("The view hierarchy is an inconsistent state,"
+ + "please refer to the logs with the tag "
+ + ViewDebug.CONSISTENCY_LOG_TAG + " for more infomation.");
+ }
+ }
+
+ if (Config.DEBUG && ViewDebug.profileLayout) {
EventLog.writeEvent(60001, SystemClock.elapsedRealtime() - startTime);
}
@@ -960,10 +963,11 @@ public final class ViewRoot extends Handler implements ViewParent,
mTmpLocation[1] + host.mBottom - host.mTop);
host.gatherTransparentRegion(mTransparentRegion);
- if (mAppScale != 1.0f) {
- mTransparentRegion.scale(mAppScale);
- }
+ // TODO: scale the region, like:
+ // Region uses native methods. We probabl should have ScalableRegion class.
+
+ // Region does not have equals method ?
if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
mPreviousTransparentRegion.set(mTransparentRegion);
// reconfigure window manager
@@ -1168,6 +1172,9 @@ public final class ViewRoot extends Handler implements ViewParent,
canvas.scale(scale, scale);
}
mView.draw(canvas);
+ if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
+ mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
+ }
} finally {
canvas.restoreToCount(saveCount);
}
@@ -1175,7 +1182,7 @@ public final class ViewRoot extends Handler implements ViewParent,
mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
checkEglErrors();
- if (SHOW_FPS) {
+ if (Config.DEBUG && ViewDebug.showFps) {
int now = (int)SystemClock.elapsedRealtime();
if (sDrawTime != 0) {
nativeShowFPS(canvas, now - sDrawTime);
@@ -1216,7 +1223,7 @@ public final class ViewRoot extends Handler implements ViewParent,
try {
if (!dirty.isEmpty() || mIsAnimating) {
- long startTime;
+ long startTime = 0L;
if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Log.v("ViewRoot", "Surface " + surface + " drawing to bitmap w="
@@ -1224,7 +1231,7 @@ public final class ViewRoot extends Handler implements ViewParent,
//canvas.drawARGB(255, 255, 0, 0);
}
- if (PROFILE_DRAWING) {
+ if (Config.DEBUG && ViewDebug.profileDrawing) {
startTime = SystemClock.elapsedRealtime();
}
@@ -1259,11 +1266,15 @@ public final class ViewRoot extends Handler implements ViewParent,
canvas.scale(scale, scale);
}
mView.draw(canvas);
+
+ if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
+ mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
+ }
} finally {
canvas.restoreToCount(saveCount);
}
- if (SHOW_FPS) {
+ if (Config.DEBUG && ViewDebug.showFps) {
int now = (int)SystemClock.elapsedRealtime();
if (sDrawTime != 0) {
nativeShowFPS(canvas, now - sDrawTime);
@@ -1271,7 +1282,7 @@ public final class ViewRoot extends Handler implements ViewParent,
sDrawTime = now;
}
- if (PROFILE_DRAWING) {
+ if (Config.DEBUG && ViewDebug.profileDrawing) {
EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime);
}
}
@@ -1878,6 +1889,9 @@ public final class ViewRoot extends Handler implements ViewParent,
} else {
didFinish = false;
}
+ if (event != null) {
+ event.scale(mAppScaleInverted);
+ }
if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event);
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 4f503b488460..1ca59b2430c7 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -3190,7 +3190,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
// Reclaim views on screen
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
- AbsListView.LayoutParams lp = (AbsListView.LayoutParams)child.getLayoutParams();
+ AbsListView.LayoutParams lp = (AbsListView.LayoutParams) child.getLayoutParams();
// Don't reclaim header or footer views, or views that should be ignored
if (lp != null && mRecycler.shouldRecycleViewType(lp.viewType)) {
views.add(child);
@@ -3205,6 +3205,63 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
/**
+ * @hide
+ */
+ @Override
+ protected boolean onConsistencyCheck(int consistency) {
+ boolean result = super.onConsistencyCheck(consistency);
+
+ final boolean checkLayout = (consistency & ViewDebug.CONSISTENCY_LAYOUT) != 0;
+
+ if (checkLayout) {
+ // The active recycler must be empty
+ final View[] activeViews = mRecycler.mActiveViews;
+ int count = activeViews.length;
+ for (int i = 0; i < count; i++) {
+ if (activeViews[i] != null) {
+ result = false;
+ android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
+ "AbsListView " + this + " has a view in its active recycler: " +
+ activeViews[i]);
+ }
+ }
+
+ // All views in the recycler must NOT be on screen and must NOT have a parent
+ final ArrayList<View> scrap = mRecycler.mCurrentScrap;
+ if (!checkScrap(scrap)) result = false;
+ final ArrayList<View>[] scraps = mRecycler.mScrapViews;
+ count = scraps.length;
+ for (int i = 0; i < count; i++) {
+ if (!checkScrap(scraps[i])) result = false;
+ }
+ }
+
+ return result;
+ }
+
+ private boolean checkScrap(ArrayList<View> scrap) {
+ if (scrap == null) return true;
+ boolean result = true;
+
+ final int count = scrap.size();
+ for (int i = 0; i < count; i++) {
+ final View view = scrap.get(i);
+ if (view.getParent() != null) {
+ result = false;
+ android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG, "AbsListView " + this +
+ " has a view in its scrap heap still attached to a parent: " + view);
+ }
+ if (indexOfChild(view) >= 0) {
+ result = false;
+ android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG, "AbsListView " + this +
+ " has a view in its scrap heap that is also a direct child: " + view);
+ }
+ }
+
+ return result;
+ }
+
+ /**
* Sets the recycler listener to be notified whenever a View is set aside in
* the recycler for later reuse. This listener can be used to free resources
* associated to the View.
diff --git a/services/java/com/android/server/status/IconMerger.java b/services/java/com/android/server/status/IconMerger.java
index 37fdbfbbb329..5b806383d80b 100644
--- a/services/java/com/android/server/status/IconMerger.java
+++ b/services/java/com/android/server/status/IconMerger.java
@@ -8,8 +8,6 @@ import android.widget.LinearLayout;
public class IconMerger extends LinearLayout {
- private static final boolean SPEW = false;
-
StatusBarService service;
StatusBarIcon moreIcon;
@@ -29,7 +27,7 @@ public class IconMerger extends LinearLayout {
int fitRight = -1;
for (i=N-1; i>=0; i--) {
final View child = getChildAt(i);
- if (child != null && child.getVisibility() != GONE) {
+ if (child.getVisibility() != GONE) {
fitRight = child.getRight();
break;
}
@@ -45,7 +43,7 @@ public class IconMerger extends LinearLayout {
moreView = child;
startIndex = i+1;
}
- else if (child != null && child.getVisibility() != GONE) {
+ else if (child.getVisibility() != GONE) {
fitLeft = child.getLeft();
break;
}
@@ -71,7 +69,7 @@ public class IconMerger extends LinearLayout {
int number = 0;
for (i=startIndex; i<N; i++) {
final View child = getChildAt(i);
- if (child != null && child.getVisibility() != GONE) {
+ if (child.getVisibility() != GONE) {
int childLeft = child.getLeft();
int childRight = child.getRight();
if (childLeft < breakingPoint) {