1.简介
公司代码比较旧,导致restart以后,在开机后的锁屏界面上出现了白屏,就是通知栏后边那个白色的背景,所以整理下显示的流程,查找原因。
- 主要修改的就是2.10以及2.7也就是mQsExpandImmediate的值
2.NotificationPanelViewController.java
这个就是下拉状态栏的根布局,具体布局内容见上篇1.3小节里的status_bar_expanded.xml布局
2.1.expand
开机后进入锁屏界面,这个是要展开的,因为锁屏界面显示的东西也在这个容器里
scss
public void expand(boolean animate) {
//完全收缩状态或者正在收缩中
if (isFullyCollapsed() || isCollapsing()) {
mInstantExpanding = true;
mAnimateAfterExpanding = animate;
mUpdateFlingOnLayout = false;
abortAnimations();
if (mTracking) {
// The panel is expanded after this call.
onTrackingStopped(true /* expands */);
}
if (mExpanding) {
notifyExpandingFinished();
}
//见补充1,使面板可见
updatePanelExpansionAndVisibility();
// Wait for window manager to pickup the change, so we know the maximum height of the
// panel then.
this.mView.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (!mInstantExpanding) {
mView.getViewTreeObserver().removeOnGlobalLayoutListener(
this);
return;
}
if (mCentralSurfaces.getNotificationShadeWindowView()
.isVisibleToUser()) {
mView.getViewTreeObserver().removeOnGlobalLayoutListener(
this);
//走到这里会展开状态栏,if和else都是设置展开高度为panel最大值
if (mAnimateAfterExpanding) {
notifyExpandingStarted();
beginJankMonitoring();
fling(0 /* expand */);
} else {
mShadeHeightLogger.logFunctionCall("expand");
setExpandedFraction(1f);
}
mInstantExpanding = false;
}
}
});
// Make sure a layout really happens.
this.mView.requestLayout();
}
setListening(true);
}
>1.updatePanelExpansionAndVisibility
更新面板的可见性
typescript
public void updatePanelExpansionAndVisibility() {
//这个类里其实是调用了一堆回调处理的
mShadeExpansionStateManager.onPanelExpansionChanged(
mExpandedFraction, isExpanded(), mTracking, mExpansionDragDownAmountPx);
updateVisibility();
}
private void updateVisibility() {
mView.setVisibility(shouldPanelBeVisible() ? VISIBLE : INVISIBLE);
}
private boolean shouldPanelBeVisible() {
boolean headsUpVisible = mHeadsUpAnimatingAway || mHeadsUpPinnedMode;
return headsUpVisible || isExpanded() || mBouncerShowing;
}
public boolean isExpanded() {
return mExpandedFraction > 0f
|| mInstantExpanding
|| isPanelVisibleBecauseOfHeadsUp()
|| mTracking
|| mHeightAnimator != null
&& !mIsSpringBackAnimation;
}
>2.setExpandedFraction
arduino
public void setExpandedFraction(float frac) {
setExpandedHeight(getMaxPanelHeight() * frac);
}
>3.fling
scss
protected void fling(float vel, boolean expand, float collapseSpeedUpFactor,
boolean expandBecauseOfFalsing) {
float target = expand ? getMaxPanelHeight() : 0;
if (!expand) {
setIsClosing(true);
}
flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing);
}
>4.setExpandedHeight
arduino
void setExpandedHeight(float height) {
setExpandedHeightInternal(height);
}
2.2.setExpandedHeightInternal
scss
private void setExpandedHeightInternal(float h) {
//就是执行对应的run方法,完事刷新layout
mNotificationShadeWindowController.batchApplyWindowLayoutParams
(() -> {
if (mExpandLatencyTracking && h != 0f) {
DejankUtils.postAfterTraversal(
() -> mLatencyTracker.onActionEnd(LatencyTracker.ACTION_EXPAND_PANEL));
mExpandLatencyTracking = false;
}
float maxPanelHeight = getMaxPanelTransitionDistance();
if (mHeightAnimator == null) {
// Split shade has its own overscroll logic
if (mTracking && !mSplitShadeEnabled) {
float overExpansionPixels = Math.max(0, h - maxPanelHeight);
setOverExpansionInternal(overExpansionPixels, true /* isFromGesture */);
}
}
//计算出面板的展开高度
mExpandedHeight = Math.min(h, maxPanelHeight);
// If we are closing the panel and we are almost there due to a slow decelerating
// interpolator, abort the animation.
if (mExpandedHeight < 1f && mExpandedHeight != 0f && mClosing) {
mExpandedHeight = 0f;
if (mHeightAnimator != null) {
mHeightAnimator.end();
}
}
mExpansionDragDownAmountPx = h;
mExpandedFraction = Math.min(1f,
maxPanelHeight == 0 ? 0 : mExpandedHeight / maxPanelHeight);
mAmbientState.setExpansionFraction(mExpandedFraction);
//见2.3,更新面板高度
onHeightUpdated(mExpandedHeight);
updatePanelExpansionAndVisibility();
});
}
>batchApplyWindowLayoutParams
就是执行对应的run方法,完事刷新layout
scss
public void batchApplyWindowLayoutParams(Runnable scope) {
mDeferWindowLayoutParams++;
scope.run();
mDeferWindowLayoutParams--;
applyWindowLayoutParams();
}
csharp
private void applyWindowLayoutParams() {
if (mDeferWindowLayoutParams == 0 && mLp != null && mLp.copyFrom(mLpChanged) != 0) {
mWindowManager.updateViewLayout(mNotificationShadeView, mLp);
}
}
2.3.onHeightUpdated
scss
private void onHeightUpdated(float expandedHeight) {
if (!mQsExpanded || mQsExpandImmediate || mIsExpanding && mQsExpandedWhenExpandingStarted) {
// Updating the clock position will set the top padding which might
// trigger a new panel height and re-position the clock.
// This is a circular dependency and should be avoided, otherwise we'll have
// a stack overflow.
if (mStackScrollerMeasuringPass > 2) {
debugLog("Unstable notification panel height. Aborting.");
} else {
positionClockAndNotifications();
}
}
// Below is true when QS are expanded and we swipe up from the same bottom of panel to
// close the whole shade with one motion. Also this will be always true when closing
// split shade as there QS are always expanded so every collapsing motion is motion from
// expanded QS to closed panel
boolean collapsingShadeFromExpandedQs = mQsExpanded && !mQsTracking
&& mQsExpansionAnimator == null && !mQsExpansionFromOverscroll;
//主要是mQsExpandImmediate这个值决定的,具体见2.7
boolean goingBetweenClosedShadeAndExpandedQs =
mQsExpandImmediate || collapsingShadeFromExpandedQs;
// in split shade we react when HUN is visible only if shade height is over HUN start
// height - which means user is swiping down. Otherwise shade QS will either not show at all
// with HUN movement or it will blink when touching HUN initially
boolean qsShouldExpandWithHeadsUp = !mSplitShadeEnabled
|| (!mHeadsUpManager.isTrackingHeadsUp() || expandedHeight > mHeadsUpStartHeight);
//判断qs是否要展开,老代码就是mQsExpandImmediate状态不对,导致进入下边的if方法,修改了qs的高度
if (goingBetweenClosedShadeAndExpandedQs && qsShouldExpandWithHeadsUp) {
float qsExpansionFraction;
if (mSplitShadeEnabled) {
qsExpansionFraction = 1;
} else if (mKeyguardShowing) {
// On Keyguard, interpolate the QS expansion linearly to the panel expansion
qsExpansionFraction = expandedHeight / (getMaxPanelHeight());
} else {
// In Shade, interpolate linearly such that QS is closed whenever panel height is
// minimum QS expansion + minStackHeight
float panelHeightQsCollapsed =
mNotificationStackScrollLayoutController.getIntrinsicPadding()
+ mNotificationStackScrollLayoutController.getLayoutMinHeight();
float panelHeightQsExpanded = calculatePanelHeightQsExpanded();
qsExpansionFraction = (expandedHeight - panelHeightQsCollapsed)
/ (panelHeightQsExpanded - panelHeightQsCollapsed);
}
float targetHeight = mQsMinExpansionHeight
+ qsExpansionFraction * (mQsMaxExpansionHeight - mQsMinExpansionHeight);
//见 2.4,
setQsExpansionHeight(targetHeight);
}
//见2.5
updateExpandedHeight(expandedHeight);
//见补充1
updateHeader();
//见补充2
updateNotificationTranslucency();
//见补充4
updatePanelExpanded();
//见补充5
updateGestureExclusionRect();
if (DEBUG_DRAWABLE) {
mView.invalidate();
}
}
>1.updateHeader
scss
private void updateHeader() {
if (mBarState == KEYGUARD) {
mKeyguardStatusBarViewController.updateViewState();
}
//见2.6
updateQsExpansion();
}
>2.updateNotificationTranslucency
ini
private void updateNotificationTranslucency() {
if (mIsToLockscreenTransitionRunning) {
return;
}
float alpha = 1f;
if (mClosingWithAlphaFadeOut && !mExpandingFromHeadsUp
&& !mHeadsUpManager.hasPinnedHeadsUp()) {
//见补充3
alpha = getFadeoutAlpha();
}
if (mBarState == KEYGUARD && !mHintAnimationRunning
&& !mKeyguardBypassController.getBypassEnabled()) {
alpha *= mClockPositionResult.clockAlpha;
}
//设置通知栏容器的透明度
mNotificationStackScrollLayoutController.setAlpha(alpha);
}
>3.getFadeoutAlpha
ini
private float getFadeoutAlpha() {
float alpha;
if (mQsMinExpansionHeight == 0) {
//横屏模式或者锁屏下,透明度一直是1,也就是通知面板可见。
return 1.0f;
}
alpha = getExpandedHeight() / mQsMinExpansionHeight;
alpha = Math.max(0, Math.min(alpha, 1));
alpha = (float) Math.pow(alpha, 0.75);
return alpha;
}
mQsMinExpansionHeight的值,可以看到,在锁屏界面或者横屏模式下,一直是0
ini
private void updateQSMinHeight() {
float previousMin = mQsMinExpansionHeight;
if (mKeyguardShowing || mSplitShadeEnabled) {
mQsMinExpansionHeight = 0;
} else {
mQsMinExpansionHeight = mQs.getQsMinExpansionHeight();
}
if (mQsExpansionHeight == previousMin) {
mQsExpansionHeight = mQsMinExpansionHeight;
}
}
>4.updatePanelExpanded
更新面板状态
scss
private void updatePanelExpanded () {
//展开状态
boolean isExpanded = !isFullyCollapsed() || mExpectingSynthesizedDown;
if (mPanelExpanded != isExpanded) {
mPanelExpanded = isExpanded;
mShadeExpansionStateManager.onShadeExpansionFullyChanged(isExpanded);
if (!isExpanded && mQs != null && mQs.isCustomizing()) {
//非展开状态,关闭qs编辑页面
mQs.closeCustomizer();
}
}
}
>5.updateGestureExclusionRect
java
private void updateGestureExclusionRect() {
Rect exclusionRect = calculateGestureExclusionRect();
mView.setSystemGestureExclusionRects(exclusionRect.isEmpty() ? Collections.emptyList()
: Collections.singletonList(exclusionRect));
}
private Rect calculateGestureExclusionRect() {
Rect exclusionRect = null;
Region touchableRegion = mStatusBarTouchableRegionManager.calculateTouchableRegion();
if (isFullyCollapsed() && touchableRegion != null) {
// Note: The manager also calculates the non-pinned touchable region
exclusionRect = touchableRegion.getBounds();
}
return exclusionRect != null ? exclusionRect : EMPTY_RECT;
}
2.4.setQsExpansionHeight
修改qs展开高度
scss
void setQsExpansionHeight (float height) {
height = Math.min(Math.max(height, mQsMinExpansionHeight), mQsMaxExpansionHeight);
mQsFullyExpanded = height == mQsMaxExpansionHeight && mQsMaxExpansionHeight != 0;
boolean qsAnimatingAway = !mQsAnimatorExpand && mAnimatingQS;
if (height > mQsMinExpansionHeight && !mQsExpanded && !mStackScrollerOverscrolling
&& !mDozing && !qsAnimatingAway) {
setQsExpanded(true);
} else if (height <= mQsMinExpansionHeight && mQsExpanded) {
setQsExpanded(false);
}
//更新qs展开高度
mQsExpansionHeight = height;
updateQsExpansion();
requestScrollerTopPaddingUpdate(false /* animate */);
mKeyguardStatusBarViewController.updateViewState();
if (mBarState == StatusBarState.SHADE_LOCKED || mBarState == KEYGUARD) {
//锁屏页面手指往下滑,可以看到底部透明度改变,以及左侧的clock位置移动
updateKeyguardBottomAreaAlpha();
positionClockAndNotifications();
}
if (mAccessibilityManager.isEnabled()) {
mView.setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
}
if (!mFalsingManager.isUnlockingDisabled() && mQsFullyExpanded
&& mFalsingCollector.shouldEnforceBouncer()) {
mCentralSurfaces.executeRunnableDismissingKeyguard(null, null /* cancelAction */,
false /* dismissShade */, true /* afterKeyguardGone */, false /* deferred */);
}
if (DEBUG_DRAWABLE) {
mView.invalidate();
}
}
2.5.updateExpandedHeight
scss
private void updateExpandedHeight(float expandedHeight) {
if (mTracking) {
mNotificationStackScrollLayoutController
.setExpandingVelocity(getCurrentExpandVelocity());
}
if (mKeyguardBypassController.getBypassEnabled() && isOnKeyguard()) {
// The expandedHeight is always the full panel Height when bypassing
expandedHeight = getMaxPanelHeight();
}
mNotificationStackScrollLayoutController.setExpandedHeight(expandedHeight);
updateKeyguardBottomAreaAlpha();
updateStatusBarIcons();
}
2.6.updateQsExpansion
更新qs的展开状态
scss
private void updateQsExpansion() {
if (mQs == null) return;
final float squishiness;
if ((mQsExpandImmediate || mQsExpanded) && !mSplitShadeEnabled) {
squishiness = 1;
} else if (mTransitioningToFullShadeProgress > 0.0f) {
squishiness = mLockscreenShadeTransitionController.getQsSquishTransitionFraction();
} else {
squishiness = mNotificationStackScrollLayoutController
.getNotificationSquishinessFraction();
}
//计算qs展开比例
final float qsExpansionFraction = computeQsExpansionFraction();
final float adjustedExpansionFraction = mSplitShadeEnabled
? 1f : computeQsExpansionFraction();
mQs.setQsExpansion(adjustedExpansionFraction, getExpandedFraction(), getHeaderTranslation(),
squishiness);
mMediaHierarchyManager.setQsExpansion(qsExpansionFraction);
int qsPanelBottomY = calculateQsBottomPosition(qsExpansionFraction);
//这里修改scrim的状态
mScrimController.setQsPosition(qsExpansionFraction, qsPanelBottomY);
setQSClippingBounds();
if (mSplitShadeEnabled) {
// In split shade we want to pretend that QS are always collapsed so their behaviour and
// interactions don't influence notifications as they do in portrait. But we want to set
// 0 explicitly in case we're rotating from non-split shade with QS expansion of 1.
mNotificationStackScrollLayoutController.setQsExpansionFraction(0);
} else {
mNotificationStackScrollLayoutController.setQsExpansionFraction(qsExpansionFraction);
}
mDepthController.setQsPanelExpansion(qsExpansionFraction);
mStatusBarKeyguardViewManager.setQsExpansion(qsExpansionFraction);
float shadeExpandedFraction = isOnKeyguard()
? getLockscreenShadeDragProgress()
: getExpandedFraction();
mLargeScreenShadeHeaderController.setShadeExpandedFraction(shadeExpandedFraction);
mLargeScreenShadeHeaderController.setQsExpandedFraction(qsExpansionFraction);
mLargeScreenShadeHeaderController.setQsVisible(mQsVisible);
}
>1.computeQsExpansionFraction
csharp
private float computeQsExpansionFraction() {
if (mQSAnimatingHiddenFromCollapsed) {
// When hiding QS from collapsed state, the expansion can sometimes temporarily
// be larger than 0 because of the timing, leading to flickers.
return 0.0f;
}
return Math.min(
1f, (mQsExpansionHeight - mQsMinExpansionHeight) / (mQsMaxExpansionHeight
- mQsMinExpansionHeight));
}
2.7.mQsExpandImmediate
看下这个值是如何变化的
ini
void setQsExpandImmediate(boolean expandImmediate) {
if (expandImmediate != mQsExpandImmediate) {
mQsExpandImmediate = expandImmediate;
mShadeExpansionStateManager.notifyExpandImmediateChange(expandImmediate);
}
}
所有调用的地方
scss
//1=====//面板收缩,qs是展开状态,设置值为true
public void collapse(boolean delayed, float speedUpFactor) {
if (!canPanelBeCollapsed()) {
return;
}
if (mQsExpanded) {
setQsExpandImmediate(true);
setShowShelfOnly(true);
}
//2=====//面板关闭的时候,设置值为false
public void closeQs() {
cancelQsAnimation();
setQsExpansionHeight(mQsMinExpansionHeight);
// qsExpandImmediate is a safety latch in case we're calling closeQS while we're in the
// middle of animation - we need to make sure that value is always false when shade if
// fully collapsed or expanded
setQsExpandImmediate(false);
}
//3=====//展开面板带qs的时候,设置为true
public void expandWithQs() {
if (isQsExpansionEnabled()) {
setQsExpandImmediate(true);
setShowShelfOnly(true);
}
//4=====//qs的触摸事件,
private boolean handleQsTouch(MotionEvent event) {
if (mTwoFingerQsExpandPossible && isOpenQsEvent(event) && event.getY(event.getActionIndex())
< mStatusBarMinHeight) {
mMetricsLogger.count(COUNTER_PANEL_OPEN_QS, 1);
setQsExpandImmediate(true);
//5=====//面板展开完成的,修改值为false
private void onExpandingFinished() {
if (mBarState != SHADE) {
// updating qsExpandImmediate is done in onPanelStateChanged for unlocked shade but
// on keyguard panel state is always OPEN so we need to have that extra update
setQsExpandImmediate(false);
}
//6=========
private void onTrackingStarted() {
if (mQsFullyExpanded) {
setQsExpandImmediate(true);
setShowShelfOnly(true);
}
//7=====//面板状态改变的时候
private void onPanelStateChanged(@PanelState int state) {
updateQSExpansionEnabledAmbient();
if (state == STATE_OPEN && mCurrentPanelState != state) {
setQsExpandImmediate(false);
mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
}
if (state == STATE_OPENING) {
// we need to ignore it on keyguard as this is a false alarm - transition from unlocked
// to locked will trigger this event and we're not actually in the process of opening
// the shade, lockscreen is just always expanded
if (mSplitShadeEnabled && !isOnKeyguard()) {
setQsExpandImmediate(true);
}
mOpenCloseListener.onOpenStarted();
}
if (state == STATE_CLOSED) {
setQsExpandImmediate(false);
// Close the status bar in the next frame so we can show the end of the
// animation.
mView.post(mMaybeHideExpandedRunnable);
}
mCurrentPanelState = state;
}
>log
我们的代码比较旧,开机会走下边的方法,上边的7,state为STATE_OPENING ,设置为true以后,没有再被修改成false,导致qs展开异常。
- log的逻辑见小节3之后的代码
php
at com.android.systemui.statusbar.phone.NotificationPanelViewController.onPanelStateChanged(NotificationPanelViewController.java:5199)
at com.android.systemui.statusbar.phone.NotificationPanelViewController.$r8$lambda$b5I6ELTIP2he3Ex7kHWUxblpoU4(Unknown Source:0)
at com.android.systemui.statusbar.phone.NotificationPanelViewController$$ExternalSyntheticLambda15.onPanelStateChanged(Unknown Source:2)
at com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager.updateStateInternal(PanelExpansionStateManager.kt:138)
at com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager.onPanelExpansionChanged(PanelExpansionStateManager.kt:98)
at com.android.systemui.statusbar.phone.PanelViewController.updatePanelExpansionAndVisibility(PanelViewController.java:1147)
at com.android.systemui.statusbar.phone.PanelViewController.expand(PanelViewController.java:952)
at com.android.systemui.statusbar.phone.NotificationPanelViewController.expand(NotificationPanelViewController.java:3382)
at com.android.systemui.statusbar.phone.ShadeControllerImpl.instantExpandNotificationsPanel(ShadeControllerImpl.java:79)
at com.android.systemui.statusbar.phone.CentralSurfacesImpl.updatePanelExpansionForKeyguard(CentralSurfacesImpl.java:3016)
at com.android.systemui.statusbar.phone.CentralSurfacesImpl.showKeyguardImpl(CentralSurfacesImpl.java:3009)
at com.android.systemui.statusbar.phone.CentralSurfacesImpl.updateIsKeyguard(CentralSurfacesImpl.java:2980)
at com.android.systemui.statusbar.phone.CentralSurfacesImpl.updateIsKeyguard(CentralSurfacesImpl.java:2953)
at com.android.systemui.statusbar.phone.CentralSurfacesImpl.showKeyguard(CentralSurfacesImpl.java:2941)
at com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.showBouncerOrKeyguard(StatusBarKeyguardViewManager.java:446)
at com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.reset(StatusBarKeyguardViewManager.java:595)
at com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.show(StatusBarKeyguardViewManager.java:430)
at com.android.systemui.keyguard.KeyguardViewMediator.handleShow(KeyguardViewMediator.java:2322)
at com.android.systemui.keyguard.KeyguardViewMediator.-$$Nest$mhandleShow(Unknown Source:0)
at com.android.systemui.keyguard.KeyguardViewMediator$10.handleMessage(KeyguardViewMediator.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
2.8.ShadeLayoutChangeListener
构造方法里添加的监听,监听布局的改变
ini
mView.addOnLayoutChangeListener(new ShadeLayoutChangeListener());
mView.setOnTouchListener(createTouchHandler());
scss
private final class ShadeLayoutChangeListener implements View.OnLayoutChangeListener {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
int oldTop, int oldRight, int oldBottom) {
//见补充1,更新面板高度
updateExpandedHeightToMaxHeight();
mHasLayoutedSinceDown = true;
if (mUpdateFlingOnLayout) {
abortAnimations();
fling(mUpdateFlingVelocity);
mUpdateFlingOnLayout = false;
}
updateMaxDisplayedNotifications(!shouldAvoidChangingNotificationsCount());
//通知面板和容器宽度一样,竖屏模式为true,横屏就不是了
setIsFullWidth(mNotificationStackScrollLayoutController.getWidth() == mView.getWidth());
// Update Clock Pivot (used by anti-burnin transformations)
mKeyguardStatusViewController.updatePivot(mView.getWidth(), mView.getHeight());
// Calculate quick setting heights.
int oldMaxHeight = mQsMaxExpansionHeight;
if (mQs != null) {
//更新qs最小展开高度
updateQSMinHeight();
mQsMaxExpansionHeight = mQs.getDesiredHeight();
mNotificationStackScrollLayoutController.setMaxTopPadding(mQsMaxExpansionHeight);
}
//更新clock和通知的为主
positionClockAndNotifications();
if (mQsExpanded && mQsFullyExpanded) {
//qs是完全展开状态
mQsExpansionHeight = mQsMaxExpansionHeight;
requestScrollerTopPaddingUpdate(false /* animate */);
updateExpandedHeightToMaxHeight();
// Size has changed, start an animation.
if (mQsMaxExpansionHeight != oldMaxHeight) {
startQsSizeChangeAnimation(oldMaxHeight, mQsMaxExpansionHeight);
}
} else if (!mQsExpanded && mQsExpansionAnimator == null) {
setQsExpansionHeight(mQsMinExpansionHeight + mLastOverscroll);
} else {
mShadeLog.v("onLayoutChange: qs expansion not set");
}
updateExpandedHeight(getExpandedHeight());
updateHeader();
// If we are running a size change animation, the animation takes care of the height
// of the container. However, if we are not animating, we always need to make the QS
// container the desired height so when closing the QS detail, it stays smaller after
// the size change animation is finished but the detail view is still being animated
// away (this animation takes longer than the size change animation).
if (mQsSizeChangeAnimator == null && mQs != null) {
mQs.setHeightOverride(mQs.getDesiredHeight());
}
updateMaxHeadsUpTranslation();
updateGestureExclusionRect();
if (mExpandAfterLayoutRunnable != null) {
mExpandAfterLayoutRunnable.run();
mExpandAfterLayoutRunnable = null;
}
}
}
>1.updateExpandedHeightToMaxHeight
csharp
private void updateExpandedHeightToMaxHeight() {
//见补充2
float currentMaxPanelHeight = getMaxPanelHeight();
if (isFullyCollapsed()) {
//面板是完全收缩状态 mExpandedFraction <= 0.0f;
return;
}
if (currentMaxPanelHeight == mExpandedHeight) {
//高度未发生变化
return;
}
if (mTracking && !isTrackingBlocked()) {
//正在触摸滑动
return;
}
if (mHeightAnimator != null && !mIsSpringBackAnimation) {
//动画中
mPanelUpdateWhenAnimatorEnds = true;
return;
}
//最终走的2.2
setExpandedHeight(currentMaxPanelHeight);
}
>2.getMaxPanelHeight
获取面板最大高度
ini
int getMaxPanelHeight() {
//默认是状态栏高度
int min = mStatusBarMinHeight;
if (!(mBarState == KEYGUARD)
&& mNotificationStackScrollLayoutController.getNotGoneChildCount() == 0) {
//非锁屏界面并且通知数为0,取(qs最小展开高度和上边的min)最小值
int minHeight = mQsMinExpansionHeight;
min = Math.max(min, minHeight);
}
int maxHeight;
if (mQsExpandImmediate || mQsExpanded || mIsExpanding && mQsExpandedWhenExpandingStarted
|| mPulsing || mSplitShadeEnabled) {
maxHeight = calculatePanelHeightQsExpanded();
} else {
maxHeight = calculatePanelHeightShade();
}
maxHeight = Math.max(min, maxHeight);
return maxHeight;
}
2.9.resetViews
重置view状态,关闭qs,通知栏状态重置
typescript
public void resetViews(boolean animate) {
mGutsManager.closeAndSaveGuts(true /* leavebehind */, true /* force */,
true /* controls */, -1 /* x */, -1 /* y */, true /* resetMenu */);
if (animate && !isFullyCollapsed()) {
animateCloseQs(true /* animateAway */);
} else {
closeQs();
}
mNotificationStackScrollLayoutController.setOverScrollAmount(0f, true /* onTop */, animate,
!animate /* cancelAnimators */);
mNotificationStackScrollLayoutController.resetScrollPosition();
}
2.10.StatusBarStateListener
java
private final class StatusBarStateListener implements StateListener {
@Override
public void onStateChanged(int statusBarState) {
boolean goingToFullShade = mStatusBarStateController.goingToFullShade();
boolean keyguardFadingAway = mKeyguardStateController.isKeyguardFadingAway();
int oldState = mBarState;
boolean keyguardShowing = statusBarState == KEYGUARD;
if (mDozeParameters.shouldDelayKeyguardShow()
&& oldState == StatusBarState.SHADE
&& statusBarState == KEYGUARD) {
// This means we're doing the screen off animation - position the keyguard status
// view where it'll be on AOD, so we can animate it in.
mKeyguardStatusViewController.updatePosition(
mClockPositionResult.clockX,
mClockPositionResult.clockYFullyDozing,
mClockPositionResult.clockScale,
false /* animate */);
}
mKeyguardStatusViewController.setKeyguardStatusViewVisibility(
statusBarState,
keyguardFadingAway,
goingToFullShade,
mBarState);
setKeyguardBottomAreaVisibility(statusBarState, goingToFullShade);
mBarState = statusBarState;
mKeyguardShowing = keyguardShowing;
//旧代码没有下边的逻辑,在closeQs()方法也里会修改2.7的字段为false
boolean fromShadeToKeyguard = statusBarState == KEYGUARD
&& (oldState == SHADE || oldState == SHADE_LOCKED);
if (mSplitShadeEnabled && fromShadeToKeyguard) {
// user can go to keyguard from different shade states and closing animation
// may not fully run - we always want to make sure we close QS when that happens
// as we never need QS open in fresh keyguard state
closeQs();
}
3.KeyguardViewMediator.java
- 可以看到实现了CoreStartable,之前帖子讲过这个接口,SystemUi的服务启动的时候里边会查找所有这种接口,然后调用对应的start以及onBootCompleted方法
- 其他方法是小节4里实例化的对象调用的
kotlin
public class KeyguardViewMediator implements CoreStartable, Dumpable,
StatusBarStateController.StateListener {
注解实例化的
less
@Binds
@IntoMap
@ClassKey(KeyguardViewMediator::class)
abstract fun bindKeyguardViewMediator(sysui: KeyguardViewMediator): CoreStartable
3.1.start
csharp
public void start() {
synchronized (this) {
setupLocked();
}
}
>setupLocked
ini
private void setupLocked() {
mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard");
mShowKeyguardWakeLock.setReferenceCounted(false);
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SHUTDOWN);
mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter);
//注册广播监听
final IntentFilter delayedActionFilter = new IntentFilter();
delayedActionFilter.addAction(DELAYED_KEYGUARD_ACTION);
delayedActionFilter.addAction(DELAYED_LOCK_PROFILE_ACTION);
delayedActionFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
mContext.registerReceiver(mDelayedLockBroadcastReceiver, delayedActionFilter,
SYSTEMUI_PERMISSION, null /* scheduler */,
Context.RECEIVER_EXPORTED_UNAUDITED);
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
KeyguardUpdateMonitor.setCurrentUser(mUserTracker.getUserId());
// Assume keyguard is showing (unless it's disabled) until we know for sure, unless Keyguard
// is disabled.
//根据锁屏服务是否可用,决定是否显示keyguard
if (isKeyguardServiceEnabled()) {
setShowingLocked(!shouldWaitForProvisioning()
&& !mLockPatternUtils.isLockScreenDisabled(
KeyguardUpdateMonitor.getCurrentUser()), true /* forceCallbacks */);
} else {
// The system's keyguard is disabled or missing.
setShowingLocked(false /* showing */, true /* forceCallbacks */);
}
final ContentResolver cr = mContext.getContentResolver();
mDeviceInteractive = mPM.isInteractive();
mLockSounds = new SoundPool.Builder()
.setMaxStreams(1)
.setAudioAttributes(
new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build())
.build();
//锁屏声音的获取
String soundPath = Settings.Global.getString(cr, Settings.Global.LOCK_SOUND);
if (soundPath != null) {
mLockSoundId = mLockSounds.load(soundPath, 1);
}
if (soundPath == null || mLockSoundId == 0) {
Log.w(TAG, "failed to load lock sound from " + soundPath);
}
soundPath = Settings.Global.getString(cr, Settings.Global.UNLOCK_SOUND);
if (soundPath != null) {
mUnlockSoundId = mLockSounds.load(soundPath, 1);
}
if (soundPath == null || mUnlockSoundId == 0) {
Log.w(TAG, "failed to load unlock sound from " + soundPath);
}
soundPath = Settings.Global.getString(cr, Settings.Global.TRUSTED_SOUND);
if (soundPath != null) {
mTrustedSoundId = mLockSounds.load(soundPath, 1);
}
if (soundPath == null || mTrustedSoundId == 0) {
Log.w(TAG, "failed to load trusted sound from " + soundPath);
}
int lockSoundDefaultAttenuation = mContext.getResources().getInteger(
com.android.internal.R.integer.config_lockSoundVolumeDb);
mLockSoundVolume = (float)Math.pow(10, (float)lockSoundDefaultAttenuation/20);
mHideAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.lock_screen_behind_enter);
mWorkLockController = new WorkLockActivityController(mContext);
}
3.2.onBootCompleted
scss
public void onBootCompleted() {
synchronized (this) {
if (mContext.getResources().getBoolean(
com.android.internal.R.bool.config_guestUserAutoCreated)) {
//自动创建guest用户
mUserSwitcherController.schedulePostBootGuestCreation();
}
mBootCompleted = true;
//见补充1
adjustStatusBarLocked(false, true);
//这个值默认是false,需要执行过3.3的方法以后才会改为true
if (mBootSendUserPresent) {
//见3.3
sendUserPresentBroadcast();
}
}
}
>1.adjustStatusBarLocked
调整状态栏数据
ini
private void adjustStatusBarLocked(boolean forceHideHomeRecentsButtons,
boolean forceClearFlags) {
if (mStatusBarManager == null) {
mStatusBarManager = (StatusBarManager)
mContext.getSystemService(Context.STATUS_BAR_SERVICE);
}
if (mStatusBarManager == null) {
Log.w(TAG, "Could not get status bar manager");
} else {
int flags = StatusBarManager.DISABLE_NONE;
if (forceClearFlags) {
mStatusBarManager.disable(flags);
}
if (forceHideHomeRecentsButtons || isShowingAndNotOccluded()) {
if (!mShowHomeOverLockscreen || !mInGestureNavigationMode) {
flags |= StatusBarManager.DISABLE_HOME;
}
flags |= StatusBarManager.DISABLE_RECENT;
}
mStatusBarManager.disable(flags);
}
}
3.3.sendUserPresentBroadcast
发送USER_PRESENT广播
ini
private void sendUserPresentBroadcast() {
synchronized (this) {
if (mBootCompleted) {
//参考3.2可以知道,走这里需要bootComplte并且user present
int currentUserId = KeyguardUpdateMonitor.getCurrentUser();
final UserHandle currentUser = new UserHandle(currentUserId);
final UserManager um = (UserManager) mContext.getSystemService(
Context.USER_SERVICE);
mUiBgExecutor.execute(() -> {
for (int profileId : um.getProfileIdsWithDisabled(currentUser.getIdentifier())) {
//发送user present广播
mContext.sendBroadcastAsUser(USER_PRESENT_INTENT, UserHandle.of(profileId));
}
mLockPatternUtils.userPresent(currentUserId);
});
} else {
mBootSendUserPresent = true;
}
}
}
3.4.onSystemReady
这个方法里调用了显示keyguard的逻辑
scss
public void onSystemReady() {
mHandler.obtainMessage(SYSTEM_READY).sendToTarget();
}
//对应的handler方法
private void handleSystemReady() {
synchronized (this) {
mSystemReady = true;
//见3.5,显示keyguard
doKeyguardLocked(null);
mUpdateMonitor.registerCallback(mUpdateCallback);
adjustStatusBarLocked();
mDreamOverlayStateController.addCallback(mDreamOverlayStateCallback);
}
// Most services aren't available until the system reaches the ready state, so we
// send it here when the device first boots.
maybeSendUserPresentBroadcast();
}
3.5.doKeyguardLocked
java
private void doKeyguardLocked(Bundle options) {
if (KeyguardUpdateMonitor.CORE_APPS_ONLY) {
// Don't show keyguard during half-booted cryptkeeper stage.
return;
}
// if another app is disabling us, don't show
if (!mExternallyEnabled) {
//如果外部app不允许显示keyguard
mNeedToReshowWhenReenabled = true;
return;
}
// if the keyguard is already showing, don't bother. check flags in both files
// to account for the hiding animation which results in a delay and discrepancy
// between flags
if (mShowing && mKeyguardStateController.isShowing()) {
//已经在显示了
resetStateLocked();
return;
}
// In split system user mode, we never unlock system user.
if (!mustNotUnlockCurrentUser()
|| !mUpdateMonitor.isDeviceProvisioned()) {
// if the setup wizard hasn't run yet, don't show
final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim", false);
final boolean absent = SubscriptionManager.isValidSubscriptionId(
mUpdateMonitor.getNextSubIdForState(TelephonyManager.SIM_STATE_ABSENT));
final boolean disabled = SubscriptionManager.isValidSubscriptionId(
mUpdateMonitor.getNextSubIdForState(TelephonyManager.SIM_STATE_PERM_DISABLED));
final boolean lockedOrMissing = mUpdateMonitor.isSimPinSecure()
|| ((absent || disabled) && requireSim);
if (!lockedOrMissing && shouldWaitForProvisioning()) {
//设备未分配完成并且sim没有锁或者丢失
return;
}
boolean forceShow = options != null && options.getBoolean(OPTION_FORCE_SHOW, false);
if (mLockPatternUtils.isLockScreenDisabled(KeyguardUpdateMonitor.getCurrentUser())
&& !lockedOrMissing && !forceShow) {
//禁止锁屏并且不强制显示
return;
}
}
//显示keyguard,见3.6
showLocked(options);
}
3.6.showLocked
显示keyguard
scss
private void showLocked(Bundle options) {
// ensure we stay awake until we are finished displaying the keyguard
mShowKeyguardWakeLock.acquire();
Message msg = mHandler.obtainMessage(SHOW, options);
// Treat these messages with priority - This call can originate from #doKeyguardTimeout,
// meaning the device should lock as soon as possible and not wait for other messages on
// the thread to process first.
mHandler.sendMessageAtFrontOfQueue(msg);
}
>1.handleShow
handler最终调用这个方法处理
scss
private void handleShow(Bundle options) {
final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
if (mLockPatternUtils.isSecure(currentUser)) {
mLockPatternUtils.getDevicePolicyManager().reportKeyguardSecured(currentUser);
}
synchronized (KeyguardViewMediator.this) {
if (!mSystemReady) {
return;
}
mHiding = false;
mKeyguardExitAnimationRunner = null;
mWakeAndUnlocking = false;
setPendingLock(false);
setShowingLocked(true);
//这个就是StatusBarKeyguardViewManager
mKeyguardViewControllerLazy.get().show(options);
resetKeyguardDonePendingLocked();
mHideAnimationRun = false;
adjustStatusBarLocked();
userActivity();
mUpdateMonitor.setKeyguardGoingAway(false);
mKeyguardViewControllerLazy.get().setKeyguardGoingAwayState(false);
mShowKeyguardWakeLock.release();
}
mKeyguardDisplayManager.show();
// schedule 4hr idle timeout after which non-strong biometrics (i.e. weak or convenience
// biometric) can't be used to unlock device until unlocking with strong biometric or
// primary auth (i.e. PIN/pattern/password)
mLockPatternUtils.scheduleNonStrongBiometricIdleTimeout(
KeyguardUpdateMonitor.getCurrentUser());
Trace.endSection();
}
java
@Binds
abstract KeyguardViewController bindKeyguardViewController(
StatusBarKeyguardViewManager statusBarKeyguardViewManager);
4.KeyguardService.java
可以看到,也是注解实例化的,构造方法里有KeyguardViewMediator参数
ini
@Inject
public KeyguardService(KeyguardViewMediator keyguardViewMediator,
KeyguardLifecyclesDispatcher keyguardLifecyclesDispatcher,
ScreenOnCoordinator screenOnCoordinator,
ShellTransitions shellTransitions) {
super();
mKeyguardViewMediator = keyguardViewMediator;
mKeyguardLifecyclesDispatcher = keyguardLifecyclesDispatcher;
mScreenOnCoordinator = screenOnCoordinator;
mShellTransitions = shellTransitions;
}
4.1.mBinder
小节5.2里封装的mKeyguardService对象,里边调用的方法最终走的就是这里
java
private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() {
5.KeyguardServiceDelegate.java
这个对象是在小节6里实例化的,方法也都是在小节6里调用的
ini
public KeyguardServiceDelegate(Context context, KeyguardStateMonitor.StateCallback callback) {
mContext = context;
mHandler = UiThread.getHandler();
mCallback = callback;
}
5.1.bindService
ini
public void bindService(Context context) {
Intent intent = new Intent();
final Resources resources = context.getApplicationContext().getResources();
//配置里就是 KeyguardService
final ComponentName keyguardComponent = ComponentName.unflattenFromString(
resources.getString(com.android.internal.R.string.config_keyguardComponent));
intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
intent.setComponent(keyguardComponent);
if (!context.bindServiceAsUser(intent, mKeyguardConnection,
Context.BIND_AUTO_CREATE, mHandler, UserHandle.SYSTEM)) {
Log.v(TAG, "*** Keyguard: can't bind to " + keyguardComponent);
mKeyguardState.showing = false;
mKeyguardState.showingAndNotOccluded = false;
mKeyguardState.secure = false;
synchronized (mKeyguardState) {
// TODO: Fix synchronisation model in this class. The other state in this class
// is at least self-healing but a race condition here can lead to the scrim being
// stuck on keyguard-less devices.
mKeyguardState.deviceHasKeyguard = false;
}
}
}
5.2.mKeyguardConnection
这里封装了一个KeyguardServiceWrapper对象,里边通过aidl的逻辑,其实最终调用的就是4.1里的binder的方法
scss
private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//这里的service就是4.1里的binder了
mKeyguardService = new KeyguardServiceWrapper(mContext,
IKeyguardService.Stub.asInterface(service), mCallback);
if (mKeyguardState.systemIsReady) {
// If the system is ready, it means keyguard crashed and restarted.
mKeyguardService.onSystemReady();
if (mKeyguardState.currentUser != UserHandle.USER_NULL) {
// There has been a user switch earlier
mKeyguardService.setCurrentUser(mKeyguardState.currentUser);
}
// This is used to hide the scrim once keyguard displays.
if (mKeyguardState.interactiveState == INTERACTIVE_STATE_AWAKE
|| mKeyguardState.interactiveState == INTERACTIVE_STATE_WAKING) {
mKeyguardService.onStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN,
false /* cameraGestureTriggered */);
}
if (mKeyguardState.interactiveState == INTERACTIVE_STATE_AWAKE) {
mKeyguardService.onFinishedWakingUp();
}
if (mKeyguardState.screenState == SCREEN_STATE_ON
|| mKeyguardState.screenState == SCREEN_STATE_TURNING_ON) {
mKeyguardService.onScreenTurningOn(
new KeyguardShowDelegate(mDrawnListenerWhenConnect));
}
if (mKeyguardState.screenState == SCREEN_STATE_ON) {
mKeyguardService.onScreenTurnedOn();
}
mDrawnListenerWhenConnect = null;
}
if (mKeyguardState.bootCompleted) {
mKeyguardService.onBootCompleted();
}
if (mKeyguardState.occluded) {
mKeyguardService.setOccluded(mKeyguardState.occluded, false /* animate */);
}
if (!mKeyguardState.enabled) {
mKeyguardService.setKeyguardEnabled(mKeyguardState.enabled);
}
if (mKeyguardState.dreaming) {
mKeyguardService.onDreamingStarted();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
if (DEBUG) Log.v(TAG, "*** Keyguard disconnected (boo!)");
mKeyguardService = null;
mKeyguardState.reset();
mHandler.post(() -> {
try {
ActivityTaskManager.getService().setLockScreenShown(true /* keyguardShowing */,
false /* aodShowing */);
} catch (RemoteException e) {
// Local call.
}
});
}
};
5.3.onSystemReady
服务已经绑定了,直接调用对应的方法,没有的话修改状态,在服务绑定以后根据状态执行对应的方法,其他方法逻辑一样就不重述了。
csharp
public void onSystemReady() {
if (mKeyguardService != null) {
mKeyguardService.onSystemReady();
} else {
mKeyguardState.systemIsReady = true;
}
}
6.PhoneWindowManager.java
这个对象是在SystemServe里初始化WindowManagerService的时候new了一个对象传递给构造方法里的参数的
ini
t.traceBegin("StartWindowManagerService");
// WMS needs sensor service ready
mSystemServiceManager.startBootPhase(t, SystemService.PHASE_WAIT_FOR_SENSOR_SERVICE);
wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
//这里。。。
new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
t.traceEnd();
6.1.构造方法
typescript
mKeyguardDelegate = new KeyguardServiceDelegate(mContext,
new StateCallback() {
@Override
public void onTrustedChanged() {
mWindowManagerFuncs.notifyKeyguardTrustedChanged();
}
@Override
public void onShowingChanged() {
mWindowManagerFuncs.onKeyguardShowingAndNotOccludedChanged();
}
});
6.2.bindKeyguard
csharp
private void bindKeyguard() {
synchronized (mLock) {
if (mKeyguardBound) {
return;
}
mKeyguardBound = true;
}
//见5.1
mKeyguardDelegate.bindService(mContext);
}
调用的地方有两处
>1.onSystemUiStarted
csharp
public void onSystemUiStarted() {
bindKeyguard();
}
>2.systemBooted
csharp
public void systemBooted() {
bindKeyguard();
6.3.systemReady
scss
public void systemReady() {
// In normal flow, systemReady is called before other system services are ready.
// So it is better not to bind keyguard here.
//见5.3,最终
mKeyguardDelegate.onSystemReady();
mVrManagerInternal = LocalServices.getService(VrManagerInternal.class);
if (mVrManagerInternal != null) {
mVrManagerInternal.addPersistentVrModeStateListener(mPersistentVrModeListener);
}
readCameraLensCoverState();
updateUiMode();
mDefaultDisplayRotation.updateOrientationListener();
synchronized (mLock) {
mSystemReady = true;
mHandler.post(new Runnable() {
@Override
public void run() {
updateSettings();
}
});
// If this happens, for whatever reason, systemReady came later than systemBooted.
// And keyguard should be already bound from systemBooted
if (mSystemBooted) {
//如果systemBoot先调用了,那这里直接调用bootCompleted
mKeyguardDelegate.onBootCompleted();
}
}
mAutofillManagerInternal = LocalServices.getService(AutofillManagerInternal.class);
mGestureLauncherService = LocalServices.getService(GestureLauncherService.class);
}
6.4.systemBooted
当系统完成引导到用户可以开始与之交互的点时调用
scss
public void systemBooted() {
bindKeyguard();
synchronized (mLock) {
mSystemBooted = true;
if (mSystemReady) {
//比如在systemReady的情况下才走这里
mKeyguardDelegate.onBootCompleted();
}
}
mSideFpsEventHandler.onFingerprintSensorReady();
startedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
finishedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
int defaultDisplayState = mDisplayManager.getDisplay(DEFAULT_DISPLAY).getState();
boolean defaultDisplayOn = defaultDisplayState == Display.STATE_ON;
boolean defaultScreenTurningOn = mDefaultDisplayPolicy.getScreenOnListener() != null;
if (defaultDisplayOn || defaultScreenTurningOn) {
// Now that system is booted, wait for keyguard and windows to be drawn before
// updating the orientation listener, stopping the boot animation and enabling screen.
screenTurningOn(DEFAULT_DISPLAY, mDefaultDisplayPolicy.getScreenOnListener());
screenTurnedOn(DEFAULT_DISPLAY);
} else {
// We're not turning the screen on, so don't wait for keyguard to be drawn
// to dismiss the boot animation and finish booting
mBootAnimationDismissable = true;
enableScreen(null, false /* report */);
}
}
7.StatusBarKeyguardViewManager.java
7.1.show
typescript
/**
* Show the keyguard. Will handle creating and attaching to the view manager
* lazily.
*/
@Override
public void show(Bundle options) {
mNotificationShadeWindowController.setKeyguardShowing(true);
//见8.1
mKeyguardStateController.notifyKeyguardState(true,
mKeyguardStateController.isOccluded());
//见7.2
reset(true /* hideBouncerWhenShowing */);
}
7.2.reset
scss
public void reset(boolean hideBouncerWhenShowing) {
if (mKeyguardStateController.isShowing()) {
final boolean isOccluded = mKeyguardStateController.isOccluded();
// Hide quick settings.见2.9
mNotificationPanelViewController.resetViews(/* animate= */ !isOccluded);
// Hide bouncer and quick-quick settings.
if (isOccluded && !mDozing) {
mCentralSurfaces.hideKeyguard();
if (hideBouncerWhenShowing || needsFullscreenBouncer()) {
hideBouncer(false /* destroyView */);
}
} else {
//见补充1
showBouncerOrKeyguard(hideBouncerWhenShowing);
}
hideAlternateBouncer(false);
mKeyguardUpdateManager.sendKeyguardReset();
updateStates();
}
}
>1.showBouncerOrKeyguard
scss
protected void showBouncerOrKeyguard(boolean hideBouncerWhenShowing) {
//pin模式
if (needsFullscreenBouncer() && !mDozing) {
// The keyguard might be showing (already). So we need to hide it.
mCentralSurfaces.hideKeyguard();
if (mPrimaryBouncer != null) {
mPrimaryBouncer.show(true /* resetSecuritySelection */);
} else {
mPrimaryBouncerInteractor.show(true);
}
} else {
//正常走这里,见补充2
mCentralSurfaces.showKeyguard();
if (hideBouncerWhenShowing) {
hideBouncer(false /* destroyView */);
if (mPrimaryBouncer != null) {
mPrimaryBouncer.prepare();
}
}
}
updateStates();
}
>2.CentralSurfaces.showKeyguard()
scss
public void showKeyguard() {
mStatusBarStateController.setKeyguardRequested(true);
mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
updateIsKeyguard();
mAssistManagerLazy.get().onLockscreenShown();
}
//
public boolean updateIsKeyguard() {
return updateIsKeyguard(false /* forceStateChange */);
}
//
public boolean updateIsKeyguard(boolean forceStateChange) {
boolean wakeAndUnlocking = mBiometricUnlockController.isWakeAndUnlock();
// For dozing, keyguard needs to be shown whenever the device is non-interactive. Otherwise
// there's no surface we can show to the user. Note that the device goes fully interactive
// late in the transition, so we also allow the device to start dozing once the screen has
// turned off fully.
boolean keyguardForDozing = mDozeServiceHost.getDozingRequested()
&& (!mDeviceInteractive || (isGoingToSleep()
&& (isScreenFullyOff()
|| (mKeyguardStateController.isShowing() && !isOccluded()))));
boolean isWakingAndOccluded = isOccluded() && isWakingOrAwake();
boolean shouldBeKeyguard = (mStatusBarStateController.isKeyguardRequested()
|| keyguardForDozing) && !wakeAndUnlocking && !isWakingAndOccluded;
if (keyguardForDozing) {
updatePanelExpansionForKeyguard();
}
if (shouldBeKeyguard) {
if (mScreenOffAnimationController.isKeyguardShowDelayed()
|| (isGoingToSleep()
&& mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_TURNING_OFF)) {
// Delay showing the keyguard until screen turned off.
} else {
//正常走这里
showKeyguardImpl();
}
} else {
// During folding a foldable device this might be called as a result of
// 'onScreenTurnedOff' call for the inner display.
// In this case:
// * When phone is locked on folding: it doesn't make sense to hide keyguard as it
// will be immediately locked again
// * When phone is unlocked: we still don't want to execute hiding of the keyguard
// as the animation could prepare 'fake AOD' interface (without actually
// transitioning to keyguard state) and this might reset the view states
if (!mScreenOffAnimationController.isKeyguardHideDelayed()
// If we're animating occluded, there's an activity launching over the keyguard
// UI. Wait to hide it until after the animation concludes.
&& !mKeyguardViewMediator.isOccludeAnimationPlaying()) {
return hideKeyguardImpl(forceStateChange);
}
}
return false;
}
//
public void showKeyguardImpl() {
if (mKeyguardStateController.isLaunchTransitionFadingAway()) {
mNotificationPanelViewController.cancelAnimation();
onLaunchTransitionFadingEnded();
}
mMessageRouter.cancelMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
if (!mLockscreenShadeTransitionController.isWakingToShadeLocked()) {
mStatusBarStateController.setState(StatusBarState.KEYGUARD);
}
updatePanelExpansionForKeyguard();
}
//
private void updatePanelExpansionForKeyguard() {
if (mState == StatusBarState.KEYGUARD && mBiometricUnlockController.getMode()
!= BiometricUnlockController.MODE_WAKE_AND_UNLOCK && !mBouncerShowing) {
//继续看补充3
mShadeController.instantExpandShade();
}
}
>3.ShadeControllerImpl.java
csharp
public void instantExpandShade() {
// Make our window larger and the panel expanded.
makeExpandedVisible(true /* force */);
//见小节2.1
mNotificationPanelViewController.expand(false /* animate */);
mCommandQueue.recomputeDisableFlags(mDisplayId, false /* animate */);
}
8.KeyguardStateController
kotlin
public class KeyguardStateControllerImpl implements KeyguardStateController, Dumpable {
8.1.notifyKeyguardState
scss
public void notifyKeyguardState(boolean showing, boolean occluded) {
if (mShowing == showing && mOccluded == occluded) return;
mShowing = showing;
mOccluded = occluded;
mKeyguardUpdateMonitor.setKeyguardShowing(showing, occluded);
notifyKeyguardChanged();
// Update the dismiss amount to the full 0f/1f if we explicitly show or hide the keyguard.
// Otherwise, the dismiss amount could be left at a random value if we show/hide during a
// dismiss gesture, canceling the gesture.
notifyKeyguardDismissAmountChanged(showing ? 0f : 1f, false);
}