Android 11 Recent App 修改滑动方向,解决滑动crash

问题:把手机旋转到270°,然后打开任务列表(就是屏幕下方的方块按钮。)然后向上无法把打开的app删除,可以向下滑动,但是会crash。

 

修改后,在270°的时候可以向上删除app,无法向下滑动,也不会crash。

 

首先打开adb logcat,看问题出在哪。从long中,这个recent app不是packages下的的recent app。尽然是launcher3。

01-01 09:25:13.930  1455  8142 I ActivityTaskManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000000 pkg=com.android.launcher3 cmp=com.android.launcher3/com.android.searchlauncher.SearchLauncher (has extras)} from uid 10169

 

但是去launcher3下面也找不到SearchLauncher,所有这个launcher3可能被overlay了。所以去对应的地方找代码。一般都是在vendor下。我这边是在vendor/partner_gms/apps/SearchLauncher 在这,打开androidmanifest.xml

        <activity
            android:name="com.android.searchlauncher.SearchLauncher"
            android:launchMode="singleTask"
            android:clearTaskOnLaunch="true"
            android:stateNotNeeded="true"
            android:windowSoftInputMode="adjustPan"
            android:screenOrientation="unspecified"
            android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
            android:resizeableActivity="true"
            android:resumeWhilePausing="true"
            android:taskAffinity=""
            android:enabled="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.HOME" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.MONKEY"/>
                <category android:name="android.intent.category.LAUNCHER_APP" />
            </intent-filter>
            <meta-data
                android:name="com.android.launcher3.grid.control"
                android:value="${packageName}.grid_control" />
        </activity>

找到了这个SeracherLauncher,再往下也没深入追了。

---------------------------------------------------------------------------------------------------------------------

直接看crash的地方,是在packages/apps/Launcher3/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java 中的

        mCurrentAnimation.setPlayFraction(Utilities.boundToRange(
                totalDisplacement * mProgressMultiplier, 0, 1));

mCurrentAnimation空指针异常。

------------------------------------------------------------------------------------------------------------------------

滑动的流程

packages/apps/Launcher3/src/com/android/launcher3/touch/BaseSwipeDetector.java

中会去监听屏幕touch事件。

public boolean onTouchEvent(MotionEvent ev) {
        int actionMasked = ev.getActionMasked();
        if (actionMasked == MotionEvent.ACTION_DOWN && mVelocityTracker != null) {
            mVelocityTracker.clear();
        }
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
        mVelocityTracker.addMovement(ev);

        switch (actionMasked) {
            case MotionEvent.ACTION_DOWN:
                mActivePointerId = ev.getPointerId(0);
                mDownPos.set(ev.getX(), ev.getY());
                mLastPos.set(mDownPos);
                mLastDisplacement.set(0, 0);
                mDisplacement.set(0, 0);

                if (mState == ScrollState.SETTLING && mIgnoreSlopWhenSettling) {
                    setState(ScrollState.DRAGGING);
                }
                break;
            //case MotionEvent.ACTION_POINTER_DOWN:
            case MotionEvent.ACTION_POINTER_UP:
                int ptrIdx = ev.getActionIndex();
                int ptrId = ev.getPointerId(ptrIdx);
                if (ptrId == mActivePointerId) {
                    final int newPointerIdx = ptrIdx == 0 ? 1 : 0;
                    mDownPos.set(
                            ev.getX(newPointerIdx) - (mLastPos.x - mDownPos.x),
                            ev.getY(newPointerIdx) - (mLastPos.y - mDownPos.y));
                    mLastPos.set(ev.getX(newPointerIdx), ev.getY(newPointerIdx));
                    mActivePointerId = ev.getPointerId(newPointerIdx);
                }
                break;
            case MotionEvent.ACTION_MOVE:
                Log.i("c","ACTION_MOVE mState "+mState);
                int pointerIndex = ev.findPointerIndex(mActivePointerId);
                if (pointerIndex == INVALID_POINTER_ID) {
                    Log.i("c","INVALID_POINTER_ID");
                    break;
                }
                mDisplacement.set(ev.getX(pointerIndex) - mDownPos.x,
                        ev.getY(pointerIndex) - mDownPos.y);
                if (mIsRtl) {
                    mDisplacement.x = -mDisplacement.x;
                }

                // handle state and listener calls.
                if (mState != ScrollState.DRAGGING && shouldScrollStart(mDisplacement)) {
                    Log.i("c","setState DRAGGING");
                    setState(ScrollState.DRAGGING);
                }
                if (TestProtocol.sDebugTracing) {
                    Log.d(TestProtocol.PAUSE_NOT_DETECTED, "before report dragging");
                }
                if (mState == ScrollState.DRAGGING) {
                    Log.i("c","reportDragging");
                    reportDragging(ev);
                }
                mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
                break;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                // These are synthetic events and there is no need to update internal values.
                if (mState == ScrollState.DRAGGING) {
                    setState(ScrollState.SETTLING);
                }
                mVelocityTracker.recycle();
                mVelocityTracker = null;
                break;
            default:
                break;
        }
        return true;
    }

