1 package js.kbars; 2 3 import android.content.Context; 4 import android.graphics.Canvas; 5 import android.graphics.Paint; 6 import android.graphics.Paint.Cap; 7 import android.graphics.Paint.Style; 8 import android.graphics.Rect; 9 import android.graphics.Typeface; 10 import android.util.Log; 11 import android.view.MotionEvent; 12 import android.view.View; 13 import android.view.View.OnLayoutChangeListener; 14 import android.widget.FrameLayout; 15 import java.util.ArrayList; 16 import java.util.List; 17 import js.kbars.SystemGestureDebugger.DownPointerInfo; 18 import js.kbars.SystemGestureDebugger.ThresholdInfo; 19 20 public class TouchTrackingLayout extends FrameLayout { 21 private static final boolean DEBUG_EVENTS = true; 22 private static final int MAX_INFO_LINES = 6; 23 private static final int MAX_POINTERS = 5; 24 private static final int MAX_POINTS = 5000; 25 private static final String TAG = Util.logTag(TouchTrackingLayout.class); 26 private boolean mDebug; 27 private final DownPointerInfo mDownPointerInfo = new DownPointerInfo(); 28 private final SystemGestureDebugger mGestures; 29 private final Paint mInfoPaint = new Paint(); 30 private final StringBuilder[] mInfoText = allocateInfoText(); 31 private final int mInfoTextLineHeight; 32 private final int mInfoTextOffset; 33 private final int[] mScribbleCounts = new int[MAX_POINTERS]; 34 private final Paint mScribblePaint = new Paint(); 35 private final List<float[]> mScribblePoints = allocatePoints(); 36 private final int mTextSize; 37 private final ThresholdInfo mThresholdInfo = new ThresholdInfo(); 38 private final float[] mThresholdLines = new float[16]; 39 private final Paint mThresholdPaint = new Paint(); 40 41 public TouchTrackingLayout(Context context) { 42 super(context); 43 setWillNotDraw(false); 44 int densityDpi = Util.getDensityDpi(context); 45 this.mTextSize = (int) (((float) densityDpi) / 12.0f); 46 this.mInfoTextLineHeight = (int) (((float) densityDpi) / 11.0f); 47 this.mInfoTextOffset = (int) (((float) densityDpi) / 1.7f); 48 Log.d(TAG, "mTextSize=" + this.mTextSize + " mInfoTextLineHeight=" + this.mInfoTextLineHeight + " mInfoTextOffset=" + this.mInfoTextOffset); 49 this.mScribblePaint.setColor(-13388315); 50 this.mScribblePaint.setStrokeWidth((float) this.mTextSize); 51 this.mScribblePaint.setStrokeCap(Cap.ROUND); 52 this.mScribblePaint.setStyle(Style.STROKE); 53 this.mGestures = new SystemGestureDebugger(context, new SystemGestureDebugger.Callbacks() { 54 public void onSwipeFromTop() { 55 Log.d(TouchTrackingLayout.TAG, "GestureCallbacks.onSwipeFromTop"); 56 } 57 58 public void onSwipeFromRight() { 59 Log.d(TouchTrackingLayout.TAG, "GestureCallbacks.onSwipeFromRight"); 60 } 61 62 public void onSwipeFromBottom() { 63 Log.d(TouchTrackingLayout.TAG, "GestureCallbacks.onSwipeFromBottom"); 64 } 65 66 public void onDebug() { 67 Log.d(TouchTrackingLayout.TAG, "GestureCallbacks.onDebug"); 68 } 69 }); 70 this.mGestures.getThresholdInfo(this.mThresholdInfo); 71 this.mInfoPaint.setTypeface(Typeface.MONOSPACE); 72 this.mInfoPaint.setTextSize((float) this.mTextSize); 73 this.mInfoPaint.setStyle(Style.STROKE); 74 this.mInfoPaint.setColor(-13388315); 75 this.mThresholdPaint.setColor(-13388315); 76 this.mThresholdPaint.setStrokeWidth(1.0f); 77 this.mThresholdPaint.setStyle(Style.STROKE); 78 addOnLayoutChangeListener(new OnLayoutChangeListener() { 79 public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { 80 TouchTrackingLayout.this.mGestures.screenWidth = right - left; 81 TouchTrackingLayout.this.mGestures.screenHeight = bottom - top; 82 TouchTrackingLayout.this.horLine(0, TouchTrackingLayout.this.mThresholdInfo.start); 83 TouchTrackingLayout.this.horLine(1, TouchTrackingLayout.this.mGestures.screenHeight - TouchTrackingLayout.this.mThresholdInfo.start); 84 TouchTrackingLayout.this.verLine(2, TouchTrackingLayout.this.mThresholdInfo.start); 85 TouchTrackingLayout.this.verLine(3, TouchTrackingLayout.this.mGestures.screenWidth - TouchTrackingLayout.this.mThresholdInfo.start); 86 } 87 }); 88 } 89 90 public boolean getDebug() { 91 return this.mDebug; 92 } 93 94 public void setDebug(boolean debug) { 95 this.mDebug = debug; 96 invalidate(); 97 } 98 99 protected boolean fitSystemWindows(Rect insets) { 100 Rect insetsBefore = new Rect(insets); 101 boolean rt = super.fitSystemWindows(insets); 102 Log.d(TAG, String.format("fitSystemWindows insetsBefore=%s insetsAfter=%s rt=%s", new Object[]{insetsBefore.toShortString(), insets.toShortString(), Boolean.valueOf(rt)})); 103 return rt; 104 } 105 106 private void horLine(int lineNum, int y) { 107 this.mThresholdLines[(lineNum * 4) + 0] = 0.0f; 108 float[] fArr = this.mThresholdLines; 109 int i = (lineNum * 4) + 1; 110 float f = (float) y; 111 this.mThresholdLines[(lineNum * 4) + 3] = f; 112 fArr[i] = f; 113 this.mThresholdLines[(lineNum * 4) + 2] = (float) this.mGestures.screenWidth; 114 } 115 116 private void verLine(int lineNum, int x) { 117 float[] fArr = this.mThresholdLines; 118 int i = (lineNum * 4) + 0; 119 float f = (float) x; 120 this.mThresholdLines[(lineNum * 4) + 2] = f; 121 fArr[i] = f; 122 this.mThresholdLines[(lineNum * 4) + 1] = 0.0f; 123 this.mThresholdLines[(lineNum * 4) + 3] = (float) this.mGestures.screenHeight; 124 } 125 126 private static StringBuilder[] allocateInfoText() { 127 StringBuilder[] rt = new StringBuilder[MAX_INFO_LINES]; 128 for (int i = 0; i < rt.length; i++) { 129 rt[i] = new StringBuilder(); 130 } 131 return rt; 132 } 133 134 public boolean onTouchEvent(MotionEvent ev) { 135 super.onTouchEvent(ev); 136 this.mGestures.onPointerEvent(ev); 137 computeInfoText(); 138 onMotionEvent(ev); 139 return true; 140 } 141 142 protected void onDraw(Canvas canvas) { 143 int i; 144 for (i = 0; i < this.mScribbleCounts.length; i++) { 145 int c = this.mScribbleCounts[i]; 146 if (c > 0) { 147 canvas.drawLines((float[]) this.mScribblePoints.get(i), 0, c - 2, this.mScribblePaint); 148 } 149 } 150 if (this.mDebug) { 151 int leftMargin = this.mThresholdInfo.start + (this.mTextSize / 4); 152 for (i = 0; i < this.mInfoText.length; i++) { 153 StringBuilder sb = this.mInfoText[i]; 154 canvas.drawText(sb, 0, sb.length(), (float) leftMargin, (float) (this.mInfoTextOffset + (this.mInfoTextLineHeight * i)), this.mInfoPaint); 155 } 156 canvas.drawLines(this.mThresholdLines, this.mThresholdPaint); 157 } 158 } 159 160 private void computeInfoText() { 161 int dpc = this.mGestures.getDownPointers(); 162 for (int i = 0; i < this.mInfoText.length; i++) { 163 StringBuilder sb = this.mInfoText[i]; 164 sb.delete(0, sb.length()); 165 if (i == 0) { 166 sb.append("th "); 167 pad(sb, 9, this.mThresholdInfo.start); 168 sb.append(" "); 169 pad(sb, 9, this.mThresholdInfo.distance); 170 sb.append(' '); 171 pad(sb, MAX_POINTERS, (int) this.mThresholdInfo.elapsed); 172 sb.append("ms"); 173 } else if (i - 1 < dpc) { 174 this.mGestures.getDownPointerInfo(i - 1, this.mDownPointerInfo); 175 sb.append('p'); 176 sb.append(this.mDownPointerInfo.downPointerId); 177 sb.append(' '); 178 sb.append('('); 179 pad(sb, 4, (int) this.mDownPointerInfo.downX); 180 sb.append(','); 181 pad(sb, 4, (int) this.mDownPointerInfo.downY); 182 sb.append(')'); 183 sb.append(' '); 184 sb.append('('); 185 pad(sb, 4, (int) (this.mDownPointerInfo.currentX - this.mDownPointerInfo.downX)); 186 sb.append(','); 187 pad(sb, 4, (int) (this.mDownPointerInfo.currentY - this.mDownPointerInfo.downY)); 188 sb.append(')'); 189 sb.append(' '); 190 pad(sb, 4, (int) this.mDownPointerInfo.elapsedThreshold); 191 sb.append("ms"); 192 } 193 } 194 } 195 196 private static void pad(StringBuilder sb, int len, int num) { 197 int n = num; 198 if (num < 0) { 199 n = Math.abs(num); 200 len--; 201 } 202 int nl = n > 0 ? ((int) Math.log10((double) n)) + 1 : 1; 203 while (true) { 204 int nl2 = nl + 1; 205 if (nl >= len) { 206 break; 207 } 208 sb.append(' '); 209 nl = nl2; 210 } 211 if (num < 0) { 212 sb.append('-'); 213 } 214 sb.append(n); 215 } 216 217 private static List<float[]> allocatePoints() { 218 List<float[]> points = new ArrayList(); 219 for (int i = 0; i < MAX_POINTERS; i++) { 220 points.add(new float[MAX_POINTS]); 221 } 222 return points; 223 } 224 225 private void onMotionEvent(MotionEvent ev) { 226 long evt; 227 int p; 228 Log.d(TAG, "EVENT " + ev); 229 if (ev.getActionMasked() == 0) { 230 clearScribbles(); 231 } 232 int hs = ev.getHistorySize(); 233 int ps = ev.getPointerCount(); 234 for (int h = 0; h < hs; h++) { 235 evt = ev.getHistoricalEventTime(h); 236 for (p = 0; p < ps; p++) { 237 int pid = ev.getPointerId(p); 238 float hx = ev.getHistoricalX(p, h); 239 float hy = ev.getHistoricalY(p, h); 240 String str = TAG; 241 Object[] objArr = new Object[MAX_POINTERS]; 242 objArr[0] = Long.valueOf(evt); 243 objArr[1] = Integer.valueOf(p); 244 objArr[2] = Integer.valueOf(pid); 245 objArr[3] = Float.valueOf(hx); 246 objArr[4] = Float.valueOf(hy); 247 Log.d(str, String.format("h.evt=%s p=%s pid=%s x=%s y=%s", objArr)); 248 recordScribblePoint(pid, hx, hy); 249 } 250 } 251 evt = ev.getEventTime(); 252 for (p = 0; p < ps; p++) { 253 int pid = ev.getPointerId(p); 254 float x = ev.getX(p); 255 float y = ev.getY(p); 256 String str = TAG; 257 Object[] objArr = new Object[MAX_POINTERS]; 258 objArr[0] = Long.valueOf(evt); 259 objArr[1] = Integer.valueOf(p); 260 objArr[2] = Integer.valueOf(pid); 261 objArr[3] = Float.valueOf(x); 262 objArr[4] = Float.valueOf(y); 263 Log.d(str, String.format("c.evt=%s p=%s pid=%s x=%s y=%s", objArr)); 264 recordScribblePoint(pid, x, y); 265 } 266 invalidate(); 267 } 268 269 private void clearScribbles() { 270 for (int i = 0; i < this.mScribbleCounts.length; i++) { 271 this.mScribbleCounts[i] = 0; 272 } 273 } 274 275 private void recordScribblePoint(int pid, float x, float y) { 276 if (pid < MAX_POINTERS) { 277 float[] pts = (float[]) this.mScribblePoints.get(pid); 278 int oldCount = this.mScribbleCounts[pid]; 279 if (oldCount + 4 >= MAX_POINTS) { 280 return; 281 } 282 int[] iArr; 283 if (oldCount == 0) { 284 pts[oldCount + 0] = x; 285 pts[oldCount + 1] = y; 286 iArr = this.mScribbleCounts; 287 iArr[pid] = iArr[pid] + 2; 288 return; 289 } 290 pts[oldCount + 0] = x; 291 pts[oldCount + 1] = y; 292 pts[oldCount + 2] = x; 293 pts[oldCount + 3] = y; 294 iArr = this.mScribbleCounts; 295 iArr[pid] = iArr[pid] + 4; 296 } 297 } 298 } 299