Android 10.0 滑动解锁流程(下)

简介: Android 10.0 滑动解锁流程(下)

接着看 PanelViewController#notifyBarPanelExpansionChanged()

这里注意:都是到 KeyguardSecurityContainer#KeyguardSecurityContainer(),滑动解锁与带有密码安全界面,即密码解锁,两个流程的代码执行顺序有差异。

// PanelViewController.java
    protected void notifyBarPanelExpansionChanged() {
        if (mBar != null) {
            mBar.panelExpansionChanged(
                    mExpandedFraction,
                    mExpandedFraction > 0f || mPeekAnimator != null || mInstantExpanding
                            || isPanelVisibleBecauseOfHeadsUp() || mTracking
                            || mHeightAnimator != null);
        }
        for (int i = 0; i < mExpansionListeners.size(); i++) {
            mExpansionListeners.get(i).onPanelExpansionChanged(mExpandedFraction, mTracking);
        }
    }

再 notifyBarPanelExpansionChanged() 方法中继而调用 PanelBar 中的panelExpansionChanged方法:页面的透明度。

PanelBar#panelExpansionChanged()

// PanelBar.java
public void panelExpansionChanged(float frac, boolean expanded) {
        if (isNaN(frac)) {
            throw new IllegalArgumentException("frac cannot be NaN");
        }
        boolean fullyClosed = true;
        boolean fullyOpened = false;
        if (SPEW) LOG("panelExpansionChanged: start state=%d", mState);
        PanelViewController pv = mPanel;
        mExpanded = expanded;
        mPanelFraction = frac;
        updateVisibility();
        // 调整可能部分可见的任何其他面板
        if (expanded) {
            if (mState == STATE_CLOSED) {
                go(STATE_OPENING);
                onPanelPeeked();
            }
            fullyClosed = false;
            final float thisFrac = pv.getExpandedFraction();
            if (SPEW) LOG("panelExpansionChanged:  -> %s: f=%.1f", pv.getName(), thisFrac);
            fullyOpened = thisFrac >= 1f;
        }
        // fullyOpened 完全打开;就是:锁屏界面是否完全展开的;(手指不滑动时,fullyOpened  = true,fullyClosed = false;)
        // fullyClosed 完全关闭,就是:锁屏界面是否完全折叠,即消失了;(锁屏界面上滑消失时,fullyOpened = false,fullyClosed  = true)
       // 手指在滑动过程中时:fullyOpened = false,fullyClosed  = false
        if (fullyOpened && !mTracking) {
            go(STATE_OPEN);
            onPanelFullyOpened();
        } else if (fullyClosed && !mTracking && mState != STATE_CLOSED) {
            go(STATE_CLOSED);
            // 面板折叠时
            onPanelCollapsed();
        }
        if (SPEW) LOG("panelExpansionChanged: end state=%d [%s%s ]", mState,
                fullyOpened?" fullyOpened":"", fullyClosed?" fullyClosed":"");
    }

当锁屏页面完全消失时,调用 onPanelCollapsed() 方法,执行 post() 方法。

PhoneStatusBarView#onPanelCollapsed()

@Override
    public void onPanelCollapsed() {
        super.onPanelCollapsed();
        // Close the status bar in the next frame so we can show the end of the animation.
        post(mHideExpandedRunnable);
        mIsFullyOpenedPanel = false;
    }
    private Runnable mHideExpandedRunnable = new Runnable() {
        @Override
        public void run() {
            if (mPanelFraction == 0.0f) {
                mBar.makeExpandedInvisible();
            }
        }
    };

接下来执行 StatusBar 中的 makeExpandedInvisible() 方法,更新通知栏和状态栏窗口的可见性。

StatusBar#makeExpandedInvisible()

