Android 7.0 锁屏解锁之向上滑动显示解锁界面分析

Android 7.0 锁屏解锁之向上滑动显示解锁界面分析

by jing.chen
锁屏的解锁操作是在锁屏界面向上滑动实现的,通过向上滑动调出解锁界面(如图案、PIN、密码解锁界面),在解锁界面输入正确的密码之后解锁显示launcher。向上滑动如何调出解锁界面,需要分析PanelView的onTouchEvent事件,用户向上滑动的整个touch事件分析如下:
Android 7.0 锁屏解锁之向上滑动显示解锁界面分析_第1张图片

1、用户手指touch屏幕,产生touch down事件,最底层view StatusBarWindowView会执行onInterceptTouchEvent,看是否需要拦截touch事件,touch down事件在此没有被拦截,再一级级往子View传递,都没有被拦截,之后执行OnTouchEvent,从子View开始往父View传递,一级级往父View传递,也都没有消耗touch down事件;
2、用户移动手指,产生touch move事件,最底层view StatusBarWindowView会执行onInterceptTouchEvent,看是否需要拦截touch事件,touch move事件在此也没有被拦截,再一级级往子View传递,都没有被拦截,之后执行OnTouchEvent,从子View开始往父View传递,一级级往父View传递,到PanelView这里当手指移动的距离达到一定的阈值会调用onTrackingStarted从而设置mTracking的值为true,接收此touch move事件,之后的touch事件直接传到此View。在用户滑动过程会调用setExpandedHeightInternal,进而调用NotificationPanelView的onHeightUpdated进行锁屏上的时间和通知View根据手指的移动距离进行缩小、变透明处理;
3、用户抬起手指,产生touch up事件,PanelView接收到这个事件后会调用endMotionEvent,如果手指从down到up之间移动的距离达到一定阈值会调用onTrackingStopped,从而调出解锁界面;
代码分析如下:

PanelView.java

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        ...
        final float x = event.getX(pointerIndex);
        final float y = event.getY(pointerIndex);

        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
            mGestureWaitForTouchSlop = isFullyCollapsed() || hasConflictingGestures();
            mIgnoreXTouchSlop = isFullyCollapsed() || shouldGestureIgnoreXTouchSlop(x, y);
        }

        switch (event.getActionMasked()) {
            ...
            case MotionEvent.ACTION_MOVE:
                float h = y - mInitialTouchY;

                // If the panel was collapsed when touching, we only need to check for the
                // y-component of the gesture, as we have no conflicting horizontal gesture.
                if (Math.abs(h) > mTouchSlop
                        && (Math.abs(h) > Math.abs(x - mInitialTouchX)
                                || mIgnoreXTouchSlop)) {
                    mTouchSlopExceeded = true;
                    if (mGestureWaitForTouchSlop && !mTracking && !mCollapsedAndHeadsUpOnDown) {
                        if (!mJustPeeked && mInitialOffsetOnTouch != 0f) {
                            startExpandMotion(x, y, false /* startTracking */, mExpandedHeight);
                            h = 0;
                        }
                        cancelHeightAnimator();
                        removeCallbacks(mPeekRunnable);
                        mPeekPending = false;
                        onTrackingStarted();//向上滑动时,手指移动的距离达到一定的阈值会调用onTrackingStarted,设置mTracking值为true,从而接收touch事件
                    }
                }
                final float newHeight = Math.max(0, h + mInitialOffsetOnTouch);
                if (newHeight > mPeekHeight) {
                    if (mPeekAnimator != null) {
                        mPeekAnimator.cancel();
                    }
                    mJustPeeked = false;
                }
                if (-h >= getFalsingThreshold()) {
                    mTouchAboveFalsingThreshold = true;
                    mUpwardsWhenTresholdReached = isDirectionUpwards(x, y);
                }
                if (!mJustPeeked && (!mGestureWaitForTouchSlop || mTracking) && !isTrackingBlocked()) {
           setExpandedHeightInternal(newHeight);//用户滑动过程会调用setExpandedHeightInternal,进而调用NotificationPanelView的onHeightUpdated进行锁屏上的时间和通知View根据手指的移动距离进行缩小、变透明处理 
                }

                trackMovement(event);
                break;

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

    protected void onTrackingStarted() {
        endClosing();
        mTracking = true;
        mCollapseAfterPeek = false;
        mBar.onTrackingStarted();
        notifyExpandingStarted();
        notifyBarPanelExpansionChanged();
    }

NotificationPanelView.java
    @Override
    protected void onHeightUpdated(float expandedHeight,  boolean isMovingInKeyguard) {
        mExpandedHeightTpv = expandedHeight;
        LogUtils.d(TAG,"--------onHeightUpdated");
        if (!mQsExpanded || mQsExpandImmediate || mIsExpanding && mQsExpandedWhenExpandingStarted) {
            positionClockAndNotifications(isMovingInKeyguard);//锁屏上的时间和通知View根据手指的移动距离进行缩小、变透明处理

        }
        ...
    }

endMotionEvent调出解锁界面流程如下:
->PanelView.endMotionEvent(MotionEvent event, float x, float y, boolean forceCancel)
->NotificationPanelView.onTrackingStopped(boolean expand)
->PhoneStatusBar.onTrackingStopped(boolean expand)
->PhoneStatusBar.showBouncer()
->StatusBarKeyguardViewManager.dismiss()
->StatusBarKeyguardViewManager.dismiss(boolean authenticated)
->StatusBarKeyguardViewManager.showBouncer(boolean authenticated)
->KeyguardBouncer.show(boolean resetSecuritySelection, boolean authenticated)
->KeyguardBouncer.mShowRunnable
调用KeyguardBouncer.show(boolean resetSecuritySelection, boolean authenticated)方法并没有重新加载解锁界面,解锁界面是在灭屏时调用StatusBarKeyguardViewManager.reset后重新inflate进来的,在此处只是通过KeyguardBouncer.mShowRunnable将这个解锁界面显示出来,灭屏时解锁界面的调用栈如下:
“main@52911” prio=5 tid=0x1 nid=NA runnable
java.lang.Thread.State: RUNNABLE
at com.android.keyguard.KeyguardSecurityContainer.showSecurityScreen(KeyguardSecurityContainer.java:584)
at com.android.keyguard.KeyguardSecurityContainer.showPrimarySecurityScreen(KeyguardSecurityContainer.java:416)
at com.android.keyguard.KeyguardHostView.onFinishInflate(KeyguardHostView.java:168)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:867)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:821)
at android.view.LayoutInflater.parseInclude(LayoutInflater.java:994)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:854)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:821)
at android.view.LayoutInflater.inflate(LayoutInflater.java:518)
- locked <0xd005> (a java.lang.Object[])
at android.view.LayoutInflater.inflate(LayoutInflater.java:426)
at android.view.LayoutInflater.inflate(LayoutInflater.java:377)
at com.android.systemui.statusbar.phone.KeyguardBouncer.inflateView(KeyguardBouncer.java:317)
at com.android.systemui.statusbar.phone.KeyguardBouncer.ensureView(KeyguardBouncer.java:307)
at com.android.systemui.statusbar.phone.KeyguardBouncer.needsFullscreenBouncer(KeyguardBouncer.java:347)
at com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.showBouncerOrKeyguard(StatusBarKeyguardViewManager.java:130)
at com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.reset(StatusBarKeyguardViewManager.java:192)

至此把用户设定的解锁界面(图案、密码、PIN码)显示出来

你可能感兴趣的:(Android 7.0 锁屏解锁之向上滑动显示解锁界面分析)