Android 11 SystemUI deletes the click-down animation of the status bar

one   Problem description

During a call, the screen is on because the distance sensor is not completely covered, and the status bar is pulled down due to touching the status bar near the ear after the screen is on

There are two ways to pull down the status bar: one is to drag the status bar, the other is to click the status bar twice in the unlocked screen to pull down the status bar (when clicking the status bar for the first time, the status bar will be pulled down to expand the animation. At this time, the status bar will be fully retracted after the animation display is completed. When clicking the status bar for the second time, the status bar will be fully expanded)

In the process of a call, there is a high probability that clicking causes the status bar to drop down, and the probability of dragging causes the drop-down is low, so this problem is solved in the click function of the status bar. In the case of clicking, because the premise of complete drop-down is that the status bar is in the expansion animation, the click-down function of the status bar can be deleted without displaying the expansion animation of the status bar

two   Click event distribution in the status bar

Clicking causes the status bar to drop Down. The processing logic must start with the processing logic of Down events and Up events, so you can check the distribution process of click events in the status bar first

Describe the distribution process of click events from the View level

Click events are transferred from ViewGroup to View, and the View in the status bar is PhoneStatusBarView. Therefore, View the click event distribution of PhoneStatusBarView

public boolean onTouchEvent(MotionEvent event) {
    boolean barConsumedEvent = mBar.interceptTouchEvent(event);

    if (DEBUG_GESTURES) {
        if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
            EventLog.writeEvent(EventLogTags.SYSUI_PANELBAR_TOUCH,
                    event.getActionMasked(), (int) event.getX(), (int) event.getY(),
                    barConsumedEvent ? 1 : 0);
        }
    }

    return barConsumedEvent || super.onTouchEvent(event);
}

There is no event processing here. Continue to call super.onTouchEvent downward
If the parent class of PhoneStatusBarView is PanelBar, call the onTouchEvent method of PanelBar
public boolean onTouchEvent(MotionEvent event) {
    // Allow subclasses to implement enable/disable semantics
    if (!panelEnabled()) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            Log.v(TAG, String.format("onTouch: all panels disabled, ignoring touch at (%d,%d)",
                    (int) event.getX(), (int) event.getY()));
        }
        return false;
    }

    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        final PanelViewController panel = mPanel;
        if (panel == null) {
            // panel is not there, so we'll eat the gesture
            Log.v(TAG, String.format("onTouch: no panel for touch at (%d,%d)",
                    (int) event.getX(), (int) event.getY()));
            return true;
        }
        boolean enabled = panel.isEnabled();
        if (DEBUG) LOG("PanelBar.onTouch: state=%d ACTION_DOWN: panel %s %s", mState, panel,
                (enabled ? "" : " (disabled)"));
        if (!enabled) {
            // panel is disabled, so we'll eat the gesture
            Log.v(TAG, String.format(
                    "onTouch: panel (%s) is disabled, ignoring touch at (%d,%d)",
                    panel, (int) event.getX(), (int) event.getY()));
            return true;
        }
    }
    return mPanel == null || mPanel.getView().dispatchTouchEvent(event);
}

