IMS:开发者选项中指针位置

IMS:开发者选项中指针位置

android11-release
在这里插入图片描述

开发者选项中指针位置开关

  • 指针位置 pointer_location:Settings.System.POINTER_LOCATION

      packages/apps/Settings/src/com/android/settings/development/PointerLocationPreferenceController.java
    

在这里插入图片描述

WindowManagerService监听

frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

private final Uri mPointerLocationUri = Settings.System.getUriFor(Settings.System.POINTER_LOCATION);

在这里插入图片描述
frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java
在这里插入图片描述在这里插入图片描述
PointerLocationView 创建并显示十字画线
在这里插入图片描述

PointerLocationView 显示

在这里插入图片描述
在这里插入图片描述

  • P: X / Y P就是 pointers ; x 是 current number pointers, y 是 max number pointers ,这些都是指在一个完整gesture中的。也就是,当同时用三手指触摸时x=y=3,而当只抬起一根手指时,当前屏幕上只有两根手指了,但是整个手势事件中最大pointers数是3,所以,x=2,y=3。显示为P:2/3
  • X:640.9Y:1250.9 X是active pointer的X轴坐标;Y是active pointer的Y轴坐标。当多点触摸时只有一个pointer是激活pointer(ActivePointer),所以X,Y表示的就是这个ActivePointer的X和Y轴坐标。dX和dY分别代表整个手势结束后活动点(ActivePointer)在X轴和Y轴方向上起始点到终止点的差值,其中X轴上从左到右为正值,Y轴上从上到下是正值,否则为负值。
  • Xv:0.0Yv:0.0 Xv和Yv分别代表了pointer当前触摸点point的X轴和Y轴方向上的速度,该速度是将MotionEvent传入VelocityTracker对象中通过计算得到的有正负区分,X轴向右,Y轴向下代表了正方向,否则为负数。多点触摸的情况下,Xv和Yv代表了ActivePointer的状态。
  • Prs:0.50 Prs 表示 Press 是一个归一化值,代表一个手指或者其他设备作用在屏幕上的压力值。它是MotionEvent内部类PointerCoords 中的一个属性,取值范围为0~1,但是也会有大于1的值出现,这取决于设备设置。
  • Size:0.0 Size 也是 MotionEvent 内部类 PointerCoords 中的另一个属性,描述了设备的最大可探测区域上pointer touch area的近似大小,代表了屏幕被按压区域的近似大小,该值可以用在决定是否是fat touch event上,取值范围为0~1

PointerLocationView中onDraw绘制

顶部Labels绘制: final PointerState ps = mPointers.get(mActivePointerId);

        // Labels
        if (mActivePointerId >= 0) {
            final PointerState ps = mPointers.get(mActivePointerId);
            
            canvas.drawRect(0, mHeaderPaddingTop, itemW-1, bottom,mTextBackgroundPaint);
            canvas.drawText(mText.clear()
                    .append("P: ").append(mCurNumPointers)
                    .append(" / ").append(mMaxNumPointers)
                    .toString(), 1, base, mTextPaint);

            final int N = ps.mTraceCount;
            if ((mCurDown && ps.mCurDown) || N == 0) {
                canvas.drawRect(itemW, mHeaderPaddingTop, (itemW * 2) - 1, bottom,
                        mTextBackgroundPaint);
                canvas.drawText(mText.clear()
                        .append("X: ").append(ps.mCoords.x, 1)
                        .toString(), 1 + itemW, base, mTextPaint);
                canvas.drawRect(itemW * 2, mHeaderPaddingTop, (itemW * 3) - 1, bottom,
                        mTextBackgroundPaint);
                canvas.drawText(mText.clear()
                        .append("Y: ").append(ps.mCoords.y, 1)
                        .toString(), 1 + itemW * 2, base, mTextPaint);
            } else {
                float dx = ps.mTraceX[N - 1] - ps.mTraceX[0];
                float dy = ps.mTraceY[N - 1] - ps.mTraceY[0];
                canvas.drawRect(itemW, mHeaderPaddingTop, (itemW * 2) - 1, bottom,
                        Math.abs(dx) < mVC.getScaledTouchSlop()
                        ? mTextBackgroundPaint : mTextLevelPaint);
                canvas.drawText(mText.clear()
                        .append("dX: ").append(dx, 1)
                        .toString(), 1 + itemW, base, mTextPaint);
                canvas.drawRect(itemW * 2, mHeaderPaddingTop, (itemW * 3) - 1, bottom,
                        Math.abs(dy) < mVC.getScaledTouchSlop()
                        ? mTextBackgroundPaint : mTextLevelPaint);
                canvas.drawText(mText.clear()
                        .append("dY: ").append(dy, 1)
                        .toString(), 1 + itemW * 2, base, mTextPaint);
            }

            canvas.drawRect(itemW * 3, mHeaderPaddingTop, (itemW * 4) - 1, bottom,
                    mTextBackgroundPaint);
            canvas.drawText(mText.clear()
                    .append("Xv: ").append(ps.mXVelocity, 3)
                    .toString(), 1 + itemW * 3, base, mTextPaint);

            canvas.drawRect(itemW * 4, mHeaderPaddingTop, (itemW * 5) - 1, bottom,
                    mTextBackgroundPaint);
            canvas.drawText(mText.clear()
                    .append("Yv: ").append(ps.mYVelocity, 3)
                    .toString(), 1 + itemW * 4, base, mTextPaint);

            canvas.drawRect(itemW * 5, mHeaderPaddingTop, (itemW * 6) - 1, bottom,
                    mTextBackgroundPaint);
            canvas.drawRect(itemW * 5, mHeaderPaddingTop,
                    (itemW * 5) + (ps.mCoords.pressure * itemW) - 1, bottom, mTextLevelPaint);
            canvas.drawText(mText.clear()
                    .append("Prs: ").append(ps.mCoords.pressure, 2)
                    .toString(), 1 + itemW * 5, base, mTextPaint);

            canvas.drawRect(itemW * 6, mHeaderPaddingTop, w, bottom, mTextBackgroundPaint);
            canvas.drawRect(itemW * 6, mHeaderPaddingTop,
                    (itemW * 6) + (ps.mCoords.size * itemW) - 1, bottom, mTextLevelPaint);
            canvas.drawText(mText.clear()
                    .append("Size: ").append(ps.mCoords.size, 2)
                    .toString(), 1 + itemW * 6, base, mTextPaint);
        }

