1:概述
應(yīng)用程序在冷啟動(dòng)過(guò)程中通常會(huì)顯示一個(gè)預(yù)覽窗口,接著在顯示要啟動(dòng)的activity的窗口,因?yàn)閍ctivity的窗口顯示渲染到屏幕上是需要時(shí)間的,特別是在性能比較差的設(shè)備上,這樣有了預(yù)覽窗口之后屏幕上看到的可能不是黑屏,增強(qiáng)了用戶(hù)體驗(yàn)
本文主要是基于android_10.0.0來(lái)講述的
2:StartingWindow添加流程
ActivityStarter.java::startActivity
ActivityStarter.java::startActivityUnchecked
ActivityStack.java::startActivityLocked
我們主要是從startActivityLocked來(lái)跟蹤
//第一個(gè)條件滿(mǎn)足,一般我們是從桌面啟動(dòng)應(yīng)用
if (!isHomeOrRecentsStack() || numActivities() > 0) {
final DisplayContent dc = getDisplay().mDisplayContent;
.......................................
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
dc.prepareAppTransition(TRANSIT_NONE, keepCurTransition);
mStackSupervisor.mNoAnimActivities.add(r);//是否需要啟動(dòng)動(dòng)畫(huà)
} else {
...................................省去部分代碼
boolean doShow = true;
if (newTask) {
..............................
//桌面啟動(dòng)一般不帶有此flag
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
resetTaskIfNeededLocked(r, r);
doShow = topRunningNonDelayedActivityLocked(null) == r;
}
} else if (options != null && options.getAnimationType()
== ActivityOptions.ANIM_SCENE_TRANSITION) {
doShow = false;
}
// mLaunchTaskBehind = options.getLaunchTaskBehind();賦值,桌面啟動(dòng)不帶有此參數(shù)
if (r.mLaunchTaskBehind) {
r.setVisibility(true);
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
} else if (SHOW_APP_STARTING_PREVIEW && doShow) {//成立doShow=true
TaskRecord prevTask = r.getTaskRecord();
ActivityRecord prev = prevTask.topRunningActivityWithStartingWindowLocked();
if (prev != null) {
// We don't want to reuse the previous starting preview if:
// (1) The current activity is in a different task.
if (prev.getTaskRecord() != prevTask) {
prev = null;
}
// (2) The current activity is already displayed.
else if (prev.nowVisible) {
prev = null;
}
}
//r為ActivityRecord,直接調(diào)用showStartingWindow
r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity));
}
} else {
// If this is the first activity, don't do any fancy animations,
// because there is nothing for it to animate on top of.
ActivityOptions.abort(options);
}
我們?cè)谶@里分析是桌面啟動(dòng)一個(gè)應(yīng)用的情況
2.1:ActivityRecord::showStartingWindow
void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch,
boolean fromRecents) {
if (mAppWindowToken == null) {
return;
}
if (mTaskOverlay) {
// We don't show starting window for overlay activities.
return;
}
if (pendingOptions != null
&& pendingOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
// Don't show starting window when using shared element transition.
return;
}
final CompatibilityInfo compatInfo =
mAtmService.compatibilityInfoForPackageLocked(info.applicationInfo);
final boolean shown = addStartingWindow(packageName, theme,
compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
allowTaskSnapshot(),
mState.ordinal() >= RESUMED.ordinal() && mState.ordinal() <= STOPPED.ordinal(),
fromRecents);
if (shown) {
mStartingWindowState = STARTING_WINDOW_SHOWN;
}
}
boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) {
..................................................
if (mAppWindowToken == null) {
Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + appToken);
return false;
}
if (mAppWindowToken.getTask() == null) {//不會(huì)為null,AppWindowToken被Task管理
return false;
}
return mAppWindowToken.addStartingWindow(pkg, theme, compatInfo, nonLocalizedLabel,
labelRes, icon, logo, windowFlags, transferFrom, newTask, taskSwitch,
processRunning, allowTaskSnapshot, activityCreated, fromRecents);
}
2.2:AppWindowToken::addStartingWindow
boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) {
if (!okToDisplay()) {//還沒(méi)準(zhǔn)備好顯示
return false;
}
if (mStartingData != null) {//如果之前已經(jīng)有啟動(dòng)窗口的數(shù)據(jù)
return false;
}
final WindowState mainWin = findMainWindow();
if (mainWin != null && mainWin.mWinAnimator.getShown()) {
// App already has a visible window...why would you want a starting window?
return false;
}
final ActivityManager.TaskSnapshot snapshot =
mWmService.mTaskSnapshotController.getSnapshot(
getTask().mTaskId, getTask().mUserId,
false /* restoreFromDisk */, false /* reducedResolution */);
final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
allowTaskSnapshot, activityCreated, fromRecents, snapshot);
if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
return createSnapshot(snapshot);
}
if (theme != 0) {//主題,對(duì)應(yīng)的activity的主題
AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
com.android.internal.R.styleable.Window,
mWmService.mCurrentUserId);
if (ent == null) {
// Whoops! App doesn't exist. Um. Okay. We'll just pretend like we didn't
// see that.
return false;
}
final boolean windowIsTranslucent = ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowIsTranslucent, false);
final boolean windowIsFloating = ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowIsFloating, false);
final boolean windowShowWallpaper = ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowShowWallpaper, false);
final boolean windowDisableStarting = ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowDisablePreview, false);
if (windowIsTranslucent) {//如果是半透明
return false;
}
if (windowIsFloating || windowDisableStarting) {//如果是懸浮的或是禁止顯示啟動(dòng)窗口
return false;
}
if (windowShowWallpaper) {//顯示壁紙
if (getDisplayContent().mWallpaperController
.getWallpaperTarget() == null) {
windowFlags |= FLAG_SHOW_WALLPAPER;
} else {//表示的壁紙窗口已經(jīng)被其他的目標(biāo)窗口占用,則不顯示
return false;
}
}
}
if (transferStartingWindow(transferFrom)) {
return true;
}
if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
return false;
}
//窗口啟動(dòng)數(shù)據(jù)
mStartingData = new SplashScreenStartingData(mWmService, pkg,
theme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
getMergedOverrideConfiguration());
scheduleAddStartingWindow();//發(fā)送消息到android.anim線(xiàn)程對(duì)應(yīng)的消息隊(duì)列中
return true;
}
2.3:scheduleAddStartingWindow
void scheduleAddStartingWindow() {
if (!mWmService.mAnimationHandler.hasCallbacks(mAddStartingWindow)) {
mWmService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
}//放在消息對(duì)應(yīng)的頭部,mAnimationHandler對(duì)應(yīng)的是android.anim線(xiàn)程
}
2.4:Runnable對(duì)象mAddStartingWindow
private final Runnable mAddStartingWindow = new Runnable() {
@Override
public void run() {
// Can be accessed without holding the global lock
final StartingData startingData;
synchronized (mWmService.mGlobalLock) {//同步鎖
// There can only be one adding request, silly caller!
mWmService.mAnimationHandler.removeCallbacks(this);//消息隊(duì)列中移除
if (mStartingData == null) {
// Animation has been canceled... do nothing.
return;
}
startingData = mStartingData;
}
WindowManagerPolicy.StartingSurface surface = null;
try {//創(chuàng)建一個(gè)surface繪圖表面startingData是SplashScreenStartingData
surface = startingData.createStartingSurface(AppWindowToken.this);
} catch (Exception e) {
Slog.w(TAG, "Exception when adding starting window", e);
}
if (surface != null) {
boolean abort = false;
synchronized (mWmService.mGlobalLock) {
// If the window was successfully added, then
// we need to remove it.
if (removed || mStartingData == null) {
startingWindow = null;
mStartingData = null;
abort = true;
} else {
startingSurface = surface;
}
}
if (abort) {
surface.remove();
}
} else if (DEBUG_STARTING_WINDOW) {
Slog.v(TAG, "Surface returned was null: " + AppWindowToken.this);
}
}
};
2.5:SplashScreenStartingData::createStartingSurface
StartingSurface createStartingSurface(AppWindowToken atoken) {
return mService.mPolicy.addSplashScreen(atoken.token, mPkg, mTheme, mCompatInfo,
mNonLocalizedLabel, mLabelRes, mIcon, mLogo, mWindowFlags,
mMergedOverrideConfiguration, atoken.getDisplayContent().getDisplayId());
}
mPolicy數(shù)據(jù)類(lèi)型是PhoneWindowManager
2.6:PhoneWindowManager::addSplashScreen
public StartingSurface addSplashScreen(IBinder appToken, String packageName, int theme,
CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon,
int logo, int windowFlags, Configuration overrideConfig, int displayId) {
if (!SHOW_SPLASH_SCREENS) {
return null;
}
if (packageName == null) {//包名信息
return null;
}
WindowManager wm = null;
View view = null;
try {
Context context = mContext;
// Obtain proper context to launch on the right display.
final Context displayContext = getDisplayContext(context, displayId);
if (displayContext == null) {
// Can't show splash screen on requested display, so skip showing at all.
return null;
}
context = displayContext;
if (theme != context.getThemeResId() || labelRes != 0) {
try {
context = context.createPackageContext(packageName, CONTEXT_RESTRICTED);
context.setTheme(theme);
} catch (PackageManager.NameNotFoundException e) {
// Ignore
}
}
if (overrideConfig != null && !overrideConfig.equals(EMPTY)) {
final Context overrideContext = context.createConfigurationContext(overrideConfig);
overrideContext.setTheme(theme);
final TypedArray typedArray = overrideContext.obtainStyledAttributes(
com.android.internal.R.styleable.Window);
final int resId = typedArray.getResourceId(R.styleable.Window_windowBackground, 0);
if (resId != 0 && overrideContext.getDrawable(resId) != null) {
context = overrideContext;
}
typedArray.recycle();
}
final PhoneWindow win = new PhoneWindow(context);//創(chuàng)建一個(gè)PhoneWindow
win.setIsStartingWindow(true);
CharSequence label = context.getResources().getText(labelRes, null);
// Only change the accessibility title if the label is localized
if (label != null) {
win.setTitle(label, true);
} else {
win.setTitle(nonLocalizedLabel, false);
}
//窗口類(lèi)型
win.setType(
WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
if (displayId == DEFAULT_DISPLAY && mKeyguardOccluded) {
windowFlags |= FLAG_SHOW_WHEN_LOCKED;//鎖屏的時(shí)候顯示
}
}
//窗口flag
win.setFlags(
windowFlags|
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
windowFlags|
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
win.setDefaultIcon(icon);
win.setDefaultLogo(logo);
win.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT);
final WindowManager.LayoutParams params = win.getAttributes();
params.token = appToken;//appToken,共有activity的token
params.packageName = packageName;
params.windowAnimations = win.getWindowStyle().getResourceId(
com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED;
params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
if (!compatInfo.supportsScreen()) {
params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
}
params.setTitle("Splash Screen " + packageName);
addSplashscreenContent(win, context);
wm = (WindowManager) context.getSystemService(WINDOW_SERVICE);
view = win.getDecorView();
wm.addView(view, params);//添加到窗口管理器
return view.getParent() != null ? new SplashScreenSurface(view, appToken) : null;
} catch (WindowManager.BadTokenException e) {
} catch (RuntimeException e) {
Log.w(TAG, appToken + " failed creating starting window", e);
} finally {
if (view != null && view.getParent() == null) {
Log.w(TAG, "view not successfully added to wm, removing view");
wm.removeViewImmediate(view);
}
}
return null;
}
這個(gè)方法主要是創(chuàng)建一個(gè)PhoneWindow對(duì)象,然后設(shè)置一些窗口屬性,最后將DecorView添加到窗口管理器
3:啟動(dòng)窗口的移除
我們都知道一個(gè)窗口既然被添加到窗口管理器了,那么肯定也有被銷(xiāo)毀(移除)的時(shí)機(jī),它移除的時(shí)機(jī)就是被啟動(dòng)的組件已經(jīng)可見(jiàn)了,那么啟動(dòng)窗口就需要被移除,我們知道窗口只要有內(nèi)容或是屬性發(fā)生了變化都會(huì)觸發(fā)更新,其更新都會(huì)調(diào)到WindowSurfacePlacer::performSurfacePlacement
3.1:performSurfacePlacement
final void performSurfacePlacement(boolean force) {
if (mDeferDepth > 0 && !force) {
return;
}
int loopCount = 6;
do {
mTraversalScheduled = false;
performSurfacePlacementLoop();
mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement);
loopCount--;
} while (mTraversalScheduled && loopCount > 0);
mService.mRoot.mWallpaperActionPending = false;
}
3.2:performSurfacePlacementLoop
private void performSurfacePlacementLoop() {
if (mInLayout) {
return;
}
// TODO(multi-display):
final DisplayContent defaultDisplay = mService.getDefaultDisplayContentLocked();
if (defaultDisplay.mWaitingForConfig) {
return;
}
if (!mService.mDisplayReady) {
// Not yet initialized, nothing to do.
return;
}
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
mInLayout = true;
boolean recoveringMemory = false;
if (!mService.mForceRemoves.isEmpty()) {
recoveringMemory = true;
// Wait a little bit for things to settle down, and off we go.
while (!mService.mForceRemoves.isEmpty()) {
final WindowState ws = mService.mForceRemoves.remove(0);
Slog.i(TAG, "Force removing: " + ws);
ws.removeImmediately();
}
Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
Object tmp = new Object();
synchronized (tmp) {
try {
tmp.wait(250);
} catch (InterruptedException e) {
}
}
}
try {
//mRoot是RootWindowContainer.java
mService.mRoot.performSurfacePlacement(recoveringMemory);
mInLayout = false;
if (mService.mRoot.isLayoutNeeded()) {
if (++mLayoutRepeatCount < 6) {
requestTraversal();
} else {
Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
mLayoutRepeatCount = 0;
}
} else {
mLayoutRepeatCount = 0;
}
if (mService.mWindowsChanged && !mService.mWindowChangeListeners.isEmpty()) {
mService.mH.removeMessages(REPORT_WINDOWS_CHANGE);
mService.mH.sendEmptyMessage(REPORT_WINDOWS_CHANGE);
}
} catch (RuntimeException e) {
mInLayout = false;
Slog.wtf(TAG, "Unhandled exception while laying out windows", e);
}
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
3.3RootWindowContainer::performSurfacePlacement
void performSurfacePlacement(boolean recoveringMemory) {
try {
performSurfacePlacementNoTrace(recoveringMemory);
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
3.4:performSurfacePlacementNoTrace
void performSurfacePlacementNoTrace(boolean recoveringMemory) {
int i;
if (mWmService.mFocusMayChange) {//如果焦點(diǎn)窗口可能改變
mWmService.mFocusMayChange = false;
mWmService.updateFocusedWindowLocked(//更新焦點(diǎn)窗口
UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
}
final int numDisplays = mChildren.size();
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
final DisplayContent displayContent = mChildren.get(displayNdx);
displayContent.setExitingTokensHasVisible(false);
}
mHoldScreen = null;
mScreenBrightness = -1;
mUserActivityTimeout = -1;
mObscureApplicationContentOnSecondaryDisplays = false;
mSustainedPerformanceModeCurrent = false;
mWmService.mTransactionSequence++;
// TODO(multi-display): recents animation & wallpaper need support multi-display.
final DisplayContent defaultDisplay = mWmService.getDefaultDisplayContentLocked();
final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applySurfaceChanges");
mWmService.openSurfaceTransaction();
try {
//執(zhí)行/應(yīng)用surface改變事務(wù)
applySurfaceChangesTransaction(recoveringMemory);
} catch (RuntimeException e) {
Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
} finally {
//關(guān)閉事務(wù)
mWmService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
mWmService.mAnimator.executeAfterPrepareSurfacesRunnables();
checkAppTransitionReady(surfacePlacer);//檢查app切換是否準(zhǔn)備完畢
// Defer starting the recents animation until the wallpaper has drawn
final RecentsAnimationController recentsAnimationController =
mWmService.getRecentsAnimationController();
if (recentsAnimationController != null) {
recentsAnimationController.checkAnimationReady(defaultDisplay.mWallpaperController);
}
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
final DisplayContent displayContent = mChildren.get(displayNdx);
if (displayContent.mWallpaperMayChange) {//壁紙窗口層級(jí)是否可能改變
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;//重新布局壁紙窗口
}
}
if (mWmService.mFocusMayChange) {
mWmService.mFocusMayChange = false;
mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
false /*updateInputWindows*/);
}
if (isLayoutNeeded()) {//是否需要重新layout
defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT;
handleResizingWindows();
if (mOrientationChangeComplete) {//旋轉(zhuǎn)
if (mWmService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
mWmService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
mWmService.mLastFinishedFreezeSource = mLastWindowFreezeSource;
mWmService.mH.removeMessages(WINDOW_FREEZE_TIMEOUT);
}
mWmService.stopFreezingDisplayLocked();
}
// Destroy the surface of any windows that are no longer visible.
i = mWmService.mDestroySurface.size();
if (i > 0) {
do {
i--;
WindowState win = mWmService.mDestroySurface.get(i);
win.mDestroying = false;
final DisplayContent displayContent = win.getDisplayContent();
if (displayContent.mInputMethodWindow == win) {//如果是輸入法窗口
displayContent.setInputMethodWindowLocked(null);
}
if (displayContent.mWallpaperController.isWallpaperTarget(win)) {
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;//如果當(dāng)前窗口是壁紙窗口的目標(biāo)窗口,那么需要重新布局壁紙,改變壁紙窗口的層級(jí)和顯示位置
}
win.destroySurfaceUnchecked();
win.mWinAnimator.destroyPreservedSurfaceLocked();
} while (i > 0);
mWmService.mDestroySurface.clear();
}
// Time to remove any exiting tokens?
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
final DisplayContent displayContent = mChildren.get(displayNdx);
displayContent.removeExistingTokensIfPossible();
}
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
final DisplayContent displayContent = mChildren.get(displayNdx);
if (displayContent.pendingLayoutChanges != 0) {
displayContent.setLayoutNeeded();
}
}
mWmService.setHoldScreenLocked(mHoldScreen);
if (!mWmService.mDisplayFrozen) {
final int brightness = mScreenBrightness < 0 || mScreenBrightness > 1.0f
? -1 : toBrightnessOverride(mScreenBrightness);
mHandler.obtainMessage(SET_SCREEN_BRIGHTNESS_OVERRIDE, brightness, 0).sendToTarget();
mHandler.obtainMessage(SET_USER_ACTIVITY_TIMEOUT, mUserActivityTimeout).sendToTarget();
}
if (mSustainedPerformanceModeCurrent != mSustainedPerformanceModeEnabled) {
mSustainedPerformanceModeEnabled = mSustainedPerformanceModeCurrent;
mWmService.mPowerManagerInternal.powerHint(
PowerHint.SUSTAINED_PERFORMANCE,
(mSustainedPerformanceModeEnabled ? 1 : 0));
}
if (mUpdateRotation) {
if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
mUpdateRotation = updateRotationUnchecked();
}
if (mWmService.mWaitingForDrawnCallback != null
|| (mOrientationChangeComplete && !isLayoutNeeded()
&& !mUpdateRotation)) {
mWmService.checkDrawnWindowsLocked();
}
final int N = mWmService.mPendingRemove.size();
if (N > 0) {
if (mWmService.mPendingRemoveTmp.length < N) {
mWmService.mPendingRemoveTmp = new WindowState[N + 10];
}
mWmService.mPendingRemove.toArray(mWmService.mPendingRemoveTmp);
mWmService.mPendingRemove.clear();
ArrayList<DisplayContent> displayList = new ArrayList();
for (i = 0; i < N; i++) {
final WindowState w = mWmService.mPendingRemoveTmp[i];
w.removeImmediately();
final DisplayContent displayContent = w.getDisplayContent();
if (displayContent != null && !displayList.contains(displayContent)) {
displayList.add(displayContent);
}
}
for (int j = displayList.size() - 1; j >= 0; --j) {
final DisplayContent dc = displayList.get(j);
dc.assignWindowLayers(true /*setLayoutNeeded*/);
}
}
// Remove all deferred displays stacks, tasks, and activities.
for (int displayNdx = mChildren.size() - 1; displayNdx >= 0; --displayNdx) {
mChildren.get(displayNdx).checkCompleteDeferredRemoval();
}
forAllDisplays(dc -> {
dc.getInputMonitor().updateInputWindowsLw(true /*force*/);
dc.updateSystemGestureExclusion();
dc.updateTouchExcludeRegion();
});
// Check to see if we are now in a state where the screen should
// be enabled, because the window obscured flags have changed.
mWmService.enableScreenIfNeededLocked();//屏幕使能
mWmService.scheduleAnimationLocked();//準(zhǔn)備開(kāi)啟動(dòng)畫(huà)
}
3.5:applySurfaceChangesTransaction
private void applySurfaceChangesTransaction(boolean recoveringMemory) {
mHoldScreenWindow = null;
mObscuringWindow = null;
// TODO(multi-display): Support these features on secondary screens.
final DisplayContent defaultDc = mWmService.getDefaultDisplayContentLocked();
final DisplayInfo defaultInfo = defaultDc.getDisplayInfo();
final int defaultDw = defaultInfo.logicalWidth;
final int defaultDh = defaultInfo.logicalHeight;
if (mWmService.mWatermark != null) {
mWmService.mWatermark.positionSurface(defaultDw, defaultDh);
}
if (mWmService.mStrictModeFlash != null) {
mWmService.mStrictModeFlash.positionSurface(defaultDw, defaultDh);
}
if (mWmService.mCircularDisplayMask != null) {
mWmService.mCircularDisplayMask.positionSurface(defaultDw, defaultDh,
mWmService.getDefaultDisplayRotation());
}
if (mWmService.mEmulatorDisplayOverlay != null) {
mWmService.mEmulatorDisplayOverlay.positionSurface(defaultDw, defaultDh,
mWmService.getDefaultDisplayRotation());
}
final int count = mChildren.size();
for (int j = 0; j < count; ++j) {
final DisplayContent dc = mChildren.get(j);
dc.applySurfaceChangesTransaction(recoveringMemory);
}
mWmService.mDisplayManagerInternal.performTraversal(mDisplayTransaction);
SurfaceControl.mergeToGlobalTransaction(mDisplayTransaction);
}
3.6:applySurfaceChangesTransaction
void applySurfaceChangesTransaction(boolean recoveringMemory) {
final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
mTmpUpdateAllDrawn.clear();
int repeats = 0;
do {
repeats++;
if (repeats > 6) {
Slog.w(TAG, "Animation repeat aborted after too many iterations");
clearLayoutNeeded();
break;
}
if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
mWallpaperController.adjustWallpaperWindows();//調(diào)整壁紙窗口
}
if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_CONFIG) != 0) {
if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
if (updateOrientationFromAppTokens()) {//如果應(yīng)用要求改變顯示方向
setLayoutNeeded();//重新布局
sendNewConfiguration();//設(shè)置新的配置
}
}
if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_LAYOUT) != 0) {
setLayoutNeeded();
}
// FIRST LOOP: Perform a layout, if needed.
if (repeats < LAYOUT_REPEAT_THRESHOLD) {
performLayout(repeats == 1, false /* updateInputWindows */);
} else {
Slog.w(TAG, "Layout repeat skipped after too many iterations");
}
pendingLayoutChanges = 0;
try {
mDisplayPolicy.beginPostLayoutPolicyLw();
forAllWindows(mApplyPostLayoutPolicy, true /* traverseTopToBottom */);
pendingLayoutChanges |= mDisplayPolicy.finishPostLayoutPolicyLw();
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
mInsetsStateController.onPostLayout();
} while (pendingLayoutChanges != 0);
mTmpApplySurfaceChangesTransactionState.reset();
mTmpRecoveringMemory = recoveringMemory;
try {
forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);//重點(diǎn)
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
prepareSurfaces();
mLastHasContent = mTmpApplySurfaceChangesTransactionState.displayHasContent;
mWmService.mDisplayManagerInternal.setDisplayProperties(mDisplayId,
mLastHasContent,
mTmpApplySurfaceChangesTransactionState.preferredRefreshRate,
mTmpApplySurfaceChangesTransactionState.preferredModeId,
true /* inTraversal, must call performTraversalInTrans... below */);
final boolean wallpaperVisible = mWallpaperController.isWallpaperVisible();
if (wallpaperVisible != mLastWallpaperVisible) {
mLastWallpaperVisible = wallpaperVisible;
mWmService.mWallpaperVisibilityListeners.notifyWallpaperVisibilityChanged(this);
}
while (!mTmpUpdateAllDrawn.isEmpty()) {
final AppWindowToken atoken = mTmpUpdateAllDrawn.removeLast();
atoken.updateAllDrawn();
}
}
3.7:mApplySurfaceChangesTransaction
private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {
final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
final boolean obscuredChanged = w.mObscured !=
mTmpApplySurfaceChangesTransactionState.obscured;
final RootWindowContainer root = mWmService.mRoot;
// Update effect.
w.mObscured = mTmpApplySurfaceChangesTransactionState.obscured;
if (!mTmpApplySurfaceChangesTransactionState.obscured) {
final boolean isDisplayed = w.isDisplayedLw();
if (isDisplayed && w.isObscuringDisplay()) {
// This window completely covers everything behind it, so we want to leave all
// of them as undimmed (for performance reasons).
root.mObscuringWindow = w;
mTmpApplySurfaceChangesTransactionState.obscured = true;
}
mTmpApplySurfaceChangesTransactionState.displayHasContent |=
root.handleNotObscuredLocked(w,
mTmpApplySurfaceChangesTransactionState.obscured,
mTmpApplySurfaceChangesTransactionState.syswin);
if (w.mHasSurface && isDisplayed) {
final int type = w.mAttrs.type;
if (type == TYPE_SYSTEM_DIALOG || type == TYPE_SYSTEM_ERROR
|| (w.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
mTmpApplySurfaceChangesTransactionState.syswin = true;
}
if (mTmpApplySurfaceChangesTransactionState.preferredRefreshRate == 0
&& w.mAttrs.preferredRefreshRate != 0) {
mTmpApplySurfaceChangesTransactionState.preferredRefreshRate
= w.mAttrs.preferredRefreshRate;
}
final int preferredModeId = getDisplayPolicy().getRefreshRatePolicy()
.getPreferredModeId(w);
if (mTmpApplySurfaceChangesTransactionState.preferredModeId == 0
&& preferredModeId != 0) {
mTmpApplySurfaceChangesTransactionState.preferredModeId = preferredModeId;
}
}
}
if (obscuredChanged && w.isVisibleLw() && mWallpaperController.isWallpaperTarget(w)) {
mWallpaperController.updateWallpaperVisibility();
}
w.handleWindowMovedIfNeeded();
final WindowStateAnimator winAnimator = w.mWinAnimator;
w.resetContentChanged();
if (w.mHasSurface) {
final boolean committed = winAnimator.commitFinishDrawingLocked();
if (isDefaultDisplay && committed) {
if (w.mAttrs.type == TYPE_DREAM) {
pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT;
}
if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
mWallpaperMayChange = true;
pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}
}
}
final AppWindowToken atoken = w.mAppToken;
if (atoken != null) {
atoken.updateLetterboxSurface(w);
final boolean updateAllDrawn = atoken.updateDrawnWindowStates(w);
if (updateAllDrawn && !mTmpUpdateAllDrawn.contains(atoken)) {
mTmpUpdateAllDrawn.add(atoken);
}
}
if (!mLosingFocus.isEmpty() && w.isFocused() && w.isDisplayedLw()) {
mWmService.mH.obtainMessage(REPORT_LOSING_FOCUS, this).sendToTarget();
}
w.updateResizingWindowIfNeeded();
};
3.8:commitFinishDrawingLocked
boolean commitFinishDrawingLocked() {
if (mDrawState != COMMIT_DRAW_PENDING && mDrawState != READY_TO_SHOW) {
return false;
}
mDrawState = READY_TO_SHOW;
boolean result = false;
final AppWindowToken atoken = mWin.mAppToken;
if (atoken == null || atoken.canShowWindows()
|| mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
result = mWin.performShowLocked();
}
return result;
}
3.9:performShowLocked
boolean performShowLocked() {
if (isHiddenFromUserLocked()) {
clearPolicyVisibilityFlag(VISIBLE_FOR_USER);
return false;
}
logPerformShow("performShow on ");
final int drawState = mWinAnimator.mDrawState;
if ((drawState == HAS_DRAWN || drawState == READY_TO_SHOW)
&& mAttrs.type != TYPE_APPLICATION_STARTING && mAppToken != null) {
mAppToken.onFirstWindowDrawn(this, mWinAnimator);
}
if (mWinAnimator.mDrawState != READY_TO_SHOW || !isReadyForDisplay()) {
return false;
}
logPerformShow("Showing ");
mWmService.enableScreenIfNeededLocked();//屏幕使能
mWinAnimator.applyEnterAnimationLocked();//執(zhí)行進(jìn)入動(dòng)畫(huà)
mWinAnimator.mLastAlpha = -1;
mWinAnimator.mDrawState = HAS_DRAWN;
mWmService.scheduleAnimationLocked();//調(diào)度動(dòng)畫(huà)
if (mHidden) {
mHidden = false;
final DisplayContent displayContent = getDisplayContent();
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = mChildren.get(i);
if (c.mWinAnimator.mSurfaceController != null) {
c.performShowLocked();
if (displayContent != null) {
displayContent.setLayoutNeeded();
}
}
}
}
if (mAttrs.type == TYPE_INPUT_METHOD) {
getDisplayContent().mDividerControllerLocked.resetImeHideRequested();
}
return true;
}
3.10:onFirstWindowDrawn
void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) {
firstWindowDrawn = true;
// We now have a good window to show, remove dead placeholders
removeDeadWindows();
if (startingWindow != null) {
win.cancelAnimation();//取消動(dòng)畫(huà)播放
}
removeStartingWindow();//移除啟動(dòng)窗口
updateReportedVisibilityLocked();//更新上報(bào)可見(jiàn)性
}
3.11:removeStartingWindow
void removeStartingWindow() {
if (startingWindow == null) {
if (mStartingData != null) {
mStartingData = null;
}
return;
}
final WindowManagerPolicy.StartingSurface surface;
if (mStartingData != null) {
surface = startingSurface;
mStartingData = null;
startingSurface = null;
startingWindow = null;
startingDisplayed = false;
if (surface == null) {
return;
}
} else {
return;
}
mWmService.mAnimationHandler.post(() -> {
try {
surface.remove();//surface是SplashScreenSurface
} catch (Exception e) {
Slog.w(TAG_WM, "Exception when removing starting window", e);
}
});
}
3.12:remove
@Override
public void remove() {
final WindowManager wm = mView.getContext().getSystemService(WindowManager.class);
wm.removeView(mView);//直接移除DecorView
}
我們從上面可以看到啟動(dòng)窗口的添加和移除是在android.anim線(xiàn)程中完成,添加的邏輯主要是創(chuàng)建一個(gè)PhoneWindow,然后將PhoneWindow的DecorView添加到窗口管理器,移除則是直接removeDecorView來(lái)完成的