Home | History | Annotate | Download | only in phone
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License
     15  */
     16 
     17 package com.android.systemui.statusbar.phone;
     18 
     19 import android.util.Log;
     20 import android.util.Pools;
     21 import android.view.MotionEvent;
     22 
     23 import java.util.ArrayDeque;
     24 import java.util.Iterator;
     25 
     26 /**
     27  * A very simple low-pass velocity filter for motion events for noisy touch screens.
     28  */
     29 public class NoisyVelocityTracker implements VelocityTrackerInterface {
     30 
     31     private static final Pools.SynchronizedPool<NoisyVelocityTracker> sNoisyPool =
     32             new Pools.SynchronizedPool<>(2);
     33 
     34     private static final float DECAY = 0.75f;
     35     private static final boolean DEBUG = false;
     36 
     37     private final int MAX_EVENTS = 8;
     38     private ArrayDeque<MotionEventCopy> mEventBuf = new ArrayDeque<MotionEventCopy>(MAX_EVENTS);
     39     private float mVX, mVY = 0;
     40 
     41     private static class MotionEventCopy {
     42         public MotionEventCopy(float x2, float y2, long eventTime) {
     43             this.x = x2;
     44             this.y = y2;
     45             this.t = eventTime;
     46         }
     47         float x, y;
     48         long t;
     49     }
     50 
     51     public static NoisyVelocityTracker obtain() {
     52         NoisyVelocityTracker instance = sNoisyPool.acquire();
     53         return (instance != null) ? instance : new NoisyVelocityTracker();
     54     }
     55 
     56     private NoisyVelocityTracker() {
     57     }
     58 
     59     public void addMovement(MotionEvent event) {
     60         if (mEventBuf.size() == MAX_EVENTS) {
     61             mEventBuf.remove();
     62         }
     63         mEventBuf.add(new MotionEventCopy(event.getX(), event.getY(), event.getEventTime()));
     64     }
     65 
     66     public void computeCurrentVelocity(int units) {
     67         if (NoisyVelocityTracker.DEBUG) {
     68             Log.v("FlingTracker", "computing velocities for " + mEventBuf.size() + " events");
     69         }
     70         mVX = mVY = 0;
     71         MotionEventCopy last = null;
     72         int i = 0;
     73         float totalweight = 0f;
     74         float weight = 10f;
     75         for (final Iterator<MotionEventCopy> iter = mEventBuf.iterator();
     76                 iter.hasNext();) {
     77             final MotionEventCopy event = iter.next();
     78             if (last != null) {
     79                 final float dt = (float) (event.t - last.t) / units;
     80                 final float dx = (event.x - last.x);
     81                 final float dy = (event.y - last.y);
     82                 if (NoisyVelocityTracker.DEBUG) {
     83                     Log.v("FlingTracker", String.format(
     84                             "   [%d] (t=%d %.1f,%.1f) dx=%.1f dy=%.1f dt=%f vx=%.1f vy=%.1f",
     85                             i, event.t, event.x, event.y,
     86                             dx, dy, dt,
     87                             (dx/dt),
     88                             (dy/dt)
     89                     ));
     90                 }
     91                 if (event.t == last.t) {
     92                     // Really not sure what to do with events that happened at the same time,
     93                     // so we'll skip subsequent events.
     94                     continue;
     95                 }
     96                 mVX += weight * dx / dt;
     97                 mVY += weight * dy / dt;
     98                 totalweight += weight;
     99                 weight *= DECAY;
    100             }
    101             last = event;
    102             i++;
    103         }
    104         if (totalweight > 0) {
    105             mVX /= totalweight;
    106             mVY /= totalweight;
    107         } else {
    108             // so as not to contaminate the velocities with NaN
    109             mVX = mVY = 0;
    110         }
    111 
    112         if (NoisyVelocityTracker.DEBUG) {
    113             Log.v("FlingTracker", "computed: vx=" + mVX + " vy=" + mVY);
    114         }
    115     }
    116 
    117     public float getXVelocity() {
    118         if (Float.isNaN(mVX) || Float.isInfinite(mVX)) {
    119             mVX = 0;
    120         }
    121         return mVX;
    122     }
    123 
    124     public float getYVelocity() {
    125         if (Float.isNaN(mVY) || Float.isInfinite(mVX)) {
    126             mVY = 0;
    127         }
    128         return mVY;
    129     }
    130 
    131     public void recycle() {
    132         mEventBuf.clear();
    133         sNoisyPool.release(this);
    134     }
    135 }
    136