// StatusBar.java
  void makeExpandedInvisible() {
        if (SPEW) Log.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible
                + " mExpandedVisible=" + mExpandedVisible);
        if (!mExpandedVisible || mNotificationShadeWindowView == null) {
            return;
        }
        // 确保面板完全折叠
        mStatusBarView.collapsePanel(/*animate=*/ false, false /* delayed*/,
                1.0f /* speedUpFactor */);
        mNotificationPanelViewController.closeQs();
        mExpandedVisible = false;
        visibilityChanged(false);
        // 更新通知阴影和状态栏窗口的可见性
        mNotificationShadeWindowController.setPanelVisible(false);
        mStatusBarWindowController.setForceStatusBarVisible(false);
        // Close any guts that might be visible
        mGutsManager.closeAndSaveGuts(true /* removeLeavebehind */, true /* force */,
                true /* removeControls */, -1 /* x */, -1 /* y */, true /* resetMenu */);
        mShadeController.runPostCollapseRunnables();
        setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
        if (!mNotificationActivityStarter.isCollapsingToShowActivityOverLockscreen()) {
            showBouncerIfKeyguard();
        } else if (DEBUG) {
            Log.d(TAG, "Not showing bouncer due to activity showing over lockscreen");
        }
        mCommandQueue.recomputeDisableFlags(
                mDisplayId,
                mNotificationPanelViewController.hideStatusBarIconsWhenExpanded() /* animate */);
        // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
        // the bouncer appear animation.
        if (!mStatusBarKeyguardViewManager.isShowing()) {
            WindowManagerGlobal.getInstance().trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
        }
    }

StatusBar#showBouncerIfKeyguard()

// StatusBar.java
    private void showBouncerIfKeyguard() {
        if ((mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)
                && !mKeyguardViewMediator.isHiding()) {
            // !mKeyguardViewMediator.isHiding() 不管是滑动解锁还是PIN码解锁等方式都是 true
            mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */);
        }
    }

StatusBarKeyguardViewManager#showBouncer()

// StatusBarKeyguardViewManager.java
    public void showBouncer(boolean scrimmed) {
        // 如果是滑动解锁,这里 if 条件是 true,如果是密码解锁,这里是 false。
        if (mShowing && !mBouncer.isShowing()) {
            mBouncer.show(false /* resetSecuritySelection */, scrimmed);
        }
        updateStates();
    }

KeyguardBouncer#show() 如果有设置密码,则显示安全锁界面

// KeyguardBouncer.java
public void show(boolean resetSecuritySelection, boolean isScrimmed) {
        final int keyguardUserId = KeyguardUpdateMonitor.getCurrentUser();
        if (keyguardUserId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser()) {
            // In split system user mode, we never unlock system user.
            return;
        }
        ensureView();
        mIsScrimmed = isScrimmed;
        if (isScrimmed) {
            setExpansion(EXPANSION_VISIBLE);
        }
        if (resetSecuritySelection) {
            showPrimarySecurityScreen();
        }
        if (mRoot.getVisibility() == View.VISIBLE || mShowingSoon) {
            return;
        }
        final int activeUserId = KeyguardUpdateMonitor.getCurrentUser();
        final boolean isSystemUser =
                UserManager.isSplitSystemUser() && activeUserId == UserHandle.USER_SYSTEM;
        final boolean allowDismissKeyguard = !isSystemUser && activeUserId == keyguardUserId;
        // 重点关注 dismiss()
        if (allowDismissKeyguard && mKeyguardView.dismiss(activeUserId)) {
            return;
        }
        if (!allowDismissKeyguard) {
            Log.w(TAG, "User can't dismiss keyguard: " + activeUserId + " != " + keyguardUserId);
        }
        mShowingSoon = true;
        // Split up the work over multiple frames.
        DejankUtils.removeCallbacks(mResetRunnable);
        if (mKeyguardStateController.isFaceAuthEnabled() && !needsFullscreenBouncer()
                && !mKeyguardUpdateMonitor.userNeedsStrongAuth()
                && !mKeyguardBypassController.getBypassEnabled()) {
            mHandler.postDelayed(mShowRunnable, BOUNCER_FACE_DELAY);
        } else {
            DejankUtils.postAfterTraversal(mShowRunnable);
        }
        // 安全锁设置可见性
        mCallback.onBouncerVisiblityChanged(true /* shown */);
        // 开始显示
        mExpansionCallback.onStartingToShow();
    }

