Android13 解锁图标无法上滑解锁问题

        我在Android13上遇到了一个问题,如图,从解锁图标处上滑无法完成解锁。

  修改效果:以解锁图标为起点上滑可以解锁,按下解锁图标抬起解锁

修改后的代码:

frameworks/base/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java

    public boolean onTouchEvent(MotionEvent event, Runnable onGestureDetectedRunnable) {
        // if (!onInterceptTouchEvent(event)) {
        //     cancelTouches();
        //     return false;
        // }

        mOnGestureDetectedRunnable = onGestureDetectedRunnable;
        switch(event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_HOVER_ENTER:
                if (!mDownDetected && mAccessibilityManager.isTouchExplorationEnabled()) {
                    mVibrator.vibrate(
                            Process.myUid(),
                            getContext().getOpPackageName(),
                            UdfpsController.EFFECT_CLICK,
                            "lock-icon-down",
                            TOUCH_VIBRATION_ATTRIBUTES);
                }

                // The pointer that causes ACTION_DOWN is always at index 0.
                // We need to persist its ID to track it during ACTION_MOVE that could include
                // data for many other pointers because of multi-touch support.
                // mActivePointerId = event.getPointerId(0);
                // if (mVelocityTracker == null) {
                //     // To simplify the lifecycle of the velocity tracker, make sure it's never null
                //     // after ACTION_DOWN, and always null after ACTION_CANCEL or ACTION_UP.
                //     mVelocityTracker = VelocityTracker.obtain();
                // } else {
                //     // ACTION_UP or ACTION_CANCEL is not guaranteed to be called before a new
                //     // ACTION_DOWN, in that case we should just reuse the old instance.
                //     mVelocityTracker.clear();
                // }
                // mVelocityTracker.addMovement(event);

                mDownDetected = true;
                // mLongPressCancelRunnable = mExecutor.executeDelayed(
                //         this::onLongPress, LONG_PRESS_TIMEOUT);
                break;
            case MotionEvent.ACTION_MOVE:
            case MotionEvent.ACTION_HOVER_MOVE:
                if(!inLockIconArea(event)){
                    mDownDetected = false;
                }
                // mVelocityTracker.addMovement(event);
                // // Compute pointer velocity in pixels per second.
                // mVelocityTracker.computeCurrentVelocity(1000);
                // float velocity = UdfpsController.computePointerSpeed(mVelocityTracker,
                //         mActivePointerId);
                // if (event.getClassification() != MotionEvent.CLASSIFICATION_DEEP_PRESS
                //         && UdfpsController.exceedsVelocityThreshold(velocity)) {
                //     Log.v(TAG, "lock icon long-press rescheduled due to "
                //             + "high pointer velocity=" + velocity);
                //     mLongPressCancelRunnable.run();
                //     mLongPressCancelRunnable = mExecutor.executeDelayed(
                //             this::onLongPress, LONG_PRESS_TIMEOUT);
                // }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_HOVER_EXIT:
                // cancelTouches();
                //add
                if(inLockIconArea(event) && mDownDetected){
                    onLongPress();
                }
                //add end
                break;
        }

        return true;
    }

    /**
     * Intercepts the touch if the onDown event and current event are within this lock icon view's
     * bounds.
     */
    public boolean onInterceptTouchEvent(MotionEvent event) {
        // if (!inLockIconArea(event) || !isActionable()) {
        //     return false;
        // }

        // if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
        //     return true;
        // }

        // return mDownDetected;
        return false;
    }

解决过程,感兴趣的可以看下: 

         Android Studio下载SDK里面有自带的布局查看工具uiautomatorviewer,通过这个工具抓取截图,从resource-id这一栏的内容"com.android.systemui:id/lock_icon"得知,我们要找的控件位于systemui,id是lock_icon。

        在SystemUI模块中全局搜索lock_icon,发现在LockIconView中有使用到此id。

src/com/android/keyguard/LockIconView.java

src/com/android/keyguard/LockIconViewController.java

LockIconView --> LockIconViewController

