AndroidQ 上滑解锁时锁屏退出与Window切换的源码分析

AndroidQ 上滑解锁时锁屏退出与Window切换的源码分析

 

锁屏界面时,touch事件触发界面上滑的动作此处就不再分析,网上已经有很多详细的信息供大家观看,本文主要分析上滑解锁后锁屏Window切换退出过程等.

 

(1)PanelBar扩展完全关闭,通知StatusBar面板消失

notifyBarPanelExpansionChanged(PanelView.java)

==>panelExpansionChanged(PhoneStatusBarView.java)

==>onPanelCollapsed(PhoneStatusBarView.java)

==>mHideExpandedRunnable(PhoneStatusBarView.java)

==>makeExpandedInvisible(StatusBar.java)

 

StatusBar.java makeExpandedInvisible主要动作是处理掉需要关闭的界面如通知界面、快捷设置界面,状态栏显示调整

    void makeExpandedInvisible() {
        if (!mExpandedVisible || mStatusBarWindow == null) {
            return;
        }

        // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868)
        mStatusBarView.collapsePanel(/*animate=*/ false, false /* delayed*/,
                1.0f /* speedUpFactor */);

        mNotificationPanel.closeQs();

        mExpandedVisible = false;
        visibilityChanged(false);

        // Shrink the window to the size of the status bar only
        mStatusBarWindowController.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 */);

        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, mNotificationPanel.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 WindowManager.LayoutParams 的焦点,但是由于此时锁屏还处于显示阶段,其高度还不会发生变化(mStatusBarWindowController.setPanelVisible,

mStatusBarWindowController.setForceStatusBarVisible)

继续追踪解锁流程

showBouncerIfKeyguard(StatusBar.java)
==>showBouncer(StatusBar.java)
==>showBouncer(StatusBarKeyguardViewManager.java)
==>show(KeyguardBouncer.java 此时无安全锁界面 dismiss)
==>dismiss(KeyguardBouncer.java)
==>dismiss(KeyguardHostView.java)
==>showNextSecurityScreenOrFinish(KeyguardSecurityContainer.java)
==>finish(KeyguardSecurityContainer.java#SecurityCallback)
==>finish(KeyguardHostView.java)
==>keyguardDone(KeyguardViewMediator.java ViewMediatorCallback)
==>tryKeyguardDone(KeyguardViewMediator.java)
==>handleKeyguardDone(KeyguardViewMediator.java)

 

(2)SystemUI解锁开始,先通知系统要开始解锁了

handleKeyguardDone(KeyguardViewMediator.java)

==>handleHide(KeyguardViewMediator.java)

 

KeyguardViewMediator.java handleHide从代码看,此处会根据锁屏界面是否是前台显示而走不同的界面.

    private void handleHide() {

        // It's possible that the device was unlocked in a dream state. It's time to wake up.
        if (mAodShowing) {
            PowerManager pm = mContext.getSystemService(PowerManager.class);
            pm.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
                    "com.android.systemui:BOUNCER_DOZING");
        }

        synchronized (KeyguardViewMediator.this) {
            if (mustNotUnlockCurrentUser()) {
                // In split system user mode, we never unlock system user. The end user has to
                // switch to another user.
                // TODO: We should stop it early by disabling the swipe up flow. Right now swipe up
                // still completes and makes the screen blank.
                if (DEBUG) Log.d(TAG, "Split system user, quit unlocking.");
                return;
            }
            mHiding = true;

            if (mShowing && !mOccluded) {
                mKeyguardGoingAwayRunnable.run();
            } else {
                handleStartKeyguardExitAnimation(
                        SystemClock.uptimeMillis() + mHideAnimation.getStartOffset(),
                        mHideAnimation.getDuration());
            }
        }
    }

以上有此处需要分析的为 mKeyguardGoingAwayRunnablehandleStartKeyguardExitAnimation,既然我们是分析的是上滑解锁,那么直接走mKeyguardGoingAwayRunnable(handleStartKeyguardExitAnimation函数在后面也会用到的).