手指点击Pointer trace十字线绘制: final PointerState ps = mPointers.get(p);

        // Pointer trace.
        for (int p = 0; p < NP; p++) {
            final PointerState ps = mPointers.get(p);

            // Draw path.
            final int N = ps.mTraceCount;
            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.mTraceX[i];
                float y = ps.mTraceY[i];
                if (Float.isNaN(x)) {
                    haveLast = false;
                    continue;
                }
                if (haveLast) {
                    canvas.drawLine(lastX, lastY, x, y, mPathPaint);
                    final Paint paint = ps.mTraceCurrent[i] ? mCurrentPointPaint : mPaint;
                    canvas.drawPoint(lastX, lastY, paint);
                    drawn = true;
                }
                lastX = x;
                lastY = y;
                haveLast = true;
            }

            if (drawn) {
                // Draw velocity vector.
                mPaint.setARGB(255, 255, 64, 128);
                float xVel = ps.mXVelocity * (1000 / 60);
                float yVel = ps.mYVelocity * (1000 / 60);
                canvas.drawLine(lastX, lastY, lastX + xVel, lastY + yVel, mPaint);

                // Draw velocity vector using an alternate VelocityTracker strategy.
                if (mAltVelocity != null) {
                    mPaint.setARGB(255, 64, 255, 128);
                    xVel = ps.mAltXVelocity * (1000 / 60);
                    yVel = ps.mAltYVelocity * (1000 / 60);
                    canvas.drawLine(lastX, lastY, lastX + xVel, lastY + yVel, mPaint);
                }
            }

            if (mCurDown && ps.mCurDown) {
                // Draw crosshairs.
                canvas.drawLine(0, ps.mCoords.y, getWidth(), ps.mCoords.y, mTargetPaint);
                canvas.drawLine(ps.mCoords.x, 0, ps.mCoords.x, getHeight(), mTargetPaint);

                // Draw current point.
                int pressureLevel = (int)(ps.mCoords.pressure * 255);
                mPaint.setARGB(255, pressureLevel, 255, 255 - pressureLevel);
                canvas.drawPoint(ps.mCoords.x, ps.mCoords.y, mPaint);

                // Draw current touch ellipse.
                mPaint.setARGB(255, pressureLevel, 255 - pressureLevel, 128);
                drawOval(canvas, ps.mCoords.x, ps.mCoords.y, ps.mCoords.touchMajor,
                        ps.mCoords.touchMinor, ps.mCoords.orientation, mPaint);

                // Draw current tool ellipse.
                mPaint.setARGB(255, pressureLevel, 128, 255 - pressureLevel);
                drawOval(canvas, ps.mCoords.x, ps.mCoords.y, ps.mCoords.toolMajor,
                        ps.mCoords.toolMinor, ps.mCoords.orientation, mPaint);

                // Draw the orientation arrow.
                float arrowSize = ps.mCoords.toolMajor * 0.7f;
                if (arrowSize < 20) {
                    arrowSize = 20;
                }
                mPaint.setARGB(255, pressureLevel, 255, 0);
                float orientationVectorX = (float) (Math.sin(ps.mCoords.orientation)
                        * arrowSize);
                float orientationVectorY = (float) (-Math.cos(ps.mCoords.orientation)
                        * arrowSize);
                if (ps.mToolType == MotionEvent.TOOL_TYPE_STYLUS
                        || ps.mToolType == MotionEvent.TOOL_TYPE_ERASER) {
                    // Show full circle orientation.
                    canvas.drawLine(ps.mCoords.x, ps.mCoords.y,
                            ps.mCoords.x + orientationVectorX,
                            ps.mCoords.y + orientationVectorY,
                            mPaint);
                } else {
                    // Show half circle orientation.
                    canvas.drawLine(
                            ps.mCoords.x - orientationVectorX,
                            ps.mCoords.y - orientationVectorY,
                            ps.mCoords.x + orientationVectorX,
                            ps.mCoords.y + orientationVectorY,
                            mPaint);
                }

                // Draw the tilt point along the orientation arrow.
                float tiltScale = (float) Math.sin(
                        ps.mCoords.getAxisValue(MotionEvent.AXIS_TILT));
                canvas.drawCircle(
                        ps.mCoords.x + orientationVectorX * tiltScale,
                        ps.mCoords.y + orientationVectorY * tiltScale,
                        3.0f, mPaint);

                // Draw the current bounding box
                if (ps.mHasBoundingBox) {
                    canvas.drawRect(ps.mBoundingLeft, ps.mBoundingTop,
                            ps.mBoundingRight, ps.mBoundingBottom, mPaint);
                }
            }
        }