这里重点关注 mKeyguardView.dismiss(activeUserId) ;

KeyguardHostView#dismiss()

// KeyguardHostView.java
    // 显示安全锁
    public boolean dismiss(int targetUserId) {
        return dismiss(false, targetUserId, false);
    }
    @Override
    public boolean dismiss(boolean authenticated, int targetUserId,
            boolean bypassSecondaryLockScreen) {
        // 重点关注
        return mSecurityContainer.showNextSecurityScreenOrFinish(authenticated, targetUserId,
                bypassSecondaryLockScreen);
    }

KeyguardSecurityContainer#showNextSecurityScreenOrFinish()

// KeyguardSecurityContainer.java
    // 显示下一个安全屏幕(如果有)
    boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId,
            boolean bypassSecondaryLockScreen) {
        if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
        boolean finish = false;
        boolean strongAuth = false;
        int eventSubtype = -1;
        int unLockMode = 0;// add for KFCAANWIKFRA-833
        BouncerUiEvent uiEvent = BouncerUiEvent.UNKNOWN;
        if (mUpdateMonitor.getUserHasTrust(targetUserId)) {
           // 省略部分代码......
        } else if (mUpdateMonitor.getUserUnlockedWithBiometric(targetUserId)) {
           // 省略部分代码......
        } else if (SecurityMode.None == mCurrentSecuritySelection) {  // mCurrentSecuritySelection当前安全选择的模式
            SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
            if (SecurityMode.None == securityMode) {
                unLockMode = 0;
                finish = true; // 没有安全锁
                eventSubtype = BOUNCER_DISMISS_NONE_SECURITY;
                uiEvent = BouncerUiEvent.BOUNCER_DISMISS_NONE_SECURITY;
            } else {
                showSecurityScreen(securityMode); // switch to the alternate security view
            }
        } else if (authenticated) {
            // mCurrentSecuritySelection 当前锁的模式
            switch (mCurrentSecuritySelection) {
                case Pattern:
                case Password:
                case PIN:
                    unLockMode = mCurrentSecuritySelection.ordinal() - 1;
                    strongAuth = true;
                    finish = true;
                    eventSubtype = BOUNCER_DISMISS_PASSWORD;
                    uiEvent = BouncerUiEvent.BOUNCER_DISMISS_PASSWORD;
                    break;
                // 省略部分代码......
                default:
                    Log.v(TAG, "Bad security screen " + mCurrentSecuritySelection + ", fail safe");
                    showPrimarySecurityScreen(false);
                    break;
            }
        }
        // 检查设备管理员指定的其他安全措施。
        /* UNISOC: Modify for bug1394148 @{ */
        Intent secondaryLockscreenIntent =
                mUpdateMonitor.getSecondaryLockscreenRequirement(targetUserId);
        if (finish && !bypassSecondaryLockScreen && secondaryLockscreenIntent != null) {
            mSecondaryLockScreenController.show(secondaryLockscreenIntent);
            return false;
        }
        /* @} */
        if (eventSubtype != -1) {
            mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER)
                    .setType(MetricsEvent.TYPE_DISMISS).setSubtype(eventSubtype));
        }
        if (uiEvent != BouncerUiEvent.UNKNOWN) {
            sUiEventLogger.log(uiEvent);
        }
        // finish 是否还有一个安全屏幕,即是否解锁完成,有则返回 false,没有返回 true
        if (finish) {
            // 重点关注
            mSecurityCallback.finish(strongAuth, targetUserId);
            // 省略部分代码......
        }
        return finish;
    }

KeyguardHostView#finish()

// KeyguardHostView.java
    @Override
    public void finish(boolean strongAuth, int targetUserId) {
        // If there's a pending runnable because the user interacted with a widget
        // and we're leaving keyguard, then run it.
        boolean deferKeyguardDone = false;
        if (mDismissAction != null) {
            deferKeyguardDone = mDismissAction.onDismiss();
            mDismissAction = null;
            mCancelAction = null;
        }
        if (mViewMediatorCallback != null) {
            if (deferKeyguardDone) {    // deferKeyguardDone 上面设置成了 false
                mViewMediatorCallback.keyguardDonePending(strongAuth, targetUserId);
            } else {
                // 重点关注
                mViewMediatorCallback.keyguardDone(strongAuth, targetUserId);
            }
        }
    }

