1 /* 2 * Copyright (C) 2010 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 package com.android.inputmethod.latin; 18 19 import android.view.MotionEvent; 20 21 class SwipeTracker { 22 private static final int NUM_PAST = 4; 23 private static final int LONGEST_PAST_TIME = 200; 24 25 final EventRingBuffer mBuffer = new EventRingBuffer(NUM_PAST); 26 27 private float mYVelocity; 28 private float mXVelocity; 29 addMovement(MotionEvent ev)30 public void addMovement(MotionEvent ev) { 31 if (ev.getAction() == MotionEvent.ACTION_DOWN) { 32 mBuffer.clear(); 33 return; 34 } 35 long time = ev.getEventTime(); 36 final int count = ev.getHistorySize(); 37 for (int i = 0; i < count; i++) { 38 addPoint(ev.getHistoricalX(i), ev.getHistoricalY(i), ev.getHistoricalEventTime(i)); 39 } 40 addPoint(ev.getX(), ev.getY(), time); 41 } 42 addPoint(float x, float y, long time)43 private void addPoint(float x, float y, long time) { 44 final EventRingBuffer buffer = mBuffer; 45 while (buffer.size() > 0) { 46 long lastT = buffer.getTime(0); 47 if (lastT >= time - LONGEST_PAST_TIME) 48 break; 49 buffer.dropOldest(); 50 } 51 buffer.add(x, y, time); 52 } 53 computeCurrentVelocity(int units)54 public void computeCurrentVelocity(int units) { 55 computeCurrentVelocity(units, Float.MAX_VALUE); 56 } 57 computeCurrentVelocity(int units, float maxVelocity)58 public void computeCurrentVelocity(int units, float maxVelocity) { 59 final EventRingBuffer buffer = mBuffer; 60 final float oldestX = buffer.getX(0); 61 final float oldestY = buffer.getY(0); 62 final long oldestTime = buffer.getTime(0); 63 64 float accumX = 0; 65 float accumY = 0; 66 final int count = buffer.size(); 67 for (int pos = 1; pos < count; pos++) { 68 final int dur = (int)(buffer.getTime(pos) - oldestTime); 69 if (dur == 0) continue; 70 float dist = buffer.getX(pos) - oldestX; 71 float vel = (dist / dur) * units; // pixels/frame. 72 if (accumX == 0) accumX = vel; 73 else accumX = (accumX + vel) * .5f; 74 75 dist = buffer.getY(pos) - oldestY; 76 vel = (dist / dur) * units; // pixels/frame. 77 if (accumY == 0) accumY = vel; 78 else accumY = (accumY + vel) * .5f; 79 } 80 mXVelocity = accumX < 0.0f ? Math.max(accumX, -maxVelocity) 81 : Math.min(accumX, maxVelocity); 82 mYVelocity = accumY < 0.0f ? Math.max(accumY, -maxVelocity) 83 : Math.min(accumY, maxVelocity); 84 } 85 86 public float getXVelocity() { 87 return mXVelocity; 88 } 89 90 public float getYVelocity() { 91 return mYVelocity; 92 } 93 94 static class EventRingBuffer { 95 private final int bufSize; 96 private final float xBuf[]; 97 private final float yBuf[]; 98 private final long timeBuf[]; 99 private int top; // points new event 100 private int end; // points oldest event 101 private int count; // the number of valid data 102 103 public EventRingBuffer(int max) { 104 this.bufSize = max; 105 xBuf = new float[max]; 106 yBuf = new float[max]; 107 timeBuf = new long[max]; 108 clear(); 109 } 110 111 public void clear() { 112 top = end = count = 0; 113 } 114 115 public int size() { 116 return count; 117 } 118 119 // Position 0 points oldest event 120 private int index(int pos) { 121 return (end + pos) % bufSize; 122 } 123 124 private int advance(int index) { 125 return (index + 1) % bufSize; 126 } 127 128 public void add(float x, float y, long time) { 129 xBuf[top] = x; 130 yBuf[top] = y; 131 timeBuf[top] = time; 132 top = advance(top); 133 if (count < bufSize) { 134 count++; 135 } else { 136 end = advance(end); 137 } 138 } 139 140 public float getX(int pos) { 141 return xBuf[index(pos)]; 142 } 143 144 public float getY(int pos) { 145 return yBuf[index(pos)]; 146 } 147 148 public long getTime(int pos) { 149 return timeBuf[index(pos)]; 150 } 151 152 public void dropOldest() { 153 count--; 154 end = advance(end); 155 } 156 } 157 }