LockIconViewController的onTouchEvent方法中实现了锁屏图标的触摸逻辑


    public boolean onTouchEvent(MotionEvent event, Runnable onGestureDetectedRunnable) {
        //---------------------------------------------------------------->(1)
        if (!onInterceptTouchEvent(event)) {
            cancelTouches();
            return false;
        }
        //---------------------------------------------------------------->(1)
        mOnGestureDetectedRunnable = onGestureDetectedRunnable;
        switch(event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_HOVER_ENTER:
        //---------------------------------------------------------------->(2)
        //一般情况下不走这里
                if (!mDownDetected && mAccessibilityManager.isTouchExplorationEnabled()) {
                    mVibrator.vibrate(
                            Process.myUid(),
                            getContext().getOpPackageName(),
                            UdfpsController.EFFECT_CLICK,
                            "lock-icon-down",
                            TOUCH_VIBRATION_ATTRIBUTES);
                }
        //---------------------------------------------------------------->(2)

                // The pointer that causes ACTION_DOWN is always at index 0.
                // We need to persist its ID to track it during ACTION_MOVE that could include
                // data for many other pointers because of multi-touch support.
        //---------------------------------------------------------------->(3)
        //初始化mVelocityTracker,用于在(5)中计算触摸移动速度
                mActivePointerId = event.getPointerId(0);
                if (mVelocityTracker == null) {
                    // To simplify the lifecycle of the velocity tracker, make sure it's never null
                    // after ACTION_DOWN, and always null after ACTION_CANCEL or ACTION_UP.
                    mVelocityTracker = VelocityTracker.obtain();
                } else {
                    // ACTION_UP or ACTION_CANCEL is not guaranteed to be called before a new
                    // ACTION_DOWN, in that case we should just reuse the old instance.
                    mVelocityTracker.clear();
                }
                mVelocityTracker.addMovement(event);
        //---------------------------------------------------------------->(3)
        //---------------------------------------------------------------->(4)
                mDownDetected = true;
                //LONG_PRESS_TIMEOUT是0.2s,延迟0.2s执行长按事件
                mLongPressCancelRunnable = mExecutor.executeDelayed(
                        this::onLongPress, LONG_PRESS_TIMEOUT);

        //---------------------------------------------------------------->(4)
                break;
            case MotionEvent.ACTION_MOVE:
            case MotionEvent.ACTION_HOVER_MOVE:
        //---------------------------------------------------------------->(5)
                mVelocityTracker.addMovement(event);
                // Compute pointer velocity in pixels per second.
                mVelocityTracker.computeCurrentVelocity(1000);
                float velocity = UdfpsController.computePointerSpeed(mVelocityTracker,
                        mActivePointerId);
                //判断触摸移动速度是否足够快
                if (event.getClassification() != MotionEvent.CLASSIFICATION_DEEP_PRESS
                        && UdfpsController.exceedsVelocityThreshold(velocity)) {
                    Log.v(TAG, "lock icon long-press rescheduled due to "
                            + "high pointer velocity=" + velocity);
                    //-------------------------------------------------->(5.1)
                    //取消ACTION_DOWN中的延迟0.2s触发长按事件
                    mLongPressCancelRunnable.run();
                    //再次开启延迟0.2s触发长按事件
                    mLongPressCancelRunnable = mExecutor.executeDelayed(
                            this::onLongPress, LONG_PRESS_TIMEOUT);
                    //-------------------------------------------------->(5.1)
                }
        //---------------------------------------------------------------->(5)
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_HOVER_EXIT:
                cancelTouches();
                break;
        }

        return true;
    }

要想修改此处的触摸逻辑,我们就必须先了解它原本的逻辑是怎样的。

当onInterceptTouchEvent为false的时候,就返回false。 

        //---------------------------------------------------------------->(1)
        if (!onInterceptTouchEvent(event)) {
            cancelTouches();
            return false;
        }
        //---------------------------------------------------------------->(1)

onInterceptTouchEvent当触摸区域不在解锁图标的范围内的时候,返回false。

这个很好理解,如果没有按在解锁图标上,就返回false不触发长按解锁按钮解锁的逻辑。

