对于冻屏理解不深可能会认为冻屏会出现黑屏,不是这样的,恰恰相反,冻屏的目的就是防止执行默写操作的过程出现黑屏。冻屏的过程只是不接收输入和不执行动画,并且会截取屏幕进行显示。下面我们就来分下冻屏的过程。
WMS暴露了一个可以通过binder调用执行的冻屏操作,是startFreezingScreen函数
@Override
public void startFreezingScreen(int exitAnim, int enterAnim) {
// 1 权限检查
if (!checkCallingPermission(android.Manifest.permission.FREEZE_SCREEN,
"startFreezingScreen()")) {
throw new SecurityException("Requires FREEZE_SCREEN permission");
}
synchronized(mWindowMap) { //2 执行冻结屏幕
if (!mClientFreezingScreen) {
mClientFreezingScreen = true;
final long origId = Binder.clearCallingIdentity();
try {
startFreezingDisplayLocked(false, exitAnim, enterAnim);
mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);
mH.sendEmptyMessageDelayed(H.CLIENT_FREEZE_TIMEOUT, 5000);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
}
}
这个函数很简单 mClientFreezingScreen变量代表通过客户端进行冻结屏幕,另外作为系统服务,客户端是不可靠的,所以添加了一个CLIENT_FREEZE_TIMEOUT超时的消息,用于结束冻结屏幕。这是系统设置中最重要的一个保障,对于不可控的客户端操作全都采用超时处理机制。
startFreezingDisplayLocked函数是内部实现,系统除了由于客户端请求的冻结,还有其他情况会冻结,都是通过这个函数实现,我们在分析结束冻结的时候会看到那些情况出发冻结
private void startFreezingDisplayLocked(boolean inTransaction, int exitAnim, int enterAnim) {
if (mDisplayFrozen) {
return;
}
if (!mDisplayReady || !mPolicy.isScreenOn()) { //1 display没准备好或者熄屏 不需要冻结屏幕
// No need to freeze the screen before the system is ready or if
// the screen is off.
return;
}
if (DEBUG_ORIENTATION) Slog.d(TAG_WM,
"startFreezingDisplayLocked: inTransaction=" + inTransaction
+ " exitAnim=" + exitAnim + " enterAnim=" + enterAnim
+ " called by " + Debug.getCallers(8));
// 2 获取一个WEAK LOCK防止睡眠
mScreenFrozenLock.acquire();
// 3 核心变量设置为真
mDisplayFrozen = true;
mDisplayFreezeTime = SystemClock.elapsedRealtime();
mLastFinishedFreezeSource = null;
// 4 冻结input输入
mInputMonitor.freezeInputDispatchingLw();
// Clear the last input window -- that is just used for
// clean transitions between IMEs, and if we are freezing
// the screen then the whole world is changing behind the scenes.
mPolicy.setLastInputMethodWindowLw(null, null);
//5 强制结束app动画
if (mAppTransition.isTransitionSet()) {
mAppTransition.freeze();
}
if (PROFILE_ORIENTATION) {
File file = new File("/data/system/frozen");
Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
}
//5 设置用户传进来的动画,CUSTOM_SCREEN_ROTATION一般系统都为真,为假的情况我们后面分析
if (CUSTOM_SCREEN_ROTATION) {
mExitAnimId = exitAnim;
mEnterAnimId = enterAnim;
final DisplayContent displayContent = getDefaultDisplayContentLocked();
final int displayId = displayContent.getDisplayId();
//6 结束之前的转屏动画
ScreenRotationAnimation screenRotationAnimation =
mAnimator.getScreenRotationAnimationLocked(displayId);
if (screenRotationAnimation != null) {
screenRotationAnimation.kill();
}
// Check whether the current screen contains any secure content.
boolean isSecure = false;
final WindowList windows = getDefaultWindowListLocked();
final int N = windows.size();
for (int i = 0; i < N; i++) {
WindowState ws = windows.get(i);
if (ws.isOnScreen() && (ws.mAttrs.flags & FLAG_SECURE) != 0) {
isSecure = true;
break;
}
}
// TODO(multidisplay): rotation on main screen only.
displayContent.updateDisplayInfo();
// 7 创建并且设置转屏动画
screenRotationAnimation = new ScreenRotationAnimation(mContext, displayContent,
mFxSession, inTransaction, mPolicy.isDefaultOrientationForced(), isSecure);
mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
}
}
对于第七步骤中设置转屏动画的解释是,系统把转屏和冻屏放在一个动画处理,首先转屏会触发冻品,其次这里冻屏其实就是0对的转屏动画, mAnimator对象则是WMS中执行动画的大管家我们后面会分析的到。
对于ScreenRotationAnimation的构造如下
public ScreenRotationAnimation(Context context, DisplayContent displayContent,
SurfaceSession session, boolean inTransaction, boolean forceDefaultOrientation,
boolean isSecure) {
mContext = context;
mDisplayContent = displayContent;
// 1获取屏幕逻辑大小(有时候模拟小屏幕的时候逻辑大小小于物理大小)
displayContent.getLogicalDisplayRect(mOriginalDisplayRect);
// Screenshot does NOT include rotation!
final Display display = displayContent.getDisplay();
int originalRotation = display.getRotation();
final int originalWidth;
final int originalHeight;
DisplayInfo displayInfo = displayContent.getDisplayInfo();
if (forceDefaultOrientation) {
// Emulated orientation.
mForceDefaultOrientation = true;
originalWidth = displayContent.mBaseDisplayWidth;
originalHeight = displayContent.mBaseDisplayHeight;
} else {
// Normal situation
originalWidth = displayInfo.logicalWidth;
originalHeight = displayInfo.logicalHeight;
}
if (originalRotation == Surface.ROTATION_90
|| originalRotation == Surface.ROTATION_270) {
mWidth = originalHeight;
mHeight = originalWidth;
} else {
mWidth = originalWidth;
mHeight = originalHeight;
}
// 2 设置三个变量,分别表示转屏之前的角度,宽高
mOriginalRotation = originalRotation;
mOriginalWidth = originalWidth;
mOriginalHeight = originalHeight;
// 4 如果没有在surfaceflinger事务中执行冻结操作要开启事务
if (!inTransaction) {
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
">>> OPEN TRANSACTION ScreenRotationAnimation");
SurfaceControl.openTransaction();
}
try {
try {
int flags = SurfaceControl.HIDDEN;
if (isSecure) {//因为后面会截取屏幕,这里有些surface是安全的则动画这个surface也应该是安全的
//否则会泄露信息
flags |= SurfaceControl.SECURE;
}
if (DEBUG_SURFACE_TRACE) {
mSurfaceControl = new SurfaceTrace(session, "ScreenshotSurface",
mWidth, mHeight,
PixelFormat.OPAQUE, flags);
Slog.w(TAG, "ScreenRotationAnimation ctor: displayOffset="
+ mOriginalDisplayRect.toShortString());
} else {
mSurfaceControl = new SurfaceControl(session, "ScreenshotSurface",
mWidth, mHeight,
PixelFormat.OPAQUE, flags);
}
//4 截取屏幕并显示这个surface,注意这里设置的z轴SCREEN_FREEZE_LAYER_SCREENSHOT很大,在上面
// capture a screenshot into the surface we just created
Surface sur = new Surface();
sur.copyFrom(mSurfaceControl);
// FIXME: we should use the proper display
SurfaceControl.screenshot(SurfaceControl.getBuiltInDisplay(
SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN), sur);
mSurfaceControl.setLayerStack(display.getLayerStack());
mSurfaceControl.setLayer(SCREEN_FREEZE_LAYER_SCREENSHOT);
mSurfaceControl.setAlpha(0);
mSurfaceControl.show();
sur.destroy();
} catch (OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate freeze surface", e);
}
if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG_WM,
" FREEZE " + mSurfaceControl + ": CREATE");
setRotationInTransaction(originalRotation);
} finally {
if (!inTransaction) { //5 最后提交事务
SurfaceControl.closeTransaction();
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
"<<< CLOSE TRANSACTION ScreenRotationAnimation");
}
}
}
// Must be called while in a transaction.
private void setRotationInTransaction(int rotation) {
mCurRotation = rotation;
// Compute the transformation matrix that must be applied
// to the snapshot to make it stay in the same original position
// with the current screen rotation.
int delta = DisplayContent.deltaRotation(rotation, Surface.ROTATION_0);
createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
if (DEBUG_STATE) Slog.v(TAG, "**** ROTATION: " + delta);
setSnapshotTransformInTransaction(mSnapshotInitialMatrix, 1.0f); //这里设置alpha为1使surface可见
}
从ScreenRotationAnimation的构造中可以看出来创建一个Surface,并且截取屏幕,放在所有layer的上面,然后显示这个layer,导致了冻结屏幕后其实显示的界面已经变成了截图的这个surface. 这里不是研究动画矩阵的变化,就不分析矩阵相关的操作了(其实也很简单,我前面有写过相关的博客)。
同样WMS有暴露了一个结束冻结的方法stopFreezingScreen
@Override
public void stopFreezingScreen() {
if (!checkCallingPermission(android.Manifest.permission.FREEZE_SCREEN,
"stopFreezingScreen()")) {
throw new SecurityException("Requires FREEZE_SCREEN permission");
}
synchronized(mWindowMap) { //设置mClientFreezingScreen为false标志客户端请求的冻结屏幕已经结束,调用stopFreezingDisplayLocked执行解冻操作
if (mClientFreezingScreen) {
mClientFreezingScreen = false;
mLastFinishedFreezeSource = "client";
final long origId = Binder.clearCallingIdentity();
try {
stopFreezingDisplayLocked();
} finally {
Binder.restoreCallingIdentity(origId);
}
}
}
}
同样stopFreezingDisplayLocak为解冻操作的实作者
void stopFreezingDisplayLocked() {
if (!mDisplayFrozen) { //1 没有冻屏直接返回
return;
}
//2 判断是否所有引起冻结的情况都已经解除,其中mWaitingForConfig表示配置属性变化
//mAppsFreezingScreen表示切换Activity时候引起的冻结,mWindowsFreezingScreen Window切换引起的,mClientFreezingScreen客户明确请求
if (mWaitingForConfig || mAppsFreezingScreen > 0
|| mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_ACTIVE
|| mClientFreezingScreen || !mOpeningApps.isEmpty()) {
if (DEBUG_ORIENTATION) Slog.d(TAG_WM,
"stopFreezingDisplayLocked: Returning mWaitingForConfig=" + mWaitingForConfig
+ ", mAppsFreezingScreen=" + mAppsFreezingScreen
+ ", mWindowsFreezingScreen=" + mWindowsFreezingScreen
+ ", mClientFreezingScreen=" + mClientFreezingScreen
+ ", mOpeningApps.size()=" + mOpeningApps.size());
return;
}
if (DEBUG_ORIENTATION) Slog.d(TAG_WM,
"stopFreezingDisplayLocked: Unfreezing now");
mDisplayFrozen = false; //3 核心变量解除冻结
mLastDisplayFreezeDuration = (int)(SystemClock.elapsedRealtime() - mDisplayFreezeTime);
StringBuilder sb = new StringBuilder(128);
sb.append("Screen frozen for ");
TimeUtils.formatDuration(mLastDisplayFreezeDuration, sb);
if (mLastFinishedFreezeSource != null) {
sb.append(" due to ");
sb.append(mLastFinishedFreezeSource);
}
Slog.i(TAG_WM, sb.toString());
mH.removeMessages(H.APP_FREEZE_TIMEOUT); //4移除超时消息
mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);
if (PROFILE_ORIENTATION) {
Debug.stopMethodTracing();
}
boolean updateRotation = false;
final DisplayContent displayContent = getDefaultDisplayContentLocked();
final int displayId = displayContent.getDisplayId();
ScreenRotationAnimation screenRotationAnimation =
mAnimator.getScreenRotationAnimationLocked(displayId);
if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
&& screenRotationAnimation.hasScreenshot()) {//5 启动冻结时候设置的动画
if (DEBUG_ORIENTATION) Slog.i(TAG_WM, "**** Dismissing screen rotation animation");
// TODO(multidisplay): rotation on main screen only.
DisplayInfo displayInfo = displayContent.getDisplayInfo();
// Get rotation animation again, with new top window
boolean isDimming = displayContent.isDimming();
if (!mPolicy.validateRotationAnimationLw(mExitAnimId, mEnterAnimId, isDimming)) {
mExitAnimId = mEnterAnimId = 0;
}
//6.1 dismiss成功后执行动画
if (screenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
getTransitionAnimationScaleLocked(), displayInfo.logicalWidth,
displayInfo.logicalHeight, mExitAnimId, mEnterAnimId)) {
scheduleAnimationLocked();
} else {
//6.2 dismiss不成功结束动画
screenRotationAnimation.kill();
mAnimator.setScreenRotationAnimationLocked(displayId, null);
updateRotation = true;
}
} else {// 6.3 不支持自定义动画什么都不做
if (screenRotationAnimation != null) {
screenRotationAnimation.kill();
mAnimator.setScreenRotationAnimationLocked(displayId, null);
}
updateRotation = true;
}
//7 恢复接收input事件
mInputMonitor.thawInputDispatchingLw();
boolean configChanged;
// While the display is frozen we don't re-compute the orientation
// to avoid inconsistent states. However, something interesting
// could have actually changed during that time so re-evaluate it
// now to catch that.
// 8 根据app更新方向
configChanged = updateOrientationFromAppTokensLocked(false);
// A little kludge: a lot could have happened while the
// display was frozen, so now that we are coming back we
// do a gc so that any remote references the system
// processes holds on others can be released if they are
// no longer needed.
// 9 进行gc
mH.removeMessages(H.FORCE_GC);
mH.sendEmptyMessageDelayed(H.FORCE_GC, 2000);
//10 释放weak lock
mScreenFrozenLock.release();
//11 更新方向
if (updateRotation) {
if (DEBUG_ORIENTATION) Slog.d(TAG_WM, "Performing post-rotate rotation");
configChanged |= updateRotationUncheckedLocked(false);
}
//12通知
if (configChanged) {
mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
}
}
这里我们关心的是ScreenRotationAnimation 关闭和动画执行的过程
public boolean dismiss(SurfaceSession session, long maxAnimationDuration,
float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) {
if (DEBUG_STATE) Slog.v(TAG, "Dismiss!");
if (mSurfaceControl == null) { //1 没有创建surface返回
// Can't do animation.
return false;
}
if (!mStarted) { //开启动画
startAnimation(session, maxAnimationDuration, animationScale, finalWidth, finalHeight,
true, exitAnim, enterAnim);
}
if (!mStarted) {
return false;
}
if (DEBUG_STATE) Slog.v(TAG, "Setting mFinishAnimReady = true");
mFinishAnimReady = true; //结束动画开始
return true;
}
动画的初始化都在startAnimation函数中
/**
* Returns true if animating.
*/
private boolean startAnimation(SurfaceSession session, long maxAnimationDuration,
float animationScale, int finalWidth, int finalHeight, boolean dismissing,
int exitAnim, int enterAnim) {
if (mSurfaceControl == null) {
// Can't do animation.
return false;
}
if (mStarted) {
return true;
}
mStarted = true;
boolean firstStart = false;
// Figure out how the screen has moved from the original rotation.
int delta = DisplayContent.deltaRotation(mCurRotation, mOriginalRotation);
if (TWO_PHASE_ANIMATION && mFinishExitAnimation == null
&& (!dismissing || delta != Surface.ROTATION_0)) {
if (DEBUG_STATE) Slog.v(TAG, "Creating start and finish animations");
firstStart = true;
mStartExitAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_start_exit);
mStartEnterAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_start_enter);
if (USE_CUSTOM_BLACK_FRAME) {
mStartFrameAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_start_frame);
}
mFinishExitAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_finish_exit);
mFinishEnterAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_finish_enter);
if (USE_CUSTOM_BLACK_FRAME) {
mFinishFrameAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_finish_frame);
}
}
if (DEBUG_STATE) Slog.v(TAG, "Rotation delta: " + delta + " finalWidth="
+ finalWidth + " finalHeight=" + finalHeight
+ " origWidth=" + mOriginalWidth + " origHeight=" + mOriginalHeight);
//2 加载动画
final boolean customAnim;
if (exitAnim != 0 && enterAnim != 0) {
customAnim = true;
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, exitAnim);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, enterAnim);
} else {
customAnim = false;
switch (delta) {
case Surface.ROTATION_0:
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_0_exit);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_0_enter);
if (USE_CUSTOM_BLACK_FRAME) {
mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_0_frame);
}
break;
case Surface.ROTATION_90:
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_plus_90_exit);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_plus_90_enter);
if (USE_CUSTOM_BLACK_FRAME) {
mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_plus_90_frame);
}
break;
case Surface.ROTATION_180:
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_180_exit);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_180_enter);
if (USE_CUSTOM_BLACK_FRAME) {
mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_180_frame);
}
break;
case Surface.ROTATION_270:
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_minus_90_exit);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_minus_90_enter);
if (USE_CUSTOM_BLACK_FRAME) {
mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_minus_90_frame);
}
break;
}
}
// Initialize the animations. This is a hack, redefining what "parent"
// means to allow supplying the last and next size. In this definition
// "%p" is the original (let's call it "previous") size, and "%" is the
// screen's current/new size.
if (TWO_PHASE_ANIMATION && firstStart) {
// Compute partial steps between original and final sizes. These
// are used for the dimensions of the exiting and entering elements,
// so they are never stretched too significantly.
final int halfWidth = (finalWidth + mOriginalWidth) / 2;
final int halfHeight = (finalHeight + mOriginalHeight) / 2;
if (DEBUG_STATE) Slog.v(TAG, "Initializing start and finish animations");
mStartEnterAnimation.initialize(finalWidth, finalHeight,
halfWidth, halfHeight);
mStartExitAnimation.initialize(halfWidth, halfHeight,
mOriginalWidth, mOriginalHeight);
mFinishEnterAnimation.initialize(finalWidth, finalHeight,
halfWidth, halfHeight);
mFinishExitAnimation.initialize(halfWidth, halfHeight,
mOriginalWidth, mOriginalHeight);
if (USE_CUSTOM_BLACK_FRAME) {
mStartFrameAnimation.initialize(finalWidth, finalHeight,
mOriginalWidth, mOriginalHeight);
mFinishFrameAnimation.initialize(finalWidth, finalHeight,
mOriginalWidth, mOriginalHeight);
}
}
mRotateEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
mRotateExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
if (USE_CUSTOM_BLACK_FRAME) {
mRotateFrameAnimation.initialize(finalWidth, finalHeight, mOriginalWidth,
mOriginalHeight);
}
mAnimRunning = false;
mFinishAnimReady = false;
mFinishAnimStartTime = -1;
if (TWO_PHASE_ANIMATION && firstStart) {
mStartExitAnimation.restrictDuration(maxAnimationDuration);
mStartExitAnimation.scaleCurrentDuration(animationScale);
mStartEnterAnimation.restrictDuration(maxAnimationDuration);
mStartEnterAnimation.scaleCurrentDuration(animationScale);
mFinishExitAnimation.restrictDuration(maxAnimationDuration);
mFinishExitAnimation.scaleCurrentDuration(animationScale);
mFinishEnterAnimation.restrictDuration(maxAnimationDuration);
mFinishEnterAnimation.scaleCurrentDuration(animationScale);
if (USE_CUSTOM_BLACK_FRAME) {
mStartFrameAnimation.restrictDuration(maxAnimationDuration);
mStartFrameAnimation.scaleCurrentDuration(animationScale);
mFinishFrameAnimation.restrictDuration(maxAnimationDuration);
mFinishFrameAnimation.scaleCurrentDuration(animationScale);
}
}
//3 设置动画属性
mRotateExitAnimation.restrictDuration(maxAnimationDuration);
mRotateExitAnimation.scaleCurrentDuration(animationScale);
mRotateEnterAnimation.restrictDuration(maxAnimationDuration);
mRotateEnterAnimation.scaleCurrentDuration(animationScale);
if (USE_CUSTOM_BLACK_FRAME) {
mRotateFrameAnimation.restrictDuration(maxAnimationDuration);
mRotateFrameAnimation.scaleCurrentDuration(animationScale);
}
final int layerStack = mDisplayContent.getDisplay().getLayerStack();
if (USE_CUSTOM_BLACK_FRAME && mCustomBlackFrame == null) {
if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
TAG_WM,
">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation");
SurfaceControl.openTransaction();
// Compute the transformation matrix that must be applied
// the the black frame to make it stay in the initial position
// before the new screen rotation. This is different than the
// snapshot transformation because the snapshot is always based
// of the native orientation of the screen, not the orientation
// we were last in.
createRotationMatrix(delta, mOriginalWidth, mOriginalHeight, mFrameInitialMatrix);
try {
Rect outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1,
mOriginalWidth*2, mOriginalHeight*2);
Rect inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
mCustomBlackFrame = new BlackFrame(session, outer, inner,
SCREEN_FREEZE_LAYER_CUSTOM, layerStack, false);
mCustomBlackFrame.setMatrix(mFrameInitialMatrix);
} catch (OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate black surface", e);
} finally {
SurfaceControl.closeTransaction();
if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
TAG_WM,
"<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
}
}
if (!customAnim && mExitingBlackFrame == null) {
if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
TAG_WM,
">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation");
SurfaceControl.openTransaction();
try {
// Compute the transformation matrix that must be applied
// the the black frame to make it stay in the initial position
// before the new screen rotation. This is different than the
// snapshot transformation because the snapshot is always based
// of the native orientation of the screen, not the orientation
// we were last in.
createRotationMatrix(delta, mOriginalWidth, mOriginalHeight, mFrameInitialMatrix);
final Rect outer;
final Rect inner;
if (mForceDefaultOrientation) {
// Going from a smaller Display to a larger Display, add curtains to sides
// or top and bottom. Going from a larger to smaller display will result in
// no BlackSurfaces being constructed.
outer = mCurrentDisplayRect;
inner = mOriginalDisplayRect;
} else {
outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1,
mOriginalWidth*2, mOriginalHeight*2);
inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
}
mExitingBlackFrame = new BlackFrame(session, outer, inner,
SCREEN_FREEZE_LAYER_EXIT, layerStack, mForceDefaultOrientation);
mExitingBlackFrame.setMatrix(mFrameInitialMatrix);
} catch (OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate black surface", e);
} finally {
SurfaceControl.closeTransaction();
if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
TAG_WM,
"<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
}
}
if (customAnim && mEnteringBlackFrame == null) {
if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
TAG_WM,
">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation");
SurfaceControl.openTransaction();
//4 插入一个黑色的layer
try {
Rect outer = new Rect(-finalWidth*1, -finalHeight*1,
finalWidth*2, finalHeight*2);
Rect inner = new Rect(0, 0, finalWidth, finalHeight);
mEnteringBlackFrame = new BlackFrame(session, outer, inner,
SCREEN_FREEZE_LAYER_ENTER, layerStack, false);
} catch (OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate black surface", e);
} finally {
SurfaceControl.closeTransaction();
if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
TAG_WM,
"<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
}
}
return true;
}
scheduleAnimationLocked函数会触发动画执行
/** Note that Locked in this case is on mLayoutToAnim */
void scheduleAnimationLocked() {
if (!mAnimationScheduled) {
mAnimationScheduled = true;
mChoreographer.postFrameCallback(mAnimator.mAnimationFrameCallback);
}
}
动画执行的过程在WindowAnimator类中,是动画执行的引擎. animateLocked函数的第一段就是动画执行的过程
SurfaceControl.openTransaction();
SurfaceControl.setAnimationTransaction();
try {
final int numDisplays = mDisplayContentsAnimators.size();
for (int i = 0; i < numDisplays; i++) {
final int displayId = mDisplayContentsAnimators.keyAt(i);
updateAppWindowsLocked(displayId); // 1 执行app transaction动画
DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
final ScreenRotationAnimation screenRotationAnimation =
displayAnimator.mScreenRotationAnimation; //2 转屏动画
if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) { // 如果有需要执行的动画
removeMultiWindowAnimationLocked(displayAnimator);//3干掉分屏动画
if (screenRotationAnimation.stepAnimationLocked(mCurrentTime)) { //4执行冻结屏幕动画
//5 执行成功
setAnimating(true);
} else {
//6 执行完成更新状态
mBulkUpdateParams |= SET_UPDATE_ROTATION;
screenRotationAnimation.kill(); //7 结束动画
displayAnimator.mScreenRotationAnimation = null;
//TODO (multidisplay): Accessibility supported only for the default display.
if (mService.mAccessibilityController != null
&& displayId == Display.DEFAULT_DISPLAY) {
// We just finished rotation animation which means we did not
// anounce the rotation and waited for it to end, announce now.
mService.mAccessibilityController.onRotationChangedLocked(
mService.getDefaultDisplayContentLocked(), mService.mRotation);
}
}
}
// Update animations of all applications, including those
// associated with exiting/removed apps
updateWindowsLocked(displayId);
WindowAnimatorInjector.updateLockDeviceWindowLocked(displayId, mService);
updateWallpaperLocked(displayId);
final WindowList windows = mService.getWindowListLocked(displayId);
final int N = windows.size();
for (int j = 0; j < N; j++) {
windows.get(j).mWinAnimator.prepareSurfaceLocked(true);
}
}
上面冻结动画执行过程很简单,我们来看下具体动画的执行过程
public boolean stepAnimationLocked(long now) {
if (!hasAnimations()) { //1 不包含动画直接返回
if (DEBUG_STATE) Slog.v(TAG, "Step: no animations running");
mFinishAnimReady = false;
return false;
}
if (!mAnimRunning) { //2 首次执行
if (DEBUG_STATE) Slog.v(TAG, "Step: starting start, finish, rotate");
//3 设置一些动画开始时间
if (TWO_PHASE_ANIMATION) {
if (mStartEnterAnimation != null) {
mStartEnterAnimation.setStartTime(now);
}
if (mStartExitAnimation != null) {
mStartExitAnimation.setStartTime(now);
}
if (mFinishEnterAnimation != null) {
mFinishEnterAnimation.setStartTime(0);
}
if (mFinishExitAnimation != null) {
mFinishExitAnimation.setStartTime(0);
}
}
if (USE_CUSTOM_BLACK_FRAME) {
if (mStartFrameAnimation != null) {
mStartFrameAnimation.setStartTime(now);
}
if (mFinishFrameAnimation != null) {
mFinishFrameAnimation.setStartTime(0);
}
if (mRotateFrameAnimation != null) {
mRotateFrameAnimation.setStartTime(now);
}
}
if (mRotateEnterAnimation != null) {
mRotateEnterAnimation.setStartTime(now);
}
if (mRotateExitAnimation != null) {
mRotateExitAnimation.setStartTime(now);
}
//3 表示动画开启,mHalfwayPoint表示开始一半的时间
mAnimRunning = true;
mHalfwayPoint = now + mRotateEnterAnimation.getDuration() / 2;
}
return stepAnimation(now);
}
下面来分析setpAnimation
private boolean stepAnimation(long now) {
if (now > mHalfwayPoint) { //1 大于一半时间设置为Long.MAX_VALUE,可以看下一半时间的时候做啥
mHalfwayPoint = Long.MAX_VALUE;
}
if (mFinishAnimReady && mFinishAnimStartTime < 0) { //2设置开始执行时间
if (DEBUG_STATE) Slog.v(TAG, "Step: finish anim now ready");
mFinishAnimStartTime = now;
}
if (TWO_PHASE_ANIMATION) { //3 二相位的动画执行
mMoreStartExit = false;
if (mStartExitAnimation != null) {
mMoreStartExit = mStartExitAnimation.getTransformation(now, mStartExitTransformation);
if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start exit: " + mStartExitTransformation);
}
mMoreStartEnter = false;
if (mStartEnterAnimation != null) {
mMoreStartEnter = mStartEnterAnimation.getTransformation(now, mStartEnterTransformation);
if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start enter: " + mStartEnterTransformation);
}
}
if (USE_CUSTOM_BLACK_FRAME) {
mMoreStartFrame = false;
if (mStartFrameAnimation != null) { // 4根据时间从开始动画中获取矩阵
mMoreStartFrame = mStartFrameAnimation.getTransformation(now, mStartFrameTransformation);
if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start frame: " + mStartFrameTransformation);
}
}
long finishNow = mFinishAnimReady ? (now - mFinishAnimStartTime) : 0;
if (DEBUG_STATE) Slog.v(TAG, "Step: finishNow=" + finishNow);
if (TWO_PHASE_ANIMATION) { //5 二相位计数动画动画处理
mMoreFinishExit = false;
if (mFinishExitAnimation != null) {
mMoreFinishExit = mFinishExitAnimation.getTransformation(finishNow, mFinishExitTransformation);
if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish exit: " + mFinishExitTransformation);
}
mMoreFinishEnter = false;
if (mFinishEnterAnimation != null) { //5.1 结束动画中获取矩阵
mMoreFinishEnter = mFinishEnterAnimation.getTransformation(finishNow, mFinishEnterTransformation);
if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish enter: " + mFinishEnterTransformation);
}
}
if (USE_CUSTOM_BLACK_FRAME) { //6 结束动画中获取矩阵
mMoreFinishFrame = false;
if (mFinishFrameAnimation != null) {
mMoreFinishFrame = mFinishFrameAnimation.getTransformation(finishNow, mFinishFrameTransformation);
if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish frame: " + mFinishFrameTransformation);
}
}
mMoreRotateExit = false;
if (mRotateExitAnimation != null) { //7 从旋转离开的动画中获取矩阵
mMoreRotateExit = mRotateExitAnimation.getTransformation(now, mRotateExitTransformation);
if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate exit: " + mRotateExitTransformation);
}
mMoreRotateEnter = false;
if (mRotateEnterAnimation != null) {
mMoreRotateEnter = mRotateEnterAnimation.getTransformation(now, mRotateEnterTransformation);
if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate enter: " + mRotateEnterTransformation);
}
if (USE_CUSTOM_BLACK_FRAME) { //8 黑屏动画中获取矩阵
mMoreRotateFrame = false;
if (mRotateFrameAnimation != null) {
mMoreRotateFrame = mRotateFrameAnimation.getTransformation(now, mRotateFrameTransformation);
if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate frame: " + mRotateFrameTransformation);
}
}
//9 结束的处理
if (!mMoreRotateExit && (!TWO_PHASE_ANIMATION || (!mMoreStartExit && !mMoreFinishExit))) {
if (TWO_PHASE_ANIMATION) {
if (mStartExitAnimation != null) {
if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing start exit anim!");
mStartExitAnimation.cancel();
mStartExitAnimation = null;
mStartExitTransformation.clear();
}
if (mFinishExitAnimation != null) {
if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing finish exit anim!");
mFinishExitAnimation.cancel();
mFinishExitAnimation = null;
mFinishExitTransformation.clear();
}
}
if (mRotateExitAnimation != null) {
if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing rotate exit anim!");
mRotateExitAnimation.cancel();
mRotateExitAnimation = null;
mRotateExitTransformation.clear();
}
}
if (!mMoreRotateEnter && (!TWO_PHASE_ANIMATION || (!mMoreStartEnter && !mMoreFinishEnter))) {
if (TWO_PHASE_ANIMATION) {
if (mStartEnterAnimation != null) {
if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing start enter anim!");
mStartEnterAnimation.cancel();
mStartEnterAnimation = null;
mStartEnterTransformation.clear();
}
if (mFinishEnterAnimation != null) {
if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing finish enter anim!");
mFinishEnterAnimation.cancel();
mFinishEnterAnimation = null;
mFinishEnterTransformation.clear();
}
}
if (mRotateEnterAnimation != null) {
if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing rotate enter anim!");
mRotateEnterAnimation.cancel();
mRotateEnterAnimation = null;
mRotateEnterTransformation.clear();
}
}
if (USE_CUSTOM_BLACK_FRAME && !mMoreStartFrame && !mMoreRotateFrame && !mMoreFinishFrame) {
if (mStartFrameAnimation != null) {
if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, clearing start frame anim!");
mStartFrameAnimation.cancel();
mStartFrameAnimation = null;
mStartFrameTransformation.clear();
}
if (mFinishFrameAnimation != null) {
if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, clearing finish frame anim!");
mFinishFrameAnimation.cancel();
mFinishFrameAnimation = null;
mFinishFrameTransformation.clear();
}
if (mRotateFrameAnimation != null) {
if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, clearing rotate frame anim!");
mRotateFrameAnimation.cancel();
mRotateFrameAnimation = null;
mRotateFrameTransformation.clear();
}
}
mExitTransformation.set(mRotateExitTransformation);
mEnterTransformation.set(mRotateEnterTransformation);
if (TWO_PHASE_ANIMATION) {
mExitTransformation.compose(mStartExitTransformation);
mExitTransformation.compose(mFinishExitTransformation);
mEnterTransformation.compose(mStartEnterTransformation);
mEnterTransformation.compose(mFinishEnterTransformation);
}
if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final exit: " + mExitTransformation);
if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final enter: " + mEnterTransformation);
if (USE_CUSTOM_BLACK_FRAME) {
//mFrameTransformation.set(mRotateExitTransformation);
//mFrameTransformation.compose(mStartExitTransformation);
//mFrameTransformation.compose(mFinishExitTransformation);
mFrameTransformation.set(mRotateFrameTransformation);
mFrameTransformation.compose(mStartFrameTransformation);
mFrameTransformation.compose(mFinishFrameTransformation);
mFrameTransformation.getMatrix().preConcat(mFrameInitialMatrix);
if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final frame: " + mFrameTransformation);
}
// 10 返回是否还有更多动画:条件是其中一个动画结束
final boolean more = (TWO_PHASE_ANIMATION
&& (mMoreStartEnter || mMoreStartExit || mMoreFinishEnter || mMoreFinishExit))
|| (USE_CUSTOM_BLACK_FRAME
&& (mMoreStartFrame || mMoreRotateFrame || mMoreFinishFrame))
|| mMoreRotateEnter || mMoreRotateExit
|| !mFinishAnimReady;
// 11设置最终矩阵
mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix);
if (DEBUG_STATE) Slog.v(TAG, "Step: more=" + more);
return more;
}
到这里来看冻屏其实还是很简单的,只不过是截取图片显示出来,到冻结屏幕结束时候执行一个渐变动画