Home | History | Annotate | Download | only in kbars
      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