Android launcher slides up to enter allapps and recentUI

Time:
The company does not allow csdn before 2021/01/21, and the notes are written elsewhere. recently tidied up

background description

The difference between Q and R is that sliding up to enter allapps and recentUI gestures are different. This article mainly analyzes the timing of entering and exiting the recentUI interface.

Phenomenon comparison

AndroidQ AndroidR
1. Swipe up continuously to enter allapps 1. Only the bottom slide up and slide out the recentUI
2. Pause in the middle of sliding up, exhale recentUI peek, let go to enter recentUI 2. Swiping up in the middle of the screen will no longer call out the recentUI peek interface
3. Continue to slide up to the top, exit from recentUI peek, let go to enter allapps

More clearly distinguish the start timing of the two interfaces

AndroidQ process analysis

In the touch event, call according to the timing.
All touch processing in this process is distributed from SwipeDetector.onTouchEvent, and FlingAndHoldTouchController specifically handles and animates.

Pseudo-flowchart
SwipeDetector.Java FlingAndHoldTouchController.Java
onTouchEvent–>setState–>reportDragStart/reportDragEnd

reportDragStart–>onDragStart: Set pause monitoring. When sliding pauses, enter and exit the peek animation of recentUI (animation is implemented in FlingAndHoldTouchController.onDragStart) in
onTouchEvent.move–>reportDragging–>onDrag: Continue to judge whether the gesture is within the range that can be paused and whether it is possible Pause, modify the flag bit
reportDragEnd–>onDragEnd: If the flag bit is paused, start the recentUI animation

Q code logic

com/android/launcher3/touch/SwipeDetector.java
onTouchEvent中
对手指触摸进行处理,
case MotionEvent.ACTION_MOVE:
    int pointerIndex = ev.findPointerIndex(mActivePointerId);
    if (pointerIndex == INVALID_POINTER_ID) {
    
    
        break;
    }
    //获取手在Y轴上的位移
    //具体实现在com/android/launcher3/touch/SwipeDetector.java中,分别针对横屏和竖屏计算
    mDisplacement = mDir.getDisplacement(ev, pointerIndex, mDownPos, mIsRtl);
    if (TestProtocol.sDebugTracing) {
    
    
        Log.d(TestProtocol.NO_ALLAPPS_EVENT_TAG, "onTouchEvent 1");
    }

    // handle state and listener calls.
    if (mState != ScrollState.DRAGGING && shouldScrollStart(ev, pointerIndex)) {
    
    
        if (TestProtocol.sDebugTracing) {
    
    
            Log.d(TestProtocol.NO_ALLAPPS_EVENT_TAG, "onTouchEvent 2");
        }
        setState(ScrollState.DRAGGING);
    }
    if (mState == ScrollState.DRAGGING) {
    
    
        reportDragging(ev);
    }
    mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
    break;

com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java

//设置运动暂停监听,呼入呼出peek动画
@Override
public void onDragStart(boolean start) {
    
    
    mMotionPauseDetector.clear();

    super.onDragStart(start);

    if (handlingOverviewAnim()) {
    
    
        mMotionPauseDetector.setOnMotionPauseListener(isPaused -> {
    
    
            RecentsView recentsView = mLauncher.getOverviewPanel();
            recentsView.setOverviewStateEnabled(isPaused);
            if (mPeekAnim != null) {
    
    
                mPeekAnim.cancel();
            }
            LauncherState fromState = isPaused ? NORMAL : OVERVIEW_PEEK;
            LauncherState toState = isPaused ? OVERVIEW_PEEK : NORMAL;
            long peekDuration = isPaused ? PEEK_IN_ANIM_DURATION : PEEK_OUT_ANIM_DURATION;
            mPeekAnim = mLauncher.getStateManager().createAtomicAnimation(fromState, toState,
                    new AnimatorSetBuilder(), ATOMIC_OVERVIEW_PEEK_COMPONENT, peekDuration);
            mPeekAnim.addListener(new AnimatorListenerAdapter() {
    
    
                @Override
                public void onAnimationEnd(Animator animation) {
    
    
                    mPeekAnim = null;
                }
            });
            mPeekAnim.start();
            recentsView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
                    HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
        });
    }
}
//动态判断手势
@Override
public boolean onDrag(float displacement, MotionEvent event) {
    
    
    float upDisplacement = -displacement;

    //判断当前点的位置是否允许暂停,只有在合理范围内暂停才会进入recentUI界面
    //这2个坐标点,判断上滑的位置 进入和退出recentUI界面前提动画--动画1
    //如果在这2个数值之间停顿、松手,就会进入recentUI界面--动画2
    mMotionPauseDetector.setDisallowPause(upDisplacement < mMotionPauseMinDisplacement
            || upDisplacement > mMotionPauseMaxDisplacement);
    //判断是否暂停
    mMotionPauseDetector.addPosition(displacement, event.getEventTime());
    return super.onDrag(displacement, event);
}