KeyguardViewMediator#keyguardDone()

// KeyguardViewMediator.java
        @Override
        public void keyguardDone(boolean strongAuth, int targetUserId) {
            if (targetUserId != ActivityManager.getCurrentUser()) {
                return;
            }
            if (DEBUG) Log.d(TAG, "keyguardDone");
            tryKeyguardDone();
        }
    private void tryKeyguardDone() {
        if (DEBUG) {
            Log.d(TAG, "tryKeyguardDone: pending - " + mKeyguardDonePending + ", animRan - "
                    + mHideAnimationRun + " animRunning - " + mHideAnimationRunning);
        }
        if (!mKeyguardDonePending && mHideAnimationRun && !mHideAnimationRunning) {
            handleKeyguardDone();
        } else if (!mHideAnimationRun) {
            if (DEBUG) Log.d(TAG, "tryKeyguardDone: starting pre-hide animation");
            mHideAnimationRun = true;
            mHideAnimationRunning = true;
            mKeyguardViewControllerLazy.get()
                    .startPreHideAnimation(mHideAnimationFinishedRunnable);    // 启动预隐藏动画
        }
    }


相关文章
|
15天前
|
Android开发
Android面试之Activity启动流程简述
Android面试之Activity启动流程简述
66 6
|
14天前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
|
16天前
|
消息中间件 Android开发 索引
Android面试高频知识点(4) 详解Activity的启动流程
Android面试高频知识点(4) 详解Activity的启动流程
22 3
|
17天前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
19 2
|
30天前
|
XML 前端开发 Android开发
Android View的绘制流程和原理详细解说
Android View的绘制流程和原理详细解说
33 3
|
16天前
|
Android开发
Android面试之Activity启动流程简述
Android面试之Activity启动流程简述
13 0
|
2月前
|
消息中间件 Android开发 索引
Android面试高频知识点(4) 详解Activity的启动流程
讲解Activity的启动流程了,Activity的启动流程相对复杂一下,涉及到了Activity中的生命周期方法,涉及到了Android体系的CS模式,涉及到了Android中进程通讯Binder机制等等, 首先介绍一下Activity,这里引用一下Android guide中对Activity的介绍:
49 4
|
2月前
|
Android开发 开发者
Android面试之Activity启动流程简述
每个Android开发者都熟悉的Activity,但你是否了解它的启动流程呢?本文将带你深入了解。启动流程涉及四个关键角色:Launcher进程、SystemServer的AMS、应用程序的ActivityThread及Zygote进程。核心在于AMS与ActivityThread间的通信。文章详细解析了从Launcher启动Activity的过程,包括通过AIDL获取AMS、Zygote进程启动以及ActivityThread与AMS的通信机制。接着介绍了如何创建Application及Activity的具体步骤。整体流程清晰明了,帮助你更深入理解Activity的工作原理。
46 0
|
3月前
|
Android开发
我的Android进阶修炼:安卓启动流程之init(1)
本文深入分析了Android系统中的init进程,包括其源码结构、主要功能以及启动流程的详细注解,旨在帮助读者理解init作为用户空间的1号进程在Android启动过程中的关键作用。
56 1
|
2月前
|
图形学 iOS开发 Android开发
从Unity开发到移动平台制胜攻略:全面解析iOS与Android应用发布流程,助你轻松掌握跨平台发布技巧,打造爆款手游不是梦——性能优化、广告集成与内购设置全包含
【8月更文挑战第31天】本书详细介绍了如何在Unity中设置项目以适应移动设备,涵盖性能优化、集成广告及内购功能等关键步骤。通过具体示例和代码片段,指导读者完成iOS和Android应用的打包与发布,确保应用顺利上线并获得成功。无论是性能调整还是平台特定的操作,本书均提供了全面的解决方案。
147 0