ArrayList<PointerState> mPointers = new ArrayList<PointerState>();在 onPointerEvent 增加 PointerState ,属性 MotionEvent 事件上报

PointerEventDispatcher 注册和接收MotionEvent

mDisplayContent.registerPointerEventListener(mPointerLocationView) -> mPointerEventDispatcher.registerInputEventListener(listener)
PointerEventDispatcher 的 InputChannel,IMS:InputChannel通过socket发送Input给App 最后通过 onInputEvent 通知到 listeners[i].onPointerEvent(motionEvent),即是 PointerLocationView 的 onPointerEvent
在这里插入图片描述

    @Override
    public void onPointerEvent(MotionEvent event) {
        final int action = event.getAction();
        int NP = mPointers.size();

        if (action == MotionEvent.ACTION_DOWN
                || (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_DOWN) {
            final int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK)
                    >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; // will be 0 for down
            if (action == MotionEvent.ACTION_DOWN) {
                for (int p=0; p<NP; p++) {
                    final PointerState ps = mPointers.get(p);
                    ps.clearTrace();
                    ps.mCurDown = false;
                }
                mCurDown = true;
                mCurNumPointers = 0;
                mMaxNumPointers = 0;
                mVelocity.clear();
                if (mAltVelocity != null) {
                    mAltVelocity.clear();
                }
            }

            mCurNumPointers += 1;
            if (mMaxNumPointers < mCurNumPointers) {
                mMaxNumPointers = mCurNumPointers;
            }

            final int id = event.getPointerId(index);
            while (NP <= id) {
                PointerState ps = new PointerState();
                mPointers.add(ps);
                NP++;
            }

            if (mActivePointerId < 0 ||
                    !mPointers.get(mActivePointerId).mCurDown) {
                mActivePointerId = id;
            }

            final PointerState ps = mPointers.get(id);
            ps.mCurDown = true;
            InputDevice device = InputDevice.getDevice(event.getDeviceId());
            ps.mHasBoundingBox = device != null &&
                    device.getMotionRange(MotionEvent.AXIS_GENERIC_1) != null;
        }

        final int NI = event.getPointerCount();

        mVelocity.addMovement(event);
        mVelocity.computeCurrentVelocity(1);
        if (mAltVelocity != null) {
            mAltVelocity.addMovement(event);
            mAltVelocity.computeCurrentVelocity(1);
        }

        final int N = event.getHistorySize();
        for (int historyPos = 0; historyPos < N; historyPos++) {
            for (int i = 0; i < NI; i++) {
                final int id = event.getPointerId(i);
                final PointerState ps = mCurDown ? mPointers.get(id) : null;
                final PointerCoords coords = ps != null ? ps.mCoords : mTempCoords;
                event.getHistoricalPointerCoords(i, historyPos, coords);
                if (mPrintCoords) {
                    logCoords("Pointer", action, i, coords, id, event);
                }
                if (ps != null) {
                    ps.addTrace(coords.x, coords.y, false);
                }
            }
        }
        for (int i = 0; i < NI; i++) {
            final int id = event.getPointerId(i);
            final PointerState ps = mCurDown ? mPointers.get(id) : null;
            final PointerCoords coords = ps != null ? ps.mCoords : mTempCoords;
            event.getPointerCoords(i, coords);
            if (mPrintCoords) {
                logCoords("Pointer", action, i, coords, id, event);
            }
            if (ps != null) {
                ps.addTrace(coords.x, coords.y, true);
                ps.mXVelocity = mVelocity.getXVelocity(id);
                ps.mYVelocity = mVelocity.getYVelocity(id);
                mVelocity.getEstimator(id, ps.mEstimator);
                if (mAltVelocity != null) {
                    ps.mAltXVelocity = mAltVelocity.getXVelocity(id);
                    ps.mAltYVelocity = mAltVelocity.getYVelocity(id);
                    mAltVelocity.getEstimator(id, ps.mAltEstimator);
                }
                ps.mToolType = event.getToolType(i);

                if (ps.mHasBoundingBox) {
                    ps.mBoundingLeft = event.getAxisValue(MotionEvent.AXIS_GENERIC_1, i);
                    ps.mBoundingTop = event.getAxisValue(MotionEvent.AXIS_GENERIC_2, i);
                    ps.mBoundingRight = event.getAxisValue(MotionEvent.AXIS_GENERIC_3, i);
                    ps.mBoundingBottom = event.getAxisValue(MotionEvent.AXIS_GENERIC_4, i);
                }
            }
        }

        if (action == MotionEvent.ACTION_UP
                || action == MotionEvent.ACTION_CANCEL
                || (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP) {
            final int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK)
                    >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; // will be 0 for UP

            final int id = event.getPointerId(index);
            if (id >= NP) {
                Slog.wtf(TAG, "Got pointer ID out of bounds: id=" + id + " arraysize="
                        + NP + " pointerindex=" + index
                        + " action=0x" + Integer.toHexString(action));
                return;
            }
            final PointerState ps = mPointers.get(id);
            ps.mCurDown = false;

            if (action == MotionEvent.ACTION_UP
                    || action == MotionEvent.ACTION_CANCEL) {
                mCurDown = false;
                mCurNumPointers = 0;
            } else {
                mCurNumPointers -= 1;
                if (mActivePointerId == id) {
                    mActivePointerId = event.getPointerId(index == 0 ? 1 : 0);
                }
                ps.addTrace(Float.NaN, Float.NaN, false);
            }
        }

        invalidate();
    }