KeyguardViewMediator.java  mKeyguardGoingAwayRunnable

    private final Runnable mKeyguardGoingAwayRunnable = new Runnable() {
        @Override
        public void run() {
            mStatusBarKeyguardViewManager.keyguardGoingAway();

            int flags = 0;
            if (mStatusBarKeyguardViewManager.shouldDisableWindowAnimationsForUnlock()
                    || (mWakeAndUnlocking && !mPulsing)) {
                flags |= WindowManagerPolicyConstants
                        .KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
            }
            if (mStatusBarKeyguardViewManager.isGoingToNotificationShade()
                    || (mWakeAndUnlocking && mPulsing)) {
                flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
            }
            if (mStatusBarKeyguardViewManager.isUnlockWithWallpaper()) {
                flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
            }

            mUpdateMonitor.setKeyguardGoingAway(true /* goingAway */);

            // Don't actually hide the Keyguard at the moment, wait for window
            // manager until it tells us it's safe to do so with
            // startKeyguardExitAnimation.
            // Posting to mUiOffloadThread to ensure that calls to ActivityTaskManager will be in
            // order.
            final int keyguardFlag = flags;
            mUiOffloadThread.submit(() -> {
                try {
                    ActivityTaskManager.getService().keyguardGoingAway(keyguardFlag);
                } catch (RemoteException e) {
                    Log.e(TAG, "Error while calling WindowManager", e);
                }
            });
            Trace.endSection();
        }
    };

(a) 通知自己锁屏很快就会消失,通知应用程序转换挂起

keyguardGoingAway(StatusBarKeyguardViewManager.java)

==>keyguardGoingAway(StatusBar.java 将键盘锁退出动画视为应用程序转换,以实现状态栏的良好转换)

    /**
     * Notifies the status bar that Keyguard is going away very soon.
     */
    public void keyguardGoingAway() {
        // Treat Keyguard exit animation as an app transition to achieve nice transition for status
        // bar.
        mKeyguardMonitor.notifyKeyguardGoingAway(true);
        mCommandQueue.appTransitionPending(mDisplayId, true /* forced */);
    }

(b) 通知自己锁屏很快就会消失,通知系统WMS开始解锁操作

通过ActivityTaskManager.getService().keyguardGoingAway(keyguardFlag),传递到frameworks system_service

 

(3)系统开始做解锁准备

keyguardGoingAway(ActivityTaskManager.java IActivityTaskManager.aidl)

==>keyguardGoingAway(ActivityTaskManagerService.java)

==>keyguardGoingAway(KeyguardController.java)

KeyguardController.java keyguardGoingAway 此时会推迟窗口布局操作并开始做锁屏消失前的准备.

    /**
     * Called when Keyguard is going away.
     *
     * @param flags See {@link WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
     *              etc.
     */
    void keyguardGoingAway(int flags) {
        if (!mKeyguardShowing) {
            return;
        }
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway");
        mWindowManager.deferSurfaceLayout();
        try {
            setKeyguardGoingAway(true);
            mRootActivityContainer.getDefaultDisplay().mDisplayContent
                    .prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
                            false /* alwaysKeepCurrent */, convertTransitFlags(flags),
                            false /* forceOverride */);
            updateKeyguardSleepToken();

            // Some stack visibility might change (e.g. docked stack)
            mRootActivityContainer.resumeFocusedStacksTopActivities();
            mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
            mRootActivityContainer.addStartingWindowsForVisibleActivities(
                    true /* taskSwitch */);
            mWindowManager.executeAppTransition();
        } finally {
            Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway: surfaceLayout");
            mWindowManager.continueSurfaceLayout();
            Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);

            Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
        }
    }

(a)准备应用程序转换

prepareAppTransition(DisplayContent.java)

==>prepareAppTransitionLocked(AppTransition.java 更新自身状态,为即将到来的切换做准备)

==>setAppTransition(AppTransition.java)