At this time, there is a judgment to make a Down gesture. However, because panel is not equal to null and panel.isEnabled is equal to true, the if judgment cannot be entered and true will not be returned. When true is returned, the event will be consumed and will not be passed Down again, but it will continue to be passed Down to mPanel.getView().dispatchTouchEvent(event);
Events continue to be distributed. In the process of dispatchTouchEvent, if the event is not intercepted, it will go through onInterceptTouchEvent (a unique method of ViewGroup), followed by onTouch, and finally onTouchEvent
The event is eventually passed to the onTouch method of NotificationPanelViewController
public boolean onTouch(View v, MotionEvent event) {
    //......
    handled |= super.onTouch(v, event);
    return !mDozing || mPulsing || handled;
}
After a lot of judgment, we finally get to super.onTouch, whose parent class is PanelViewController
public boolean onTouch(View v, MotionEvent event) {
    //......

    /*
     * We capture touch events here and update the extension height here to prevent according to the user's fingers.
     * This also handles multi touch.
     *
     * If the user simply clicks, we will quickly see the shadow.
     *
     * You can also open or close the drop-down menu by dragging
     */

    //......
    switch (event.getActionMasked()) {
        case MotionEvent.ACTION_DOWN:
            startExpandMotion(x, y, false /* startTracking */, mExpandedHeight);
            mJustPeeked = false;
            mMinExpandHeight = 0.0f;
            mPanelClosedOnDown = isFullyCollapsed();
            mHasLayoutedSinceDown = false;
            mUpdateFlingOnLayout = false;
            mMotionAborted = false;
            mPeekTouching = mPanelClosedOnDown;
            mDownTime = SystemClock.uptimeMillis();
            mTouchAboveFalsingThreshold = false;
            mCollapsedAndHeadsUpOnDown =
                    isFullyCollapsed() && mHeadsUpManager.hasPinnedHeadsUp();
            addMovement(event);
            //......
            //The lock screen interface cannot click the drop-down status bar
            if (isFullyCollapsed() && !mHeadsUpManager.hasPinnedHeadsUp()
                    && !mStatusBar.isBouncerShowing()) {
                startOpening(event);
            }
            break;

        //......

        case MotionEvent.ACTION_UP:
            addMovement(event);
            endMotionEvent(event, x, y, false /* forceCancel */);
            break;
    }
    return !mGestureWaitForTouchSlop || mTracking;
}

Here is the processing logic of the real Down Up event. The native annotation shows that if the user simply clicks, he will quickly see the shade. When receiving the Down event, he will judge. If he is in the fully stowed state, is not in the click state, and is not in the lock screen interface, he will go to startOpening ()
private void startOpening(MotionEvent event) {
    runPeekAnimation(INITIAL_OPENING_PEEK_DURATION, getOpeningHeight(),
            false /* collapseWhenFinished */);
    //......
}

runPeekAnimation is mainly called in startOpening (), that is, click to quickly expand the animation of the shadow on time, and the height of the animation will be passed in when calling
If it is pressed, because the expanded animation is only as high as the status bar, the height is only 45. During the processing of Up time, it will be judged that if the Down and Up time does not exceed 400ms, the animation will still be called and the higher height will be reset
private void runPeekAnimation(long duration, float peekHeight, boolean collapseWhenFinished) {
    mPeekHeight = peekHeight;
    if (mHeightAnimator != null) {
        return;
    }
    if (mPeekAnimator != null) {
        mPeekAnimator.cancel();
    }
    mPeekAnimator = ObjectAnimator.ofFloat(this, "expandedHeight", mPeekHeight).setDuration(
            duration);
    mPeekAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
    mPeekAnimator.addListener(new AnimatorListenerAdapter() {
        private boolean mCancelled;

        @Override
        public void onAnimationCancel(Animator animation) {
            mCancelled = true;
        }

        @Override
        public void onAnimationEnd(Animator animation) {
            mPeekAnimator = null;
            if (!mCancelled && collapseWhenFinished) {
                mView.postOnAnimation(mPostCollapseRunnable);
            }

        }
    });
    notifyExpandingStarted();
    mPeekAnimator.start();
    mJustPeeked = true;
}

mPeekAnimator is to quickly expand the animation of Shade. There are many methods to delete the animation, but the following methods are used in the end
mPeekAnimator = ObjectAnimator.ofFloat(this, "expandedHeight", 0f).setDuration(
            duration);
Only adjust the animation height, and adjust the animation height at Down time and Up time to 0f, so the animation will not be displayed, the animation will not be displayed, and the second click event will not cause the status bar to drop Down completely

Keywords: Java Android

Added by Bendude14 on Thu, 30 Sep 2021 05:36:45 +0300