//运动判断相关
com/android/quickstep/util/MotionPauseDetector.java
addPosition
checkMotionPaused
updatePaused
//回调监听呼出peek动画
mOnMotionPauseListener.onMotionPauseChanged(mIsPaused);// listener实现在FlingAndHoldTouchController中

//松手后判断是否进入recentUI
@Override
public void onDragEnd(float velocity, boolean fling) {
    
    
    if (mMotionPauseDetector.isPaused() && handlingOverviewAnim()) {
    
    
        if (mPeekAnim != null) {
    
    
            mPeekAnim.cancel();
        }

        AnimatorSetBuilder builder = new AnimatorSetBuilder();
        builder.setInterpolator(ANIM_VERTICAL_PROGRESS, OVERSHOOT_1_2);
        if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
    
    
            builder.setInterpolator(ANIM_HOTSEAT_SCALE, OVERSHOOT_1_2);
            builder.setInterpolator(ANIM_HOTSEAT_TRANSLATE, OVERSHOOT_1_2);
        }
        //呼出recentUI之后松手进入recentUI界面动画
        AnimatorSet overviewAnim = mLauncher.getStateManager().createAtomicAnimation(
                NORMAL, OVERVIEW, builder, ANIM_ALL, ATOMIC_DURATION);
        overviewAnim.addListener(new AnimatorListenerAdapter() {
    
    
            @Override
            public void onAnimationEnd(Animator animation) {
    
    
                onSwipeInteractionCompleted(OVERVIEW, Touch.SWIPE);
            }
        });
        overviewAnim.start();
    } else {
    
    
        super.onDragEnd(velocity, fling);
    }
    mMotionPauseDetector.clear();
}

AndroidR process analysis

大体流程和Q相同,但是R上多了下面一个类:
NoButtonNavbarToOverviewTouchController extends FlingAndHoldTouchController
继承并重写关键方法,实现进入overview动画
packages/apps/Launcher3/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java

@Override
protected boolean canInterceptTouch(MotionEvent ev) {
    
    
    //判断是否从边缘触发Touch事件
    mDidTouchStartInNavBar = (ev.getEdgeFlags() & EDGE_NAV_BAR) != 0;
    Log.d(TestProtocol.PAUSE_NOT_DETECTED,"ev.getEdgeFlags(): "+ev.getEdgeFlags()+" EDGE_NAV_BAR: "+EDGE_NAV_BAR);
    return super.canInterceptTouch(ev);
}

@Override
protected boolean handlingOverviewAnim() {
    
    
    return mDidTouchStartInNavBar && super.handlingOverviewAnim();
}

@Override
protected void onMotionPauseChanged(boolean isPaused) {
    
    
    if (mCurrentAnimation == null) {
    
    
        return;
    }
    mNormalToHintOverviewScrimAnimator = null;
    mCurrentAnimation.dispatchOnCancelWithoutCancelRunnable(() -> {
    
    
        mLauncher.getStateManager().goToState(OVERVIEW, true, () -> {
    
    
            mReachedOverview = true;
            maybeSwipeInteractionToOverviewComplete();
        });
    });
    VibratorWrapper.INSTANCE.get(mLauncher).vibrate(OVERVIEW_HAPTIC);
}
...未完待续

Refer to https://blog.csdn.net/a396604593/article/details/127965396 for the rest of the logic

ViewConfiguration.getScaledTouchSlop//;触发移动事件的最小距离,自定义View处理touch事件的时候,有的时候需要判断用户是否真的存在movie,系统提供了这样的方法。表示滑动的时候,手的移动要大于这个返回的距离值才开始移动控件

Guess you like

Origin blog.csdn.net/a396604593/article/details/129796777