主要看ACTION_MOVE这个,mState是当前的状态,如果不是正在滑出app,并且可以开始滑动,那么就去把状态设置成滑动中。然后去滑动。

                if (mState != ScrollState.DRAGGING && shouldScrollStart(mDisplacement)) {
                    Log.i("c","setState DRAGGING");
                    setState(ScrollState.DRAGGING);
                }

                if (mState == ScrollState.DRAGGING) {
                    Log.i("c","reportDragging");
                    reportDragging(ev);
                }

  shouldScrollStart 是 这个抽象函数,具体实现在packages/apps/Launcher3/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java

    @Override
    protected boolean shouldScrollStart(PointF displacement) {
        // Reject cases where the angle or slop condition is not met.
        float minDisplacement = Math.max(mTouchSlop,
                Math.abs(mDir.extractOrthogonalDirection(displacement)));
        if (Math.abs(mDir.extractDirection(displacement)) < minDisplacement) {
            Log.i("c","shouldScrollStart  return false");
            return false;
        }
        Log.i("c","shouldScrollStart  minDisplacement "+minDisplacement+" extractDirection "+Math.abs(mDir.extractDirection(displacement)));

        // Check if the client is interested in scroll in current direction.
        float displacementComponent = mDir.extractDirection(displacement);
        return canScrollNegative(displacementComponent) || canScrollPositive(displacementComponent);
    }

    private boolean canScrollNegative(float displacement) {
        Log.i("c","canScrollNegative  "+mScrollDirections +"  "+ mDir.isNegative(displacement));
        return (mScrollDirections & DIRECTION_NEGATIVE) > 0 && mDir.isNegative(displacement);
    }

    private boolean canScrollPositive(float displacement) {
        Log.i("c"," canScrollPositive "+mScrollDirections +"  "+mDir.isPositive(displacement));
        return (mScrollDirections & DIRECTION_POSITIVE) > 0 && mDir.isPositive(displacement);
    }

下面继续看reportDragging做了什么

    private void reportDragging(MotionEvent event) {
        Log.d(TAG, "mDisplacement  "+mDisplacement+"  mLastDisplacement "+mLastDisplacement);
        if (mDisplacement != mLastDisplacement) {
            if (DBG) {
                Log.d(TAG, String.format("onDrag disp=%s", mDisplacement));
            }

            mLastDisplacement.set(mDisplacement);
            sTempPoint.set(mDisplacement.x - mSubtractDisplacement.x,
                    mDisplacement.y - mSubtractDisplacement.y);
            reportDraggingInternal(sTempPoint, event);
        }
    }

然后继续追reportDraggingInternal,是在SingleAxisSwipeDetector.java中实现

    @Override
    protected void reportDraggingInternal(PointF displacement, MotionEvent event) {
        if (TestProtocol.sDebugTracing) {
            Log.d(TestProtocol.PAUSE_NOT_DETECTED, "SingleAxisSwipeDetector "
                    + mListener.getClass().getSimpleName());
        }
        mListener.onDrag(mDir.extractDirection(displacement),
                mDir.extractOrthogonalDirection(displacement), event);
    }

然后追onDrag,这是一个listener,是在TaskViewTouchController中重写的。这边new SingleAxisSwipeDetector是时候this就是。onDrag   onDragEnd   onDragStart这些。分别是手滑动,离开屏幕和接触屏幕时会走的。

    public TaskViewTouchController(T activity) {
        mActivity = activity;
        mRecentsView = activity.getOverviewPanel();
        mIsRtl = Utilities.isRtl(activity.getResources());
        SingleAxisSwipeDetector.Direction dir =
            mRecentsView.getPagedOrientationHandler().getOppositeSwipeDirection();
        mDetector = new SingleAxisSwipeDetector(activity, this, dir);
    }

 

最后packages/apps/Launcher3/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java看一下。它会根据屏幕旋转的角度去处理一些东西。

    public boolean update(
            @SurfaceRotation int touchRotation, @SurfaceRotation int displayRotation) {
        mRecentsActivityRotation = inferRecentsActivityRotation(displayRotation);
        mDisplayRotation = displayRotation;
        mTouchRotation = touchRotation;
        mPreviousRotation = touchRotation;

        PagedOrientationHandler oldHandler = mOrientationHandler;
        if (mRecentsActivityRotation == mTouchRotation
                || (canRecentsActivityRotate() && (mFlags & FLAG_SWIPE_UP_NOT_RUNNING) != 0)) {
            mOrientationHandler = PagedOrientationHandler.PORTRAIT;
            if (DEBUG) {
                Log.d(TAG, "current RecentsOrientedState: " + this);
            }
        } else if (mTouchRotation == ROTATION_90) {
            mOrientationHandler = PagedOrientationHandler.LANDSCAPE;
        } else if (mTouchRotation == ROTATION_270) {
            mOrientationHandler = PagedOrientationHandler.SEASCAPE;
        } else {
            mOrientationHandler = PagedOrientationHandler.PORTRAIT;
        }
        if (DEBUG) {
            Log.d(TAG, "current RecentsOrientedState: " + this);
        }
        return oldHandler != mOrientationHandler;
    }

 

