Merge "Annotate ListView with StrictMode.Span"
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 97f015b..1fa5af2 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -1276,11 +1276,14 @@
                     state.mActiveHead = mNext;
                 }
 
+                state.mActiveSize--;
+
+                if (LOG_V) Log.d(TAG, "Span finished=" + mName + "; size=" + state.mActiveSize);
+
                 this.mCreateMillis = -1;
                 this.mName = null;
                 this.mPrev = null;
                 this.mNext = null;
-                state.mActiveSize--;
 
                 // Add ourselves to the freeList, if it's not already
                 // too big.
@@ -1367,6 +1370,7 @@
             if (span.mNext != null) {
                 span.mNext.mPrev = span;
             }
+            if (LOG_V) Log.d(TAG, "Span enter=" + name + "; size=" + state.mActiveSize);
         }
         return span;
     }
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 30b1e5d..466e541 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -29,6 +29,7 @@
 import android.os.Handler;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.StrictMode;
 import android.text.Editable;
 import android.text.TextUtils;
 import android.text.TextWatcher;
@@ -460,6 +461,15 @@
     private boolean mFlingProfilingStarted = false;
 
     /**
+     * The StrictMode "critical time span" objects to catch animation
+     * stutters.  Non-null when a time-sensitive animation is
+     * in-flight.  Must call finish() on them when done animating.
+     * These are no-ops on user builds.
+     */
+    private StrictMode.Span mScrollStrictSpan = null;
+    private StrictMode.Span mFlingStrictSpan = null;
+
+    /**
      * The last CheckForLongPress runnable we posted, if any
      */
     private CheckForLongPress mPendingCheckForLongPress;
@@ -2089,6 +2099,16 @@
             mAdapter.unregisterDataSetObserver(mDataSetObserver);
             mDataSetObserver = null;
         }
+
+        if (mScrollStrictSpan != null) {
+            mScrollStrictSpan.finish();
+            mScrollStrictSpan = null;
+        }
+
+        if (mFlingStrictSpan != null) {
+            mFlingStrictSpan.finish();
+            mFlingStrictSpan = null;
+        }
     }
 
     @Override
@@ -2559,6 +2579,11 @@
                     }
                 }
 
+                if (mScrollStrictSpan == null) {
+                    // If it's non-null, we're already in a scroll.
+                    mScrollStrictSpan = StrictMode.enterCriticalSpan("AbsListView-scroll");
+                }
+
                 if (y != mLastY) {
                     // We may be here after stopping a fling and continuing to scroll.
                     // If so, we haven't disallowed intercepting touch events yet.
@@ -2722,6 +2747,11 @@
                     mScrollProfilingStarted = false;
                 }
             }
+
+            if (mScrollStrictSpan != null) {
+                mScrollStrictSpan.finish();
+                mScrollStrictSpan = null;
+            }
             break;
         }
 
@@ -2934,6 +2964,10 @@
                     mFlingProfilingStarted = true;
                 }
             }
+
+            if (mFlingStrictSpan == null) {
+                mFlingStrictSpan = StrictMode.enterCriticalSpan("AbsListView-fling");
+            }
         }
 
         void startScroll(int distance, int duration) {
@@ -3012,6 +3046,11 @@
                             mFlingProfilingStarted = false;
                         }
                     }
+
+                    if (mFlingStrictSpan != null) {
+                        mFlingStrictSpan.finish();
+                        mFlingStrictSpan = null;
+                    }
                 }
                 break;
             }