绘制属性

    public static class PointerState {
        // Trace of previous points.
        private float[] mTraceX = new float[32];
        private float[] mTraceY = new float[32];
        private boolean[] mTraceCurrent = new boolean[32];
        private int mTraceCount;
        
        // True if the pointer is down.
        @UnsupportedAppUsage
        private boolean mCurDown;
        
        // Most recent coordinates.
        private PointerCoords mCoords = new PointerCoords();
        private int mToolType;
        
        // Most recent velocity.
        private float mXVelocity;
        private float mYVelocity;
        private float mAltXVelocity;
        private float mAltYVelocity;

        // Current bounding box, if any
        private boolean mHasBoundingBox;
        private float mBoundingLeft;
        private float mBoundingTop;
        private float mBoundingRight;
        private float mBoundingBottom;

        // Position estimator.
        private VelocityTracker.Estimator mEstimator = new VelocityTracker.Estimator();
        private VelocityTracker.Estimator mAltEstimator = new VelocityTracker.Estimator();

        @UnsupportedAppUsage
        public PointerState() {
        }

        public void clearTrace() {
            mTraceCount = 0;
        }

        public void addTrace(float x, float y, boolean current) {
            int traceCapacity = mTraceX.length;
            if (mTraceCount == traceCapacity) {
                traceCapacity *= 2;
                float[] newTraceX = new float[traceCapacity];
                System.arraycopy(mTraceX, 0, newTraceX, 0, mTraceCount);
                mTraceX = newTraceX;
                
                float[] newTraceY = new float[traceCapacity];
                System.arraycopy(mTraceY, 0, newTraceY, 0, mTraceCount);
                mTraceY = newTraceY;

                boolean[] newTraceCurrent = new boolean[traceCapacity];
                System.arraycopy(mTraceCurrent, 0, newTraceCurrent, 0, mTraceCount);
                mTraceCurrent= newTraceCurrent;
            }
            
            mTraceX[mTraceCount] = x;
            mTraceY[mTraceCount] = y;
            mTraceCurrent[mTraceCount] = current;
            mTraceCount += 1;
        }
    }

待续~~~

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xhBruce

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值