==>setLastAppTransition(AppTransition.java)

    private void setAppTransition(int transit, int flags) {
        mNextAppTransition = transit;
        mNextAppTransitionFlags |= flags;
        setLastAppTransition(TRANSIT_UNSET, null, null, null);
        updateBooster();//改变进程优先级,准备加速运行
    }

    void setLastAppTransition(int transit, AppWindowToken openingApp, AppWindowToken closingApp,
            AppWindowToken changingApp) {
        mLastUsedAppTransition = transit;
        mLastOpeningApp = "" + openingApp;
        mLastClosingApp = "" + closingApp;
        mLastChangingApp = "" + changingApp;
    }

(b)更新锁屏睡眠功能

    private void updateKeyguardSleepToken() {
        for (int displayNdx = mRootActivityContainer.getChildCount() - 1;
             displayNdx >= 0; displayNdx--) {
            final ActivityDisplay display = mRootActivityContainer.getChildAt(displayNdx);
            updateKeyguardSleepToken(display.mDisplayId);
        }
    }

    private void updateKeyguardSleepToken(int displayId) {
        final KeyguardDisplayState state = getDisplay(displayId);
        if (isKeyguardUnoccludedOrAodShowing(displayId) && state.mSleepToken == null) {
            state.acquiredSleepToken();
        } else if (!isKeyguardUnoccludedOrAodShowing(displayId) && state.mSleepToken != null) {
            state.releaseSleepToken();
        }
    }

    private KeyguardDisplayState getDisplay(int displayId) {
        KeyguardDisplayState state = mDisplayStates.get(displayId);
        if (state == null) {
            state = new KeyguardDisplayState(mService, displayId);
            mDisplayStates.append(displayId, state);
        }
        return state;
    }

(c)重置activity堆栈的可见性

resumeFocusedStacksTopActivities(RootActivityContainer.java)

ensureActivitiesVisible(RootActivityContainer.java)

addStartingWindowsForVisibleActivities(RootActivityContainer.java)

(d)开始应用转换

executeAppTransition(WindowManagerService.java)

==>executeAppTransition(DisplayContent.java)

    void executeAppTransition() {
        if (mAppTransition.isTransitionSet()) {
            if (DEBUG_APP_TRANSITIONS) {
                Slog.w(TAG_WM, "Execute app transition: " + mAppTransition + ", displayId: "
                        + mDisplayId + " Callers=" + Debug.getCallers(5));
            }
            mAppTransition.setReady();
            mWmService.mWindowPlacerLocked.requestTraversal();
        }
    }

setReady(AppTransition.java)

requestTraversal(WindowManagerService.java)

==>requestTraversal(WindowSurfacePlacer.java)

==>performSurfacePlacement(WindowSurfacePlacer.java)

==>performSurfacePlacementLoop(WindowSurfacePlacer.java)

==>performSurfacePlacement(RootWindowContainer.java)

==>performSurfacePlacementNoTrace(RootWindowContainer.java)

(e)系统准备好后,开始反馈至SystemUI

performSurfacePlacementNoTrace(RootWindowContainer.java)

==>checkAppTransitionReady(RootWindowContainer.java)

==>handleAppTransitionReady(AppTransitionController.java)

==>goodToGo(AppTransition.java)

==>notifyAppTransitionStartingLocked(AppTransition.java)

==>onAppTransitionStartingLocked(PhoneWindowManager.java)

==>handleStartTransitionForKeyguardLw(PhoneWindowManager.java)

==>startKeyguardExitAnimation(PhoneWindowManager.java)

==>startKeyguardExitAnimation(KeyguardServiceDelegate.java)

==>startKeyguardExitAnimation(KeyguardServiceWrapper.java)

==>startKeyguardExitAnimation(IKeyguardService.aidl)

此时系统通过aidl通知SystemUI可以开始进行解锁动画了.

 

(4)SystemUI接收到系统的反馈,开始解锁动画

startKeyguardExitAnimation(KeyguardService.java)

==>startKeyguardExitAnimation(KeyguardViewMediator.java)

-->handleStartKeyguardExitAnimation(KeyguardViewMediator.java)

==>hide(StatusBarKeyguardViewManager.java)

==>hideKeyguard(StatusBar.java)

==>updateIsKeyguard(StatusBar.java)

==>hideKeyguardImpl(StatusBar.java)

