基于AndroidR源碼分析
Android WMS動(dòng)畫系統(tǒng)初探(一)
Android WMS動(dòng)畫系統(tǒng)初探(二)
Android WMS動(dòng)畫系統(tǒng)初探(三)
Android WMS動(dòng)畫系統(tǒng)初探 完結(jié)篇
屏幕旋轉(zhuǎn)動(dòng)畫
OrientationListener#onProposedRotationChanged ->
WindowManagerService#updateRotation
當(dāng)屏幕需要旋轉(zhuǎn),WindowOrientationListener響應(yīng)sensorchanged脖母,會(huì)調(diào)用到WMS的updateRotation方法画舌。
從這里開啟屏幕旋轉(zhuǎn)動(dòng)畫的入口。
WindowManagerService#updateRotation
/**
* 重新計(jì)算當(dāng)前旋轉(zhuǎn)
* 當(dāng)系統(tǒng)狀態(tài)發(fā)生變化時(shí)摔竿,如當(dāng)前旋轉(zhuǎn)可能需要更新疲眷、
* 例如當(dāng)設(shè)備头靠或旋轉(zhuǎn)到新的姿態(tài)時(shí)锈候,調(diào)用WindowManagerPolicy
*/
@Override
public void updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout) {
updateRotationUnchecked(alwaysSendConfiguration, forceRelayout);
}
private void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {
ProtoLog.v(WM_DEBUG_ORIENTATION, "updateRotationUnchecked:"
+ " alwaysSendConfiguration=%b forceRelayout=%b",
alwaysSendConfiguration, forceRelayout);
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateRotation");
long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
boolean layoutNeeded = false;
final int displayCount = mRoot.mChildren.size();
for (int i = 0; i < displayCount; ++i) {
final DisplayContent displayContent = mRoot.mChildren.get(i);
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateRotation: display");
// 獲取rotationChanged薄料, 如果是true
// 則必須調(diào)用DisplayContent#sendNewConfiguration完成屏幕旋轉(zhuǎn)或解凍
final boolean rotationChanged = displayContent.updateRotationUnchecked();
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
if (rotationChanged) {
mAtmService.getTaskChangeNotificationController()
.notifyOnActivityRotation(displayContent.mDisplayId);
}
if (!rotationChanged || forceRelayout) {
displayContent.setLayoutNeeded();
layoutNeeded = true;
}
if (rotationChanged || alwaysSendConfiguration) {
displayContent.sendNewConfiguration();
}
}
if (layoutNeeded) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
"updateRotation: performSurfacePlacement");
mWindowPlacerLocked.performSurfacePlacement();
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
} finally {
Binder.restoreCallingIdentity(origId);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
遍歷mRoot.mChildren所有的DisplayContent,調(diào)用displayContent.updateRotationUnchecked()
-> DisplayRotation.updateRotationUnchecked
DisplayRotation#updateRotationUnchecked
/**
* 在這個(gè)方法中將通知container對(duì)于rotation的感知
* 然后根據(jù)頂部的activity開始凍屏動(dòng)畫或者無縫動(dòng)畫
* The display itself gets rotated in {@link DisplayContent#applyRotationLocked}
* during {@link DisplayContent#sendNewConfiguration}.
*
* @param forceUpdate 強(qiáng)制更新旋轉(zhuǎn)泵琳。
* 有時(shí)在WM中摄职,我們可能會(huì)跳過更新方向,因?yàn)槲覀冋诘却D(zhuǎn)完成或顯示解凍
* 這導(dǎo)致先前可見的活動(dòng)的配置被應(yīng)用到一個(gè)新可見的活動(dòng)获列。
* 強(qiáng)制旋轉(zhuǎn)更新可以解決這個(gè)問題谷市。
* @return {@code true} 如果是true
* 則必須調(diào)用DisplayContent#sendNewConfiguration完成屏幕旋轉(zhuǎn)或解凍
*/
boolean updateRotationUnchecked(boolean forceUpdate) {
final int displayId = mDisplayContent.getDisplayId();
if (!forceUpdate) {
if (mDeferredRotationPauseCount > 0) {
// rotation更新被暫停,推遲更新
ProtoLog.v(WM_DEBUG_ORIENTATION, "Deferring rotation, rotation is paused.");
return false;
}
final ScreenRotationAnimation screenRotationAnimation =
mDisplayContent.getRotationAnimation();
if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
// 當(dāng)之前的旋轉(zhuǎn)動(dòng)畫仍在進(jìn)行時(shí)击孩,不能執(zhí)行旋轉(zhuǎn)更新
// 將嘗試在動(dòng)畫完成和顯示解凍后再次更新迫悠。
ProtoLog.v(WM_DEBUG_ORIENTATION, "Deferring rotation, animation in progress.");
return false;
}
if (mService.mDisplayFrozen) {
// 即使屏幕旋轉(zhuǎn)動(dòng)畫已經(jīng)完成(例如isAnimating返回false)
// 但仍然有一段時(shí)間我們還沒有解凍顯示,我們也要停止旋轉(zhuǎn)巩梢。
ProtoLog.v(WM_DEBUG_ORIENTATION,
"Deferring rotation, still finishing previous rotation");
return false;
}
if (mDisplayContent.mFixedRotationTransitionListener
.isTopFixedOrientationRecentsAnimating()) {
// 特殊場(chǎng)景:用戶在Recents動(dòng)畫運(yùn)行時(shí)旋轉(zhuǎn)屏幕创泄,忽略這次更新
return false;
}
}
if (!mService.mDisplayEnabled) {
// display不可用場(chǎng)景
ProtoLog.v(WM_DEBUG_ORIENTATION, "Deferring rotation, display is not enabled.");
return false;
}
final int oldRotation = mRotation;
final int lastOrientation = mLastOrientation;
final int rotation = rotationForOrientation(lastOrientation, oldRotation);
ProtoLog.v(WM_DEBUG_ORIENTATION,
"Computed rotation=%s (%d) for display id=%d based on lastOrientation=%s (%d) and "
+ "oldRotation=%s (%d)",
Surface.rotationToString(rotation), rotation,
displayId,
ActivityInfo.screenOrientationToString(lastOrientation), lastOrientation,
Surface.rotationToString(oldRotation), oldRotation);
ProtoLog.v(WM_DEBUG_ORIENTATION,
"Display id=%d selected orientation %s (%d), got rotation %s (%d)", displayId,
ActivityInfo.screenOrientationToString(lastOrientation), lastOrientation,
Surface.rotationToString(rotation), rotation);
if (oldRotation == rotation) {
// No change.
return false;
}
ProtoLog.v(WM_DEBUG_ORIENTATION,
"Display id=%d rotation changed to %d from %d, lastOrientation=%d",
displayId, rotation, oldRotation, lastOrientation);
if (DisplayContent.deltaRotation(rotation, oldRotation) != 2) {
mDisplayContent.mWaitingForConfig = true;
}
mRotation = rotation;
mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
mService.mH.sendNewMessageDelayed(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT,
mDisplayContent, WINDOW_FREEZE_TIMEOUT_DURATION);
mDisplayContent.setLayoutNeeded();
if (shouldRotateSeamlessly(oldRotation, rotation, forceUpdate)) {
// The screen rotation animation uses a screenshot to freeze the screen while windows
// resize underneath. When we are rotating seamlessly, we allow the elements to
// transition to their rotated state independently and without a freeze required.
prepareSeamlessRotation();
} else {
prepareNormalRotationAnimation();
}
// Give a remote handler (system ui) some time to reposition things.
startRemoteRotation(oldRotation, mRotation);
return true;
}
方法注釋很清楚地解釋了這個(gè)方法的工作:
- 在這個(gè)方法中將通知container對(duì)于rotation的感知,然后根據(jù)頂部的activity開始凍屏動(dòng)畫或者無縫動(dòng)畫且改。
- shouldRotateSeamlessly方法判斷是否需要準(zhǔn)備無縫動(dòng)畫验烧。
-
startRemoteRotation使得在動(dòng)畫開始之前systemui有機(jī)會(huì)響應(yīng)方向變化
@DisplayContent.updateRotationUnchecked → @DisplayRotation.startRemoteRotation
SystemUI端處理查看DisplayChangeController.onRotateDisplay
DisplayRotation#shouldRotateSeamlessly
boolean shouldRotateSeamlessly(int oldRotation, int newRotation, boolean forceUpdate) {
// 如果應(yīng)用(top activity)已經(jīng)在正確的方向上啟動(dòng)那么不需要凍結(jié)顯示
// 剩下的窗口可以使用無縫旋轉(zhuǎn)
if (mDisplayContent.hasTopFixedRotationLaunchingApp()) {
return true;
}
final WindowState w = mDisplayPolicy.getTopFullscreenOpaqueWindow();
if (w == null || w != mDisplayContent.mCurrentFocus) {
return false;
}
// 只有當(dāng)top window請(qǐng)求了無縫旋轉(zhuǎn)并且處于全屏不透明狀態(tài)時(shí),我們才會(huì)啟用無縫旋轉(zhuǎn)又跛。
// 無縫旋轉(zhuǎn)需要凍結(jié)各種表面狀態(tài),不適合動(dòng)畫若治,所以我們現(xiàn)在在動(dòng)畫情況下禁用它
if (w.getAttrs().rotationAnimation != ROTATION_ANIMATION_SEAMLESS || w.isAnimatingLw()) {
return false;
}
// 對(duì)于上下旋轉(zhuǎn)慨蓝,我們不會(huì)隨著導(dǎo)航條移動(dòng)位置而無縫地旋轉(zhuǎn)感混。
// 注意大多數(shù)應(yīng)用程序(orientation:sensor|user,而不是fullSensor的應(yīng)用)
// 不會(huì)進(jìn)入reverse portarit(豎屏的反向)狀態(tài)礼烈,所以實(shí)際上方向不會(huì)改變弧满。
if (oldRotation == mUpsideDownRotation || newRotation == mUpsideDownRotation) {
return false;
}
// 如果導(dǎo)航條不能改變side,那么當(dāng)我們改變方向時(shí)會(huì)發(fā)生跳躍庭呜,不能無縫地旋轉(zhuǎn)
if (!mAllowSeamlessRotationDespiteNavBarMoving && !mDisplayPolicy.navigationBarCanMove()) {
return false;
}
// 如果Activity的bounds不同于它的父窗口犀忱,那么也不能無縫,因?yàn)榇翱谖恢每赡軙?huì)在旋轉(zhuǎn)后改變
if (w.mActivityRecord != null && !w.mActivityRecord.matchParentBounds()) {
return false;
}
// 在存在PinnedTask或System Alert窗口時(shí)阴汇,無法無縫旋轉(zhuǎn)
if (mDisplayContent.getDefaultTaskDisplayArea().hasPinnedTask()
|| mDisplayContent.hasAlertWindowSurfaces()) {
return false;
}
// 在等待最后一次無縫旋轉(zhuǎn)完成(即等待窗口重繪)時(shí)数冬,不能旋轉(zhuǎn)(無縫或不無縫)搀庶。
if (!forceUpdate && mDisplayContent.getWindow(win -> win.mSeamlesslyRotated) != null) {
return false;
}
return true;
}
可以看到進(jìn)行無縫旋轉(zhuǎn)的條件限制還是很多的,具體的判斷邏輯我已經(jīng)在代碼上做了注釋哥倔。
部分場(chǎng)景我目前還無法理解秸架,可能要在之后的開發(fā)維護(hù)工作中逐步理解清楚。
無縫旋轉(zhuǎn)
private void prepareSeamlessRotation() {
// We are careful to reset this in case a window was removed before it finished
// seamless rotation.
mSeamlessRotationCount = 0;
mRotatingSeamlessly = true;
}
額...看起來無縫旋轉(zhuǎn)的prepare方法里并沒有做什么太多的事情
先看一下凍屏旋轉(zhuǎn)吧
凍屏旋轉(zhuǎn)
void prepareNormalRotationAnimation() {
cancelSeamlessRotation();
final RotationAnimationPair anim = selectRotationAnimation();
mService.startFreezingDisplay(anim.mExit, anim.mEnter, mDisplayContent);
}
先是取消無縫旋轉(zhuǎn)動(dòng)畫东抹,然后進(jìn)行凍屏旋轉(zhuǎn)
private static class RotationAnimationPair {
@AnimRes
int mEnter;
@AnimRes
int mExit;
}
DisplayRotation#selectRotationAnimation方法挑選實(shí)際要運(yùn)行的RotationAnimationPair動(dòng)畫效果
WindowManagerService#startFreezingDisplay
void startFreezingDisplay(int exitAnim, int enterAnim, DisplayContent displayContent,
int overrideOriginalRotation) {
// 如果當(dāng)前已經(jīng)處于凍屏或者無縫動(dòng)畫 return
if (mDisplayFrozen || displayContent.getDisplayRotation().isRotatingSeamlessly()) {
return;
}
// 判斷是否滿足凍屏條件
if (!displayContent.isReady() || !mPolicy.isScreenOn() || !displayContent.okToAnimate()) {
// No need to freeze the screen before the display is ready, if the screen is off,
// or we can't currently animate.
return;
}
ProtoLog.d(WM_DEBUG_ORIENTATION,
"startFreezingDisplayLocked: exitAnim=%d enterAnim=%d called by %s",
exitAnim, enterAnim, Debug.getCallers(8));
mScreenFrozenLock.acquire();
mDisplayFrozen = true;
mDisplayFreezeTime = SystemClock.elapsedRealtime();
mLastFinishedFreezeSource = null;
// {@link mDisplayFrozen} prevents us from freezing on multiple displays at the same time.
// As a result, we only track the display that has initially froze the screen.
mFrozenDisplayId = displayContent.getDisplayId();
// 凍結(jié)輸入事件分發(fā)
mInputManagerCallback.freezeInputDispatchingLw();
if (displayContent.mAppTransition.isTransitionSet()) {
displayContent.mAppTransition.freeze();
}
if (PROFILE_ORIENTATION) {
File file = new File("/data/system/frozen");
Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
}
mLatencyTracker.onActionStart(ACTION_ROTATE_SCREEN);
mExitAnimId = exitAnim;
mEnterAnimId = enterAnim;
displayContent.updateDisplayInfo();
// 這時(shí)候還未更新rotaton府阀,獲取的是旋轉(zhuǎn)前的rotation
final int originalRotation = overrideOriginalRotation != ROTATION_UNDEFINED
? overrideOriginalRotation
: displayContent.getDisplayInfo().rotation;
// 創(chuàng)建ScreenRotationAnimation
displayContent.setRotationAnimation(new ScreenRotationAnimation(displayContent,
originalRotation));
}
startFreezingDisplay構(gòu)建了ScreenRotationAnimation并設(shè)置到DisplayContent中
ScreenRotationAnimation
ScreenRotationAnimation(DisplayContent displayContent, @Surface.Rotation int originalRotation) {
mService = displayContent.mWmService;
mContext = mService.mContext;
mDisplayContent = displayContent;
displayContent.getBounds(mOriginalDisplayRect);
// Screenshot does NOT include rotation!
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
// 重新從DisplayInfo中獲取原方向值
final int realOriginalRotation = displayInfo.rotation;
final int originalWidth;
final int originalHeight;
// 這一段是獲取旋轉(zhuǎn)前的長(zhǎng)和寬
if (displayContent.getDisplayRotation().isFixedToUserRotation()) {
// Emulated orientation.
mForceDefaultOrientation = true;
originalWidth = displayContent.mBaseDisplayWidth;
originalHeight = displayContent.mBaseDisplayHeight;
} else {
// Normal situation
originalWidth = displayInfo.logicalWidth;
originalHeight = displayInfo.logicalHeight;
}
if (realOriginalRotation == Surface.ROTATION_90
|| realOriginalRotation == Surface.ROTATION_270) {
mWidth = originalHeight;
mHeight = originalWidth;
} else {
mWidth = originalWidth;
mHeight = originalHeight;
}
mOriginalRotation = originalRotation;
// 計(jì)算旋轉(zhuǎn)前后delta值 用于旋轉(zhuǎn)動(dòng)畫效果
final int delta = DisplayContent.deltaRotation(originalRotation, realOriginalRotation);
final boolean flipped = delta == Surface.ROTATION_90 || delta == Surface.ROTATION_270;
mOriginalWidth = flipped ? originalHeight : originalWidth;
mOriginalHeight = flipped ? originalWidth : originalHeight;
mSurfaceRotationAnimationController = new SurfaceRotationAnimationController();
// Check whether the current screen contains any secure content.
final boolean isSecure = displayContent.hasSecureWindowOnScreen();
final SurfaceControl.Transaction t = mService.mTransactionFactory.get();
try {
// 創(chuàng)建動(dòng)畫要用的幾個(gè)surface
mBackColorSurface = displayContent.makeChildSurface(null)
.setName("BackColorSurface")
.setColorLayer()
.setCallsite("ScreenRotationAnimation")
.build();
// mScreenshotLayer是真正用于旋轉(zhuǎn)動(dòng)畫的layer
mScreenshotLayer = displayContent.makeOverlay()
.setName("RotationLayer")
.setBufferSize(mWidth, mHeight)
.setSecure(isSecure)
.setCallsite("ScreenRotationAnimation")
.build();
mEnterBlackFrameLayer = displayContent.makeOverlay()
.setName("EnterBlackFrameLayer")
.setContainerLayer()
.setCallsite("ScreenRotationAnimation")
.build();
// In case display bounds change, screenshot buffer and surface may mismatch so set a
// scaling mode.
SurfaceControl.Transaction t2 = mService.mTransactionFactory.get();
t2.setOverrideScalingMode(mScreenshotLayer, Surface.SCALING_MODE_SCALE_TO_WINDOW);
t2.apply(true /* sync */);
// 這一大段就是抓取截圖綁定到mScreenshotLayer
final int displayId = displayContent.getDisplayId();
final Surface surface = mService.mSurfaceFactory.get();
surface.copyFrom(mScreenshotLayer);
SurfaceControl.ScreenshotGraphicBuffer gb =
mService.mDisplayManagerInternal.systemScreenshot(displayId);
if (gb != null) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
"ScreenRotationAnimation#getMedianBorderLuma");
mStartLuma = RotationAnimationUtils.getMedianBorderLuma(gb.getGraphicBuffer(),
gb.getColorSpace());
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
try {
surface.attachAndQueueBufferWithColorSpace(gb.getGraphicBuffer(),
gb.getColorSpace());
} catch (RuntimeException e) {
Slog.w(TAG, "Failed to attach screenshot - " + e.getMessage());
}
// If the screenshot contains secure layers, we have to make sure the
// screenshot surface we display it in also has FLAG_SECURE so that
// the user can not screenshot secure layers via the screenshot surface.
if (gb.containsSecureLayers()) {
t.setSecure(mScreenshotLayer, true);
}
t.setLayer(mScreenshotLayer, SCREEN_FREEZE_LAYER_BASE);
t.reparent(mBackColorSurface, displayContent.getSurfaceControl());
t.setLayer(mBackColorSurface, -1);
t.setColor(mBackColorSurface, new float[]{mStartLuma, mStartLuma, mStartLuma});
t.setAlpha(mBackColorSurface, 1);
t.show(mScreenshotLayer);
t.show(mBackColorSurface);
} else {
Slog.w(TAG, "Unable to take screenshot of display " + displayId);
}
surface.destroy();
} catch (OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate freeze surface", e);
}
ProtoLog.i(WM_SHOW_SURFACE_ALLOC,
" FREEZE %s: CREATE", mScreenshotLayer);
// 這里我的理解是對(duì)rotationLayer做默認(rèn)的旋轉(zhuǎn)變換
setRotation(t, realOriginalRotation);
t.apply();
}
接下來我們回到入口的 WindowManagerService#updateRotationUnchecked寞蚌,接下來繼續(xù)調(diào)用DisplayContent#sendNewConfiguration()
DisplayContent#sendNewConfiguration()
void sendNewConfiguration() {
...
if (mWaitingForConfig) {
mWaitingForConfig = false;
mWmService.mLastFinishedFreezeSource = "config-unchanged";
setLayoutNeeded();
mWmService.mWindowPlacerLocked.performSurfacePlacement();
}
}
這里再次調(diào)用我們熟悉的performSurfacePlacement方法挟秤,經(jīng)典再現(xiàn),進(jìn)入窗口布局流程艘刚,
這個(gè)流程會(huì)像前文分析的那樣調(diào)用到RootWindowContainer#performSurfacePlacementNoTrace方法
void performSurfacePlacementNoTrace() {
...
if (mOrientationChangeComplete) {
if (mWmService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
mWmService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
mWmService.mLastFinishedFreezeSource = mLastWindowFreezeSource;
mWmService.mH.removeMessages(WINDOW_FREEZE_TIMEOUT);
}
mWmService.stopFreezingDisplayLocked();
}
}
mWmService#stopFreezingDisplayLocked()
ScreenRotationAnimation screenRotationAnimation = displayContent == null ? null
: displayContent.getRotationAnimation();
if (screenRotationAnimation != null && screenRotationAnimation.hasScreenshot()) {
ProtoLog.i(WM_DEBUG_ORIENTATION, "**** Dismissing screen rotation animation");
DisplayInfo displayInfo = displayContent.getDisplayInfo();
// Get rotation animation again, with new top window
if (!displayContent.getDisplayRotation().validateRotationAnimation(
mExitAnimId, mEnterAnimId, false /* forceDefault */)) {
mExitAnimId = mEnterAnimId = 0;
}
if (screenRotationAnimation.dismiss(mTransaction, MAX_ANIMATION_DURATION,
// MIUI ADD: START
// getTransitionAnimationScaleLocked(), displayInfo.logicalWidth,
mIsCastMode ? 0.0f : getTransitionAnimationScaleLocked(), displayInfo.logicalWidth,
// END
displayInfo.logicalHeight, mExitAnimId, mEnterAnimId)) {
mTransaction.apply();
} else {
screenRotationAnimation.kill();
displayContent.setRotationAnimation(null);
updateRotation = true;
}
} else {
if (screenRotationAnimation != null) {
screenRotationAnimation.kill();
displayContent.setRotationAnimation(null);
}
updateRotation = true;
}
displayContent.getRotationAnimation()獲取了前面流程設(shè)置的ScreenRotationAnimation
screenRotationAnimation.dismiss方法將調(diào)用startAnimation啟動(dòng)動(dòng)畫
ScreenRotationAnimation#startAnimation
/**
* Returns true if animating.
*/
private boolean startAnimation(SurfaceControl.Transaction t, long maxAnimationDuration,
float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) {
if (mScreenshotLayer == null) {
// Can't do animation.
return false;
}
if (mStarted) {
return true;
}
mStarted = true;
// Figure out how the screen has moved from the original rotation.
int delta = DisplayContent.deltaRotation(mCurRotation, mOriginalRotation);
// 這里的exitAnim和enterAnim來自前面流程的selectRotationAnimation方法
final boolean customAnim;
if (exitAnim != 0 && enterAnim != 0) {
customAnim = true;
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, exitAnim);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, enterAnim);
mRotateAlphaAnimation = AnimationUtils.loadAnimation(mContext,
R.anim.screen_rotate_alpha);
} else {
// 如果selectRotationAnimation沒有選擇到custom動(dòng)畫效果
// 就加載默認(rèn)的對(duì)應(yīng)4種方向變換的動(dòng)畫效果
customAnim = false;
switch (delta) { /* Counter-Clockwise Rotations */
case Surface.ROTATION_0:
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
R.anim.screen_rotate_0_exit);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
R.anim.screen_rotate_0_enter);
break;
case Surface.ROTATION_90:
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
R.anim.screen_rotate_plus_90_exit);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
R.anim.screen_rotate_plus_90_enter);
break;
case Surface.ROTATION_180:
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
R.anim.screen_rotate_180_exit);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
R.anim.screen_rotate_180_enter);
break;
case Surface.ROTATION_270:
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
R.anim.screen_rotate_minus_90_exit);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
R.anim.screen_rotate_minus_90_enter);
break;
}
}
ProtoLog.d(WM_DEBUG_ORIENTATION, "Start rotation animation. customAnim=%s, "
+ "mCurRotation=%s, mOriginalRotation=%s",
customAnim, Surface.rotationToString(mCurRotation),
Surface.rotationToString(mOriginalRotation));
mRotateExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
mRotateExitAnimation.restrictDuration(maxAnimationDuration);
mRotateExitAnimation.scaleCurrentDuration(animationScale);
mRotateEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
mRotateEnterAnimation.restrictDuration(maxAnimationDuration);
mRotateEnterAnimation.scaleCurrentDuration(animationScale);
mAnimRunning = false;
mFinishAnimReady = false;
mFinishAnimStartTime = -1;
if (customAnim) {
mRotateAlphaAnimation.restrictDuration(maxAnimationDuration);
mRotateAlphaAnimation.scaleCurrentDuration(animationScale);
}
if (customAnim && mEnteringBlackFrame == null) {
try {
Rect outer = new Rect(-finalWidth, -finalHeight,
finalWidth * 2, finalHeight * 2);
Rect inner = new Rect(0, 0, finalWidth, finalHeight);
mEnteringBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner,
SCREEN_FREEZE_LAYER_ENTER, mDisplayContent, false, mEnterBlackFrameLayer);
} catch (OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate black surface", e);
}
}
if (customAnim) {
mSurfaceRotationAnimationController.startCustomAnimation();
} else {
mSurfaceRotationAnimationController.startScreenRotationAnimation();
}
return true;
}
- exitAnim和enterAnim來自前面流程的selectRotationAnimation方法
- 如果selectRotationAnimation方法沒有獲取到custom動(dòng)畫效果,就加載四種默認(rèn)的效果
- 加載的Animation賦值給 mRotateEnterAnimation 和 mRotateExitAnimation
后面的startCustomAnimation或startScreenRotationAnimation方法流程將使用mRotateEnterAnimation及mRotateExitAnimation構(gòu)建AnimationSpec炸庞,然后使用SurfaceAnimator啟動(dòng)并驅(qū)動(dòng)動(dòng)畫,還是那個(gè)熟悉的味道钱床。
關(guān)于無縫旋轉(zhuǎn)的具體實(shí)現(xiàn)我后面會(huì)再做深入理解。
至此埠居,WMS動(dòng)畫系統(tǒng)初探完結(jié), 撒花 \ o /