--------------------------------------------------------------------------------------------------------------------------

 

修改。

加了很多log,发现在270°的时候,向上滑动不会触发reportDragging。说明前面setState肯定没有走,log上看是shouldScrollStart返回false。

                if (mState != ScrollState.DRAGGING && shouldScrollStart(mDisplacement)) {
                    Log.i("c","setState DRAGGING");
                    setState(ScrollState.DRAGGING);
                }
                if (TestProtocol.sDebugTracing) {
                    Log.d(TestProtocol.PAUSE_NOT_DETECTED, "before report dragging");
                }
                if (mState == ScrollState.DRAGGING) {
                    Log.i("c","reportDragging");
                    reportDragging(ev);
                }

继续追log, 其实是canScrollNegative返回false。(mScrollDirections & DIRECTION_NEGATIVE) > 0 不满足条件。所以在270°的时候要让这个条件满足。

    @Override
    protected boolean shouldScrollStart(PointF displacement) {
        // Reject cases where the angle or slop condition is not met.
        float minDisplacement = Math.max(mTouchSlop,
                Math.abs(mDir.extractOrthogonalDirection(displacement)));
        if (Math.abs(mDir.extractDirection(displacement)) < minDisplacement) {
            Log.i("c","shouldScrollStart  return false");
            return false;
        }
        Log.i("c","shouldScrollStart  minDisplacement "+minDisplacement+" extractDirection "+Math.abs(mDir.extractDirection(displacement)));

        // Check if the client is interested in scroll in current direction.
        float displacementComponent = mDir.extractDirection(displacement);
        return canScrollNegative(displacementComponent) || canScrollPositive(displacementComponent);
    }

    private boolean canScrollNegative(float displacement) {
        Log.i("c","canScrollNegative  "+mScrollDirections +"  "+ mDir.isNegative(displacement));
        return (mScrollDirections & DIRECTION_NEGATIVE) > 0 && mDir.isNegative(displacement);
    }

    private boolean canScrollPositive(float displacement) {
        Log.i("c"," canScrollPositive "+mScrollDirections +"  "+mDir.isPositive(displacement));
        return (mScrollDirections & DIRECTION_POSITIVE) > 0 && mDir.isPositive(displacement);
    }

在TaskViewTouchController中的onControllerInterceptTouchEvent中添加,ACRION_DOWN的时候就去设置,DIRECTION_NEGATIVE。然后canScrollNegative那就能返回true,向上滑动就能触发了。

  @Override
    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
        if ((ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL)
                && mCurrentAnimation == null) {
            clearState();
        }
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {

        //省略代码


            //Add
           mRecentsView.getOrientationState().getTouchRotation();
            Log.i("a","onControllerInterceptTouchEvent  touch rotation "+mRecentsView.getOrientationState().getTouchRotation());
            if(mRecentsView.getOrientationState().getTouchRotation() ==ROTATION_270){
                Log.i("a","onControllerInterceptTouchEvent  270 ");
                directionsToDetectScroll= DIRECTION_NEGATIVE;
            }
            //end


            Log.i("a","onControllerInterceptTouchEvent  setDetectableScrollConditions "+directionsToDetectScroll);
            mDetector.setDetectableScrollConditions(
                    directionsToDetectScroll, ignoreSlopWhenSettling);
        }

        if (mNoIntercept) {
            return false;
        }

        onControllerTouchEvent(ev);
        return mDetector.isDraggingOrSettling();
    }

 

但是每次向下滑动还是会crash,所以我们要对270°做特殊处理。在crash的地方处理。

    private void reInitAnimationController(boolean goingUp) {
        Log.i("a","reInitAnimationController mCurrentAnimationIsGoingUp "+mCurrentAnimationIsGoingUp
        +"  goingUp  "+goingUp);
        if (mCurrentAnimation != null && mCurrentAnimationIsGoingUp == goingUp) {
            // No need to init
            Log.i("a","no need to init");
            return;
        }
        int scrollDirections = mDetector.getScrollDirections();
        Log.i("a","reInitAnimationController  goingUp  "+goingUp + "  scrollDirections  "+
                scrollDirections );

        //add  防止crash,在270°的时候不走走,继续初始化
        if (mRecentsView.getOrientationState().getTouchRotation() != ROTATION_270) {        
//end
            if (goingUp && ((scrollDirections & DIRECTION_POSITIVE) == 0)
                    || !goingUp && ((scrollDirections & DIRECTION_NEGATIVE) == 0)) {
                // Trying to re-init in an unsupported direction.
                Log.i("a", "203");
                return;
            }
        } 
        //add   向下滑动会打开app,加了可以避免。
        else {
            if (goingUp == false && mCurrentAnimationIsGoingUp == true) {
                Log.i("a", "220");
                return;
            }
        }//end
}

 

到这修改完成,270°的时候,可以向上滑动删除app,向下无操作。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值