Make velocity tracker used in panel dependent on config.

The velocity tracker used in PanelView can now be configured with
a boolean value. The default is to use tha platform-standard velocity
tracker, but can be overriden to use our own velocity tracker for
noisy touch screens instead.

Change-Id: I375f4e2675ddbaa003acd6f085065bb3fe59ebf4
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 21eb41c..73b52ae 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -131,5 +131,9 @@
     <!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow
      card. -->
     <integer name="keyguard_max_notification_count">4</integer>
+
+    <!-- Defines the implementation of the velocity tracker to be used for the panel expansion. Can
+         be 'platform' or 'noisy' (i.e. for noisy touch screens). -->
+    <string name="velocity_tracker_impl" translatable="false">platform</string>
 </resources>
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NoisyVelocityTracker.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NoisyVelocityTracker.java
new file mode 100644
index 0000000..214dda2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NoisyVelocityTracker.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.util.Log;
+import android.util.Pools;
+import android.view.MotionEvent;
+
+import java.util.ArrayDeque;
+import java.util.Iterator;
+
+/**
+ * A very simple low-pass velocity filter for motion events for noisy touch screens.
+ */
+public class NoisyVelocityTracker implements VelocityTrackerInterface {
+
+    private static final Pools.SynchronizedPool<NoisyVelocityTracker> sNoisyPool =
+            new Pools.SynchronizedPool<>(2);
+
+    private static final float DECAY = 0.75f;
+    private static final boolean DEBUG = false;
+
+    private final int MAX_EVENTS = 8;
+    private ArrayDeque<MotionEventCopy> mEventBuf = new ArrayDeque<MotionEventCopy>(MAX_EVENTS);
+    private float mVX, mVY = 0;
+
+    private static class MotionEventCopy {
+        public MotionEventCopy(float x2, float y2, long eventTime) {
+            this.x = x2;
+            this.y = y2;
+            this.t = eventTime;
+        }
+        float x, y;
+        long t;
+    }
+
+    public static NoisyVelocityTracker obtain() {
+        NoisyVelocityTracker instance = sNoisyPool.acquire();
+        return (instance != null) ? instance : new NoisyVelocityTracker();
+    }
+
+    private NoisyVelocityTracker() {
+    }
+
+    public void addMovement(MotionEvent event) {
+        if (mEventBuf.size() == MAX_EVENTS) {
+            mEventBuf.remove();
+        }
+        mEventBuf.add(new MotionEventCopy(event.getX(), event.getY(), event.getEventTime()));
+    }
+
+    public void computeCurrentVelocity(int units) {
+        if (NoisyVelocityTracker.DEBUG) {
+            Log.v("FlingTracker", "computing velocities for " + mEventBuf.size() + " events");
+        }
+        mVX = mVY = 0;
+        MotionEventCopy last = null;
+        int i = 0;
+        float totalweight = 0f;
+        float weight = 10f;
+        for (final Iterator<MotionEventCopy> iter = mEventBuf.iterator();
+                iter.hasNext();) {
+            final MotionEventCopy event = iter.next();
+            if (last != null) {
+                final float dt = (float) (event.t - last.t) / units;
+                final float dx = (event.x - last.x);
+                final float dy = (event.y - last.y);
+                if (NoisyVelocityTracker.DEBUG) {
+                    Log.v("FlingTracker", String.format(
+                            "   [%d] (t=%d %.1f,%.1f) dx=%.1f dy=%.1f dt=%f vx=%.1f vy=%.1f",
+                            i, event.t, event.x, event.y,
+                            dx, dy, dt,
+                            (dx/dt),
+                            (dy/dt)
+                    ));
+                }
+                if (event.t == last.t) {
+                    // Really not sure what to do with events that happened at the same time,
+                    // so we'll skip subsequent events.
+                    continue;
+                }
+                mVX += weight * dx / dt;
+                mVY += weight * dy / dt;
+                totalweight += weight;
+                weight *= DECAY;
+            }
+            last = event;
+            i++;
+        }
+        if (totalweight > 0) {
+            mVX /= totalweight;
+            mVY /= totalweight;
+        } else {
+            // so as not to contaminate the velocities with NaN
+            mVX = mVY = 0;
+        }
+
+        if (NoisyVelocityTracker.DEBUG) {
+            Log.v("FlingTracker", "computed: vx=" + mVX + " vy=" + mVY);
+        }
+    }
+
+    public float getXVelocity() {
+        if (Float.isNaN(mVX) || Float.isInfinite(mVX)) {
+            mVX = 0;
+        }
+        return mVX;
+    }
+
+    public float getYVelocity() {
+        if (Float.isNaN(mVY) || Float.isInfinite(mVX)) {
+            mVY = 0;
+        }
+        return mVY;
+    }
+
+    public void recycle() {
+        mEventBuf.clear();
+        sNoisyPool.release(this);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 517f763..a89fc0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -80,123 +80,7 @@
 
     private TimeAnimator mTimeAnimator;
     private ObjectAnimator mPeekAnimator;
-    private FlingTracker mVelocityTracker;
-
-    /**
-     * A very simple low-pass velocity filter for motion events; not nearly as sophisticated as
-     * VelocityTracker but optimized for the kinds of gestures we expect to see in status bar
-     * panels.
-     */
-    private static class FlingTracker {
-        static final boolean DEBUG = false;
-        final int MAX_EVENTS = 8;
-        final float DECAY = 0.75f;
-        ArrayDeque<MotionEventCopy> mEventBuf = new ArrayDeque<MotionEventCopy>(MAX_EVENTS);
-        float mVX, mVY = 0;
-        private static class MotionEventCopy {
-            public MotionEventCopy(float x2, float y2, long eventTime) {
-                this.x = x2;
-                this.y = y2;
-                this.t = eventTime;
-            }
-            public float x, y;
-            public long t;
-        }
-        public FlingTracker() {
-        }
-        public void addMovement(MotionEvent event) {
-            if (mEventBuf.size() == MAX_EVENTS) {
-                mEventBuf.remove();
-            }
-            mEventBuf.add(new MotionEventCopy(event.getX(), event.getY(), event.getEventTime()));
-        }
-        public void computeCurrentVelocity(long timebase) {
-            if (FlingTracker.DEBUG) {
-                Log.v("FlingTracker", "computing velocities for " + mEventBuf.size() + " events");
-            }
-            mVX = mVY = 0;
-            MotionEventCopy last = null;
-            int i = 0;
-            float totalweight = 0f;
-            float weight = 10f;
-            for (final Iterator<MotionEventCopy> iter = mEventBuf.iterator();
-                    iter.hasNext();) {
-                final MotionEventCopy event = iter.next();
-                if (last != null) {
-                    final float dt = (float) (event.t - last.t) / timebase;
-                    final float dx = (event.x - last.x);
-                    final float dy = (event.y - last.y);
-                    if (FlingTracker.DEBUG) {
-                        Log.v("FlingTracker", String.format(
-                                "   [%d] (t=%d %.1f,%.1f) dx=%.1f dy=%.1f dt=%f vx=%.1f vy=%.1f",
-                                i, event.t, event.x, event.y,
-                                dx, dy, dt,
-                                (dx/dt),
-                                (dy/dt)
-                                ));
-                    }
-                    if (event.t == last.t) {
-                        // Really not sure what to do with events that happened at the same time,
-                        // so we'll skip subsequent events.
-                        if (DEBUG_NAN) {
-                            Log.v("FlingTracker", "skipping simultaneous event at t=" + event.t);
-                        }
-                        continue;
-                    }
-                    mVX += weight * dx / dt;
-                    mVY += weight * dy / dt;
-                    totalweight += weight;
-                    weight *= DECAY;
-                }
-                last = event;
-                i++;
-            }
-            if (totalweight > 0) {
-                mVX /= totalweight;
-                mVY /= totalweight;
-            } else {
-                if (DEBUG_NAN) {
-                    Log.v("FlingTracker", "computeCurrentVelocity warning: totalweight=0",
-                            new Throwable());
-                }
-                // so as not to contaminate the velocities with NaN
-                mVX = mVY = 0;
-            }
-
-            if (FlingTracker.DEBUG) {
-                Log.v("FlingTracker", "computed: vx=" + mVX + " vy=" + mVY);
-            }
-        }
-        public float getXVelocity() {
-            if (Float.isNaN(mVX) || Float.isInfinite(mVX)) {
-                if (DEBUG_NAN) {
-                    Log.v("FlingTracker", "warning: vx=" + mVX);
-                }
-                mVX = 0;
-            }
-            return mVX;
-        }
-        public float getYVelocity() {
-            if (Float.isNaN(mVY) || Float.isInfinite(mVX)) {
-                if (DEBUG_NAN) {
-                    Log.v("FlingTracker", "warning: vx=" + mVY);
-                }
-                mVY = 0;
-            }
-            return mVY;
-        }
-        public void recycle() {
-            mEventBuf.clear();
-        }
-
-        static FlingTracker sTracker;
-        static FlingTracker obtain() {
-            if (sTracker == null) {
-                sTracker = new FlingTracker();
-            }
-            return sTracker;
-        }
-    }
+    private VelocityTrackerInterface mVelocityTracker;
 
     PanelBar mBar;
 
@@ -385,7 +269,9 @@
 
                 mInitialTouchY = y;
                 mInitialTouchX = x;
-                initVelocityTracker();
+                if (mVelocityTracker == null) {
+                    initVelocityTracker();
+                }
                 trackMovement(event);
                 mTimeAnimator.cancel(); // end any outstanding animations
                 onTrackingStarted();
@@ -569,7 +455,7 @@
         if (mVelocityTracker != null) {
             mVelocityTracker.recycle();
         }
-        mVelocityTracker = FlingTracker.obtain();
+        mVelocityTracker = VelocityTrackerFactory.obtain(getContext());
     }
 
     protected boolean isScrolledToBottom() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PlatformVelocityTracker.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PlatformVelocityTracker.java
new file mode 100644
index 0000000..f589c3d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PlatformVelocityTracker.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.util.Pools;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+
+/**
+ * An implementation of {@link VelocityTrackerInterface} using the platform-standard
+ * {@link VelocityTracker}.
+ */
+public class PlatformVelocityTracker implements VelocityTrackerInterface {
+
+    private static final Pools.SynchronizedPool<PlatformVelocityTracker> sPool =
+            new Pools.SynchronizedPool<>(2);
+
+    private VelocityTracker mTracker;
+
+    public static PlatformVelocityTracker obtain() {
+        PlatformVelocityTracker tracker = sPool.acquire();
+        if (tracker == null) {
+            tracker = new PlatformVelocityTracker();
+        }
+        tracker.setTracker(VelocityTracker.obtain());
+        return tracker;
+    }
+
+    public void setTracker(VelocityTracker tracker) {
+        mTracker = tracker;
+    }
+
+    @Override
+    public void addMovement(MotionEvent event) {
+        mTracker.addMovement(event);
+    }
+
+    @Override
+    public void computeCurrentVelocity(int units) {
+        mTracker.computeCurrentVelocity(units);
+    }
+
+    @Override
+    public float getXVelocity() {
+        return mTracker.getXVelocity();
+    }
+
+    @Override
+    public float getYVelocity() {
+        return mTracker.getYVelocity();
+    }
+
+    @Override
+    public void recycle() {
+        mTracker.recycle();
+        sPool.release(this);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/VelocityTrackerFactory.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/VelocityTrackerFactory.java
new file mode 100644
index 0000000..4f43b4d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/VelocityTrackerFactory.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+
+import com.android.systemui.R;
+
+import static android.util.Pools.SynchronizedPool;
+
+/**
+ * A class to generate {@link VelocityTrackerInterface}, depending on the configuration.
+ */
+public class VelocityTrackerFactory {
+
+    public static final String PLATFORM_IMPL = "platform";
+    public static final String NOISY_IMPL = "noisy";
+
+    public static VelocityTrackerInterface obtain(Context ctx) {
+        String tracker = ctx.getResources().getString(R.string.velocity_tracker_impl);
+        switch (tracker) {
+            case NOISY_IMPL:
+                return NoisyVelocityTracker.obtain();
+            case PLATFORM_IMPL:
+                return PlatformVelocityTracker.obtain();
+            default:
+                throw new IllegalStateException("Invalid tracker: " + tracker);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/VelocityTrackerInterface.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/VelocityTrackerInterface.java
new file mode 100644
index 0000000..a54b054
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/VelocityTrackerInterface.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.view.MotionEvent;
+
+/**
+ * An interface for a velocity tracker to delegate. To be implemented by different velocity tracking
+ * algorithms.
+ */
+public interface VelocityTrackerInterface {
+    public void addMovement(MotionEvent event);
+    public void computeCurrentVelocity(int units);
+    public float getXVelocity();
+    public float getYVelocity();
+    public void recycle();
+}