diff options
4 files changed, 377 insertions, 23 deletions
diff --git a/common/java/com/android/common/ui/PointerLocationView.java b/common/java/com/android/common/ui/PointerLocationView.java new file mode 100644 index 0000000..e83c5ae --- /dev/null +++ b/common/java/com/android/common/ui/PointerLocationView.java @@ -0,0 +1,333 @@ +package com.android.common.ui; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Paint.FontMetricsInt; +import android.util.Log; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.View; +import android.view.ViewConfiguration; + +import java.util.ArrayList; + +public class PointerLocationView extends View { + public static class PointerState { + private final ArrayList<Float> mXs = new ArrayList<Float>(); + private final ArrayList<Float> mYs = new ArrayList<Float>(); + private boolean mCurDown; + private int mCurX; + private int mCurY; + private float mCurPressure; + private float mCurSize; + private int mCurWidth; + private VelocityTracker mVelocity; + } + + private final ViewConfiguration mVC; + private final Paint mTextPaint; + private final Paint mTextBackgroundPaint; + private final Paint mTextLevelPaint; + private final Paint mPaint; + private final Paint mTargetPaint; + private final Paint mPathPaint; + private final FontMetricsInt mTextMetrics = new FontMetricsInt(); + private int mHeaderBottom; + private boolean mCurDown; + private int mCurNumPointers; + private int mMaxNumPointers; + private final ArrayList<PointerState> mPointers + = new ArrayList<PointerState>(); + + private boolean mPrintCoords = true; + + public PointerLocationView(Context c) { + super(c); + mVC = ViewConfiguration.get(c); + mTextPaint = new Paint(); + mTextPaint.setAntiAlias(true); + mTextPaint.setTextSize(10 + * getResources().getDisplayMetrics().density); + mTextPaint.setARGB(255, 0, 0, 0); + mTextBackgroundPaint = new Paint(); + mTextBackgroundPaint.setAntiAlias(false); + mTextBackgroundPaint.setARGB(128, 255, 255, 255); + mTextLevelPaint = new Paint(); + mTextLevelPaint.setAntiAlias(false); + mTextLevelPaint.setARGB(192, 255, 0, 0); + mPaint = new Paint(); + mPaint.setAntiAlias(true); + mPaint.setARGB(255, 255, 255, 255); + mPaint.setStyle(Paint.Style.STROKE); + mPaint.setStrokeWidth(2); + mTargetPaint = new Paint(); + mTargetPaint.setAntiAlias(false); + mTargetPaint.setARGB(255, 0, 0, 192); + mPathPaint = new Paint(); + mPathPaint.setAntiAlias(false); + mPathPaint.setARGB(255, 0, 96, 255); + mPaint.setStyle(Paint.Style.STROKE); + mPaint.setStrokeWidth(1); + + PointerState ps = new PointerState(); + ps.mVelocity = VelocityTracker.obtain(); + mPointers.add(ps); + } + + public void setPrintCoords(boolean state) { + mPrintCoords = state; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + mTextPaint.getFontMetricsInt(mTextMetrics); + mHeaderBottom = -mTextMetrics.ascent+mTextMetrics.descent+2; + if (false) { + Log.i("foo", "Metrics: ascent=" + mTextMetrics.ascent + + " descent=" + mTextMetrics.descent + + " leading=" + mTextMetrics.leading + + " top=" + mTextMetrics.top + + " bottom=" + mTextMetrics.bottom); + } + } + + @Override + protected void onDraw(Canvas canvas) { + synchronized (mPointers) { + final int w = getWidth(); + final int itemW = w/7; + final int base = -mTextMetrics.ascent+1; + final int bottom = mHeaderBottom; + + final int NP = mPointers.size(); + + if (NP > 0) { + final PointerState ps = mPointers.get(0); + canvas.drawRect(0, 0, itemW-1, bottom,mTextBackgroundPaint); + canvas.drawText("P: " + mCurNumPointers + " / " + mMaxNumPointers, + 1, base, mTextPaint); + + final int N = ps.mXs.size(); + if ((mCurDown && ps.mCurDown) || N == 0) { + canvas.drawRect(itemW, 0, (itemW * 2) - 1, bottom, mTextBackgroundPaint); + canvas.drawText("X: " + ps.mCurX, 1 + itemW, base, mTextPaint); + canvas.drawRect(itemW * 2, 0, (itemW * 3) - 1, bottom, mTextBackgroundPaint); + canvas.drawText("Y: " + ps.mCurY, 1 + itemW * 2, base, mTextPaint); + } else { + float dx = ps.mXs.get(N-1) - ps.mXs.get(0); + float dy = ps.mYs.get(N-1) - ps.mYs.get(0); + canvas.drawRect(itemW, 0, (itemW * 2) - 1, bottom, + Math.abs(dx) < mVC.getScaledTouchSlop() + ? mTextBackgroundPaint : mTextLevelPaint); + canvas.drawText("dX: " + String.format("%.1f", dx), 1 + itemW, base, mTextPaint); + canvas.drawRect(itemW * 2, 0, (itemW * 3) - 1, bottom, + Math.abs(dy) < mVC.getScaledTouchSlop() + ? mTextBackgroundPaint : mTextLevelPaint); + canvas.drawText("dY: " + String.format("%.1f", dy), 1 + itemW * 2, base, mTextPaint); + } + + canvas.drawRect(itemW * 3, 0, (itemW * 4) - 1, bottom, mTextBackgroundPaint); + int velocity = ps.mVelocity == null ? 0 : (int) (ps.mVelocity.getXVelocity() * 1000); + canvas.drawText("Xv: " + velocity, 1 + itemW * 3, base, mTextPaint); + + canvas.drawRect(itemW * 4, 0, (itemW * 5) - 1, bottom, mTextBackgroundPaint); + velocity = ps.mVelocity == null ? 0 : (int) (ps.mVelocity.getYVelocity() * 1000); + canvas.drawText("Yv: " + velocity, 1 + itemW * 4, base, mTextPaint); + + canvas.drawRect(itemW * 5, 0, (itemW * 6) - 1, bottom, mTextBackgroundPaint); + canvas.drawRect(itemW * 5, 0, (itemW * 5) + (ps.mCurPressure * itemW) - 1, + bottom, mTextLevelPaint); + canvas.drawText("Prs: " + String.format("%.2f", ps.mCurPressure), 1 + itemW * 5, + base, mTextPaint); + + canvas.drawRect(itemW * 6, 0, w, bottom, mTextBackgroundPaint); + canvas.drawRect(itemW * 6, 0, (itemW * 6) + (ps.mCurSize * itemW) - 1, + bottom, mTextLevelPaint); + canvas.drawText("Size: " + String.format("%.2f", ps.mCurSize), 1 + itemW * 6, + base, mTextPaint); + } + + for (int p=0; p<NP; p++) { + final PointerState ps = mPointers.get(p); + + if (mCurDown && ps.mCurDown) { + canvas.drawLine(0, (int)ps.mCurY, getWidth(), (int)ps.mCurY, mTargetPaint); + canvas.drawLine((int)ps.mCurX, 0, (int)ps.mCurX, getHeight(), mTargetPaint); + int pressureLevel = (int)(ps.mCurPressure*255); + mPaint.setARGB(255, pressureLevel, 128, 255-pressureLevel); + canvas.drawPoint(ps.mCurX, ps.mCurY, mPaint); + canvas.drawCircle(ps.mCurX, ps.mCurY, ps.mCurWidth, mPaint); + } + } + + for (int p=0; p<NP; p++) { + final PointerState ps = mPointers.get(p); + + final int N = ps.mXs.size(); + float lastX=0, lastY=0; + boolean haveLast = false; + boolean drawn = false; + mPaint.setARGB(255, 128, 255, 255); + for (int i=0; i<N; i++) { + float x = ps.mXs.get(i); + float y = ps.mYs.get(i); + if (Float.isNaN(x)) { + haveLast = false; + continue; + } + if (haveLast) { + canvas.drawLine(lastX, lastY, x, y, mPathPaint); + canvas.drawPoint(lastX, lastY, mPaint); + drawn = true; + } + lastX = x; + lastY = y; + haveLast = true; + } + + if (drawn) { + if (ps.mVelocity != null) { + mPaint.setARGB(255, 255, 64, 128); + float xVel = ps.mVelocity.getXVelocity() * (1000/60); + float yVel = ps.mVelocity.getYVelocity() * (1000/60); + canvas.drawLine(lastX, lastY, lastX+xVel, lastY+yVel, mPaint); + } else { + canvas.drawPoint(lastX, lastY, mPaint); + } + } + } + } + } + + public void addTouchEvent(MotionEvent event) { + synchronized (mPointers) { + int action = event.getAction(); + + //Log.i("Pointer", "Motion: action=0x" + Integer.toHexString(action) + // + " pointers=" + event.getPointerCount()); + + int NP = mPointers.size(); + + //mRect.set(0, 0, getWidth(), mHeaderBottom+1); + //invalidate(mRect); + //if (mCurDown) { + // mRect.set(mCurX-mCurWidth-3, mCurY-mCurWidth-3, + // mCurX+mCurWidth+3, mCurY+mCurWidth+3); + //} else { + // mRect.setEmpty(); + //} + if (action == MotionEvent.ACTION_DOWN) { + for (int p=0; p<NP; p++) { + final PointerState ps = mPointers.get(p); + ps.mXs.clear(); + ps.mYs.clear(); + ps.mVelocity = VelocityTracker.obtain(); + ps.mCurDown = false; + } + mPointers.get(0).mCurDown = true; + mMaxNumPointers = 0; + if (mPrintCoords) { + Log.i("Pointer", "Pointer 1: DOWN"); + } + } + + if ((action&MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_DOWN) { + final int id = (action&MotionEvent.ACTION_POINTER_ID_MASK) + >> MotionEvent.ACTION_POINTER_ID_SHIFT; + while (NP <= id) { + PointerState ps = new PointerState(); + ps.mVelocity = VelocityTracker.obtain(); + mPointers.add(ps); + NP++; + } + final PointerState ps = mPointers.get(id); + ps.mVelocity = VelocityTracker.obtain(); + ps.mCurDown = true; + if (mPrintCoords) { + Log.i("Pointer", "Pointer " + (id+1) + ": DOWN"); + } + } + + final int NI = event.getPointerCount(); + + mCurDown = action != MotionEvent.ACTION_UP + && action != MotionEvent.ACTION_CANCEL; + mCurNumPointers = mCurDown ? NI : 0; + if (mMaxNumPointers < mCurNumPointers) { + mMaxNumPointers = mCurNumPointers; + } + + for (int i=0; i<NI; i++) { + final PointerState ps = mPointers.get(event.getPointerId(i)); + ps.mVelocity.addMovement(event); + ps.mVelocity.computeCurrentVelocity(1); + final int N = event.getHistorySize(); + for (int j=0; j<N; j++) { + if (mPrintCoords) { + Log.i("Pointer", "Pointer " + (i+1) + ": (" + + event.getHistoricalX(i, j) + + ", " + event.getHistoricalY(i, j) + ")" + + " Prs=" + event.getHistoricalPressure(i, j) + + " Size=" + event.getHistoricalSize(i, j)); + } + ps.mXs.add(event.getHistoricalX(i, j)); + ps.mYs.add(event.getHistoricalY(i, j)); + } + if (mPrintCoords) { + Log.i("Pointer", "Pointer " + (i+1) + ": (" + + event.getX(i) + ", " + event.getY(i) + ")" + + " Prs=" + event.getPressure(i) + + " Size=" + event.getSize(i)); + } + ps.mXs.add(event.getX(i)); + ps.mYs.add(event.getY(i)); + ps.mCurX = (int)event.getX(i); + ps.mCurY = (int)event.getY(i); + //Log.i("Pointer", "Pointer #" + p + ": (" + ps.mCurX + // + "," + ps.mCurY + ")"); + ps.mCurPressure = event.getPressure(i); + ps.mCurSize = event.getSize(i); + ps.mCurWidth = (int)(ps.mCurSize*(getWidth()/3)); + } + + if ((action&MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP) { + final int id = (action&MotionEvent.ACTION_POINTER_ID_MASK) + >> MotionEvent.ACTION_POINTER_ID_SHIFT; + final PointerState ps = mPointers.get(id); + ps.mXs.add(Float.NaN); + ps.mYs.add(Float.NaN); + ps.mCurDown = false; + if (mPrintCoords) { + Log.i("Pointer", "Pointer " + (id+1) + ": UP"); + } + } + + if (action == MotionEvent.ACTION_UP) { + for (int i=0; i<NI; i++) { + final PointerState ps = mPointers.get(event.getPointerId(i)); + if (ps.mCurDown) { + ps.mCurDown = false; + if (mPrintCoords) { + Log.i("Pointer", "Pointer " + (i+1) + ": UP"); + } + } + } + } + + //if (mCurDown) { + // mRect.union(mCurX-mCurWidth-3, mCurY-mCurWidth-3, + // mCurX+mCurWidth+3, mCurY+mCurWidth+3); + //} + //invalidate(mRect); + postInvalidate(); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + addTouchEvent(event); + return true; + } +} diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index ee7193b..bfab30a 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -1489,6 +1489,14 @@ public final class Settings { public static final String DEFAULT_INSTALL_LOCATION = "default_install_location"; /** + * Show pointer location on screen? + * 0 = no + * 1 = yes + * @hide + */ + public static final String POINTER_LOCATION = "pointer_location"; + + /** * Settings to backup. This is here so that it's in the same place as the settings * keys and easy to update. * @hide diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 7bc5cce..ab3260e 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -851,6 +851,11 @@ public interface WindowManagerPolicy { */ public boolean isCheekPressedAgainstScreen(MotionEvent ev); + /** + * Called every time the window manager is dispatching a pointer event. + */ + public void dispatchedPointerEventLw(MotionEvent ev, int targetX, int targetY); + public void setCurrentOrientationLw(int newOrientation); /** diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index b5e6520..7fcf900 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -1773,6 +1773,32 @@ public class WindowManagerService extends IWindowManager.Stub } } + void dispatchPointerElsewhereLocked(WindowState srcWin, WindowState relWin, + MotionEvent pointer, long eventTime, boolean skipped) { + if (relWin != null) { + mPolicy.dispatchedPointerEventLw(pointer, relWin.mFrame.left, relWin.mFrame.top); + } else { + mPolicy.dispatchedPointerEventLw(pointer, 0, 0); + } + + // If we sent an initial down to the wallpaper, then continue + // sending events until the final up. + if (mSendingPointersToWallpaper) { + if (skipped) { + Log.i(TAG, "Sending skipped pointer to wallpaper!"); + } + sendPointerToWallpaperLocked(relWin, pointer, eventTime); + + // If we are on top of the wallpaper, then the wallpaper also + // gets to see this movement. + } else if (srcWin != null + && pointer.getAction() == MotionEvent.ACTION_DOWN + && mWallpaperTarget == srcWin + && srcWin.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD) { + sendPointerToWallpaperLocked(relWin, pointer, eventTime); + } + } + public int addWindow(Session session, IWindow client, WindowManager.LayoutParams attrs, int viewVisibility, Rect outContentInsets) { @@ -4918,10 +4944,7 @@ public class WindowManagerService extends IWindowManager.Stub Log.w(TAG, "No window to dispatch pointer action " + ev.getAction()); } synchronized (mWindowMap) { - if (mSendingPointersToWallpaper) { - Log.i(TAG, "Sending skipped pointer to wallpaper!"); - sendPointerToWallpaperLocked(null, ev, ev.getEventTime()); - } + dispatchPointerElsewhereLocked(null, null, ev, ev.getEventTime(), true); } if (qev != null) { mQueue.recycleEvent(qev); @@ -4931,10 +4954,7 @@ public class WindowManagerService extends IWindowManager.Stub } if (targetObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) { synchronized (mWindowMap) { - if (mSendingPointersToWallpaper) { - Log.i(TAG, "Sending skipped pointer to wallpaper!"); - sendPointerToWallpaperLocked(null, ev, ev.getEventTime()); - } + dispatchPointerElsewhereLocked(null, null, ev, ev.getEventTime(), true); } if (qev != null) { mQueue.recycleEvent(qev); @@ -5059,9 +5079,7 @@ public class WindowManagerService extends IWindowManager.Stub if (!target.isVisibleLw()) { // During this motion dispatch, the target window has become // invisible. - if (mSendingPointersToWallpaper) { - sendPointerToWallpaperLocked(null, ev, eventTime); - } + dispatchPointerElsewhereLocked(null, null, ev, ev.getEventTime(), false); if (qev != null) { mQueue.recycleEvent(qev); } @@ -5094,13 +5112,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - // If we are on top of the wallpaper, then the wallpaper also - // gets to see this movement. - if ((mWallpaperTarget == target && - target.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD) - || mSendingPointersToWallpaper) { - sendPointerToWallpaperLocked(null, ev, eventTime); - } + dispatchPointerElsewhereLocked(target, null, ev, ev.getEventTime(), false); final Rect frame = target.mFrame; ev.offsetLocation(-(float)frame.left, -(float)frame.top); @@ -6031,11 +6043,7 @@ public class WindowManagerService extends IWindowManager.Stub if (res != null && returnWhat == RETURN_PENDING_POINTER) { synchronized (mWindowMap) { - if ((mWallpaperTarget == win && - win.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD) - || mSendingPointersToWallpaper) { - sendPointerToWallpaperLocked(win, res, res.getEventTime()); - } + dispatchPointerElsewhereLocked(win, win, res, res.getEventTime(), false); } } |