StatusBar.java updateIsKeyguard函数开始更新锁屏,开始hideKeyguardImpl.

    /**
     * @return true if we would like to stay in the shade, false if it should go away entirely
     */
    public boolean hideKeyguardImpl() {
        mIsKeyguard = false;
        Trace.beginSection("StatusBar#hideKeyguard");
        boolean staying = mStatusBarStateController.leaveOpenOnKeyguardHide();
        if (!(mStatusBarStateController.setState(StatusBarState.SHADE))) {
            //TODO: StatusBarStateController should probably know about hiding the keyguard and
            // notify listeners.

            // If the state didn't change, we may still need to update public mode
            mLockscreenUserManager.updatePublicMode();
        }
        if (mStatusBarStateController.leaveOpenOnKeyguardHide()) {
            if (!mStatusBarStateController.isKeyguardRequested()) {
                mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
            }
            long delay = mKeyguardMonitor.calculateGoingToFullShadeDelay();
            mNotificationPanel.animateToFullShade(delay);
            if (mDraggedDownEntry != null) {
                mDraggedDownEntry.setUserLocked(false);
                mDraggedDownEntry = null;
            }

            // Disable layout transitions in navbar for this transition because the load is just
            // too heavy for the CPU and GPU on any device.
            mNavigationBarController.disableAnimationsDuringHide(mDisplayId, delay);
        } else if (!mNotificationPanel.isCollapsing()) {
            instantCollapseNotificationPanel();
        }

        // Keyguard state has changed, but QS is not listening anymore. Make sure to update the tile
        // visibilities so next time we open the panel we know the correct height already.
        if (mQSPanel != null) {
            mQSPanel.refreshAllTiles();
        }
        mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
        releaseGestureWakeLock();
        mNotificationPanel.onAffordanceLaunchEnded();
        mNotificationPanel.animate().cancel();
        mNotificationPanel.setAlpha(1f);
        updateScrimController();
        Trace.endSection();
        return staying;
    }

(a)改变statusbar状态,开始锁屏壁纸结束动画等

setState(StatusBarStateControllerImpl.java)

==>onStateChanged(StatusBar.java)

==>updateMediaMetaData(StatusBarNotificationPresenter.java)

==>updateMediaMetaData(NotificationMediaManager.java 开始锁屏壁纸隐藏动画)

 

(b)开始折叠通知栏,更新通知条目状态,通知栏完全关闭后唤起打开虚拟按键等操作

instantCollapseNotificationPanel(StatusBar.java)

==>instantCollapse(PanelView.java)

==>setExpandedFraction(PanelView.java)

==>notifyBarPanelExpansionChanged(PanelView.java)

==>panelExpansionChanged(PhoneStatusBarView.java)

==>onPanelExpandedChange(NavigationBarView.java)

 

总结

 

  手指脱离触摸屏以致滑动事件结束后,SystemUI根据脱离时触摸事件的位置,速度等属性去设置一个新的滑动动画.当滑动动画结束PanelBar扩展面板完全收起时就进入了判断是否需要解锁的阶段.

  判断是否需要解锁时会检测各种安全锁是不是存在,安全锁是不是还没有解开,是否需要显示安全锁界面等等一系列操作.当检测完成,需要解锁并显示正常应用界面时,就需要与系统的WMS做交互,开始进行应用切换动画的准备阶段了(解锁完成到应用界面显示的过程还是需要一个流畅的动画的)

  系统接到解锁的命令后,开始重置顶端Actiivty,准备切换动画,更改线程优先级等切换前的准备动作,保证此后的切换能正常进行.

  系统开始解锁即应用切换开始后,因为SystemUI的锁屏是一个悬浮窗类型的窗口而非一个正常的Activity,这个时候就需要系统通知SystemUI去开始自己的解锁动画来配合应用的切换动画以保证界面切换的流程性.

  SystemUI接到的系统的退出命令时,会携带有应用切换动画的持续时间,而SystemUI就可以根据这个时间去设置自己的退出动画,如隐藏锁屏壁纸,适时的改变状态栏高度,更新通知栏上的通知状态变换,显示出虚拟按键等.

 

 

你可能感兴趣的:(android,源码)