mDownDetected负责在ACTION_MOVE事件下移出解锁图标的边界的情况下拦截触摸事件,不让它继续分发,会造成以解锁图标为起点上滑无法解锁。 

    public boolean onInterceptTouchEvent(MotionEvent event) {
        if (!inLockIconArea(event) || !isActionable()) {
            return false;
        }

        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
            return true;
        }

        return mDownDetected;
    }

(2)处的代码忽略掉,一般情况下不走这里

        //---------------------------------------------------------------->(2)
                if (!mDownDetected && mAccessibilityManager.isTouchExplorationEnabled()) {
                    mVibrator.vibrate(
                            Process.myUid(),
                            getContext().getOpPackageName(),
                            UdfpsController.EFFECT_CLICK,
                            "lock-icon-down",
                            TOUCH_VIBRATION_ATTRIBUTES);
                }
        //---------------------------------------------------------------->(2)

(3)处的代码用于初始化VelocityTracker,这个类在(5)处用于计算触摸移动速度

        //---------------------------------------------------------------->(3)
                mActivePointerId = event.getPointerId(0);
                if (mVelocityTracker == null) {
                    // To simplify the lifecycle of the velocity tracker, make sure it's never null
                    // after ACTION_DOWN, and always null after ACTION_CANCEL or ACTION_UP.
                    mVelocityTracker = VelocityTracker.obtain();
                } else {
                    // ACTION_UP or ACTION_CANCEL is not guaranteed to be called before a new
                    // ACTION_DOWN, in that case we should just reuse the old instance.
                    mVelocityTracker.clear();
                }
                mVelocityTracker.addMovement(event);
        //---------------------------------------------------------------->(3)

(4) 用于延迟0.2s调用onLongPress

        //---------------------------------------------------------------->(4)
                mDownDetected = true;
                //计时两秒触发长按事件
                mLongPressCancelRunnable = mExecutor.executeDelayed(
                        this::onLongPress, LONG_PRESS_TIMEOUT);

        //---------------------------------------------------------------->(4)

(5) 首先,触摸点一定要在解锁图标上,否则在onTouchEvent的开头就返回了。

这里是在解锁图标的范围内快速移动的时候,0.2s触发长按事件会不停地刷新,重新计算时间

//---------------------------------------------------------------->(5)
                mVelocityTracker.addMovement(event);
                // Compute pointer velocity in pixels per second.
                mVelocityTracker.computeCurrentVelocity(1000);
                float velocity = UdfpsController.computePointerSpeed(mVelocityTracker,
                        mActivePointerId);
                //判断触摸移动速度是否足够快
                if (event.getClassification() != MotionEvent.CLASSIFICATION_DEEP_PRESS
                        && UdfpsController.exceedsVelocityThreshold(velocity)) {
                    Log.v(TAG, "lock icon long-press rescheduled due to "
                            + "high pointer velocity=" + velocity);
                    //-------------------------------------------------->(5.1)
                    //取消ACTION_DOWN中的延迟0.2s触发长按事件
                    mLongPressCancelRunnable.run();
                    //再次开启延迟0.2s触发长按事件
                    mLongPressCancelRunnable = mExecutor.executeDelayed(
                            this::onLongPress, LONG_PRESS_TIMEOUT);
                    //-------------------------------------------------->(5.1)
                }
        //---------------------------------------------------------------->(5)

 cancelTouches()在onTouchEvent的开头和ACTION_UP的时候用到

    private void cancelTouches() {
        mDownDetected = false;
        if (mLongPressCancelRunnable != null) {
            //取消长按事件
            mLongPressCancelRunnable.run();
        }
        if (mVelocityTracker != null) {
            //释放用于计算触摸速度的对象
            mVelocityTracker.recycle();
            mVelocityTracker = null;
        }
    }

总:解锁图标的触摸逻辑

(1)按在图标外面,onInterceptTouchEvent返回false,onTouchEvent返回false,不拦截触摸事件,可以正常上滑解锁。

(2)按在图标区域0.2s且移动速度小于阈值,解锁。

(3)按在图标区域,快速移动大于阈值,直到移动速度小于阈值0.2s,解锁。

(4)按在图标区域,0.2s内快速滑出图标区域,onInterceptTouchEvent返回false,onTouchEvent返回true,触摸事件无法继续分发,此时上滑无法解锁。
 

  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值