锁屏界面时,touch事件触发界面上滑的动作此处就不再分析,网上已经有很多详细的信息供大家观看,本文主要分析上滑解锁后锁屏Window切换退出过程等.
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)
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());
}
}
}
以上有此处需要分析的为 mKeyguardGoingAwayRunnable 与 handleStartKeyguardExitAnimation,既然我们是分析的是上滑解锁,那么直接走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();
}
};
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 */);
}
通过ActivityTaskManager.getService().keyguardGoingAway(keyguardFlag),传递到frameworks system_service
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);
}
}
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;
}
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;
}
resumeFocusedStacksTopActivities(RootActivityContainer.java)
ensureActivitiesVisible(RootActivityContainer.java)
addStartingWindowsForVisibleActivities(RootActivityContainer.java)
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)
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可以开始进行解锁动画了.
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;
}
setState(StatusBarStateControllerImpl.java)
==>onStateChanged(StatusBar.java)
==>updateMediaMetaData(StatusBarNotificationPresenter.java)
==>updateMediaMetaData(NotificationMediaManager.java 开始锁屏壁纸隐藏动画)
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就可以根据这个时间去设置自己的退出动画,如隐藏锁屏壁纸,适时的改变状态栏高度,更新通知栏上的通知状态变换,显示出虚拟按键等.