1、触发屏幕旋转流程
更多内容qqun:422901085 https://ke.qq.com/course/5992266#term_id=106217431 触发流程,这里我先只考虑正常窗手机传感器检测到了有旋转然后触发横竖屏情况,为了方便这里需要对相关的PROTO日志打开: 具体如下: adb shell wm logging enable-text WM_DEBUG_ORIENTATION WM_DEBUG_STATES WM_DEBUG_CONFIGURATION 最主要这里一定要WM_DEBUG_ORIENTATION,它就是专门来打印相关的旋转屏幕信息,开启屏幕自动旋转,然后进入一个会有旋转屏幕现象的Activity,旋转抓取日志:
04-05 16:16:40.127 565 583 V WindowManager: onProposedRotationChanged, rotation=1
04-05 16:16:40.129 565 583 V WindowManager: updateRotationUnchecked: alwaysSendConfiguration=false forceRelayout=false
04-05 16:16:40.129 565 583 V WindowManager: rotationForOrientation(orient=SCREEN_ORIENTATION_UNSPECIFIED (-1), last=ROTATION_0 (0)); user=ROTATION_0 (0)
04-05 16:16:40.129 565 583 V WindowManager: Computed rotation=ROTATION_90 (1) for display id=0 based on lastOrientation=SCREEN_ORIENTATION_UNSPECIFIED (-1) and oldRotation=ROTATION_0 (0)
04-05 16:16:40.130 565 583 V WindowManager: Display id=0 selected orientation SCREEN_ORIENTATION_UNSPECIFIED (-1), got rotation ROTATION_90 (1)
04-05 16:16:40.130 565 583 V WindowManager: Display id=0 rotation changed to 1 from 0, lastOrientation=-1
04-05 16:16:40.136 565 583 D WindowManager: startFreezingDisplayLocked: exitAnim=0 enterAnim=0 called by com.android.server.wm.WindowManagerService.startFreezingDisplay:6038 com.android.server.wm.WindowManagerService.startFreezingDisplay:6019 com.android.server.wm.DisplayRotation.prepareNormalRotationAnimation:619 com.android.server.wm.DisplayRotation.updateRotationUnchecked:536 com.android.server.wm.DisplayContent.updateRotationUnchecked:1960 com.android.server.wm.WindowManagerService.updateRotationUnchecked:4255 com.android.server.wm.WindowManagerService.updateRotation:4236 com.android.server.wm.DisplayRotation$OrientationListener.onProposedRotationChanged:1596
这里面就其实已经有对应的一个堆栈打印了,都不需要我们额外再自己加什么堆栈日志,从最后的startFreezingDisplayLocked来看堆栈: com.android.server.wm.WindowManagerService.startFreezingDisplay:6019 com.android.server.wm.DisplayRotation.prepareNormalRotationAnimation:619 com.android.server.wm.DisplayRotation.updateRotationUnchecked:536 com.android.server.wm.DisplayContent.updateRotationUnchecked:1960 com.android.server.wm.WindowManagerService.updateRotationUnchecked:4255 com.android.server.wm.WindowManagerService.updateRotation:4236 com.android.server.wm.DisplayRotation
O
r
i
e
n
t
a
t
i
o
n
L
i
s
t
e
n
e
r
.
o
n
P
r
o
p
o
s
e
d
R
o
t
a
t
i
o
n
C
h
a
n
g
e
d
:
1596
p
r
e
p
a
r
e
N
o
r
m
a
l
R
o
t
a
t
i
o
n
A
n
i
m
a
t
i
o
n
其实就是代表要准备好正常的旋转动画,再继续跟踪发现也就是
D
i
s
p
l
a
y
R
o
t
a
t
i
o
n
OrientationListener.onProposedRotationChanged:1596 prepareNormalRotationAnimation其实就是代表要准备好正常的旋转动画,再继续跟踪发现 也就是DisplayRotation
OrientationListener.onProposedRotationChanged:1596prepareNormalRotationAnimation其实就是代表要准备好正常的旋转动画,再继续跟踪发现也就是DisplayRotationOrientationListener.onProposedRotationChanged触发了旋转屏幕动画的 那么它自己又是被谁触发的呢? 这里其实可以考虑把Proto堆栈改长一点获取如下
04-05 16:16:40.160 565 583 I WindowManager: at com.android.server.wm.DisplayRotation$OrientationListener.onProposedRotationChanged(DisplayRotation.java:1596)
04-05 16:16:40.160 565 583 I WindowManager: at com.android.server.wm.WindowOrientationListener$AccelSensorJudge.onSensorChanged(WindowOrientationListener.java:872)
04-05 16:16:40.160 565 583 I WindowManager: at android.hardware.SystemSensorManager$SensorEventQueue.dispatchSensorEvent(SystemSensorManager.java:894)
04-05 16:16:40.160 565 583 I WindowManager: at android.os.MessageQueue.nativePollOnce(Native Method)
04-05 16:16:40.160 565 583 I WindowManager: at android.os.MessageQueue.next(MessageQueue.java:335)
04-05 16:16:40.160 565 583 I WindowManager: at android.os.Looper.loopOnce(Looper.java:161)
04-05 16:16:40.160 565 583 I WindowManager: at android.os.Looper.loop(Looper.java:288)
04-05 16:16:40.160 565 583 I WindowManager: at android.os.HandlerThread.run(HandlerThread.java:67)
04-05 16:16:40.160 565 583 I WindowManager: at com.android.server.ServiceThread.run(ServiceThread.java:44)
其实是SystemSensorManager$SensorEventQueue.dispatchSensorEvent触发调用过来的,反正大家清楚旋转屏幕触发源头就是sensor就行。然后跟着这个堆栈一直追既可以到startFreezingDisplayLocked,这个方法代表是冻屏,一般要进行屏幕整个旋转,肯定需要冻屏方便让我们整体画面进行动画
上面我们只是简单知道了动画类ScreenRotationAnimation创建的调用流程,其实还是有比较多的疑问的: 1、难道任何画面都要进行旋转动画么? 哈哈这个其实可以对比一个画面会旋转的Activity和画面不旋转的activity,从日志中获得一些答案 如果画面会旋转打印如下:
04-05 16:16:40.129 565 583 V WindowManager: rotationForOrientation(orient=SCREEN_ORIENTATION_UNSPECIFIED (-1), last=ROTATION_0 (0)); user=ROTATION_0 (0)
04-05 16:16:40.129 565 583 V WindowManager: Computed rotation=ROTATION_90 (1) for display id=0 based on lastOrientation=SCREEN_ORIENTATION_UNSPECIFIED (-1) and oldRotation=ROTATION_0 (0)
04-05 16:16:40.130 565 583 V WindowManager: Display id=0 selected orientation SCREEN_ORIENTATION_UNSPECIFIED (-1), got rotation ROTATION_90 (1)
04-05 16:16:40.130 565 583 V WindowManager: Display id=0 rotation changed to 1 from 0, lastOrientation=-1
如果画面不会旋转打印如下:
04-05 21:41:42.044 563 581 V WindowManager: onProposedRotationChanged, rotation=1
04-05 21:41:42.044 563 581 V WindowManager: updateRotationUnchecked: alwaysSendConfiguration=false forceRelayout=false
04-05 21:41:42.045 563 581 V WindowManager: rotationForOrientation(orient=SCREEN_ORIENTATION_NOSENSOR (5), last=ROTATION_0 (0)); user=ROTATION_0 (0)
04-05 21:41:42.046 563 581 V WindowManager: Computed rotation=ROTATION_0 (0) for display id=0 based on lastOrientation=SCREEN_ORIENTATION_NOSENSOR (5) and oldRotation=ROTATION_0 (0)
04-05 21:41:42.046 563 581 V WindowManager: Display id=0 selected orientation SCREEN_ORIENTATION_NOSENSOR (5), got rotation ROTATION_0 (0)
对比明显发现画面不会旋转没有发打印WindowManager: Display id=0 rotation changed , 代码其实如下:
有打印即代表rotation有变化,但是他们物理操作都是一样,这个时候都是横屏了 再往上看对比日志: 有旋转情况: V WindowManager: Computed rotation=ROTATION_90 (1) for display id=0 based on lastOrientation=SCREEN_ORIENTATION_UNSPECIFIED (-1) and oldRotation=ROTATION_0 (0) 这里直接计算为了ROTATION_90,即代表可以旋转,新角度是ROTATION_90 五旋转情况: V WindowManager: Computed rotation=ROTATION_0 (0) for display id=0 based on lastOrientation=SCREEN_ORIENTATION_NOSENSOR (5) and oldRotation=ROTATION_0 (0) 这里依旧是ROTATION_0,和以前oldRotation属于一样故不需要旋转 但他们唯一差别lastOrientation=SCREEN_ORIENTATION_NOSENSOR lastOrientation=SCREEN_ORIENTATION_UNSPECIFIED (-1) 这个其实就是和activity自己进行设置的一个属性,可以manifest也可以代码指定,所以说应用的设置也会影响是否触发旋转
2、难道传感器一直运行么?我要是没有开屏幕自动旋转呢?如果还工作是不是不合理 这个我可以看看关闭状态栏的中的屏幕自动旋转开关 但是关闭了,虽然没看到activity旋转了,依然旋转屏幕发现有如下打印: 04-05 21:41:42.044 563 581 V WindowManager: onProposedRotationChanged, rotation=1 有这句打印说明传感器就一定工作着,那这个为啥,要怎么才可以关闭传感器? 其实这里我们可以从frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java的 needSensorRunning开始分析:
private boolean needSensorRunning() {
//省略
//我们属于这种锁定情况
if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
// If the setting for using the sensor by default is enabled, then
// we will always leave it on. Note that the user could go to
// a window that forces an orientation that does not use the
// sensor and in theory we could turn it off... however, when next
// turning it on we won't have a good value for the current
// orientation for a little bit, which can cause orientation
// changes to lag, so we'd like to keep it always on. (It will
// still be turned off when the screen is off.)
// When locked we can provide rotation suggestions users can approve to change the
// current screen rotation. To do this the sensor needs to be running.
//mSupportAutoRotation一般都是true系统直接指定,mShowRotationSuggestions这个是由对应setting值进行指定
return mSupportAutoRotation &&
mShowRotationSuggestions == Settings.Secure.SHOW_ROTATION_SUGGESTIONS_ENABLED;
}
return mSupportAutoRotation;
}
说白了就是还有个setting值 public static final String SHOW_ROTATION_SUGGESTIONS = “show_rotation_suggestions”; 也是为true 即是否显示旋转建议,可以把它手动变为0既可以
2、屏幕动画的截图部分创建位置摆放
ScreenRotationAnimation(DisplayContent displayContent, @Surface.Rotation int originalRotation) {
mService = displayContent.mWmService;
mContext = mService.mContext;
mDisplayContent = displayContent;
final Rect currentBounds = displayContent.getBounds();
final int width = currentBounds.width();
final int height = currentBounds.height();
// Screenshot does NOT include rotation!
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
final int realOriginalRotation = displayInfo.rotation;
mOriginalRotation = originalRotation;
//大家注意这里一般delta为0,因为originalRotation和realOriginalRotation其实都是刚刚取出的最新,创建时候其实还没有差异
final int delta = deltaRotation(originalRotation, realOriginalRotation);
final boolean flipped = delta == Surface.ROTATION_90 || delta == Surface.ROTATION_270;
mOriginalWidth = flipped ? height : width;//目前还是未旋转前宽高,这里做了保存方便后面做差异
mOriginalHeight = flipped ? width : height;
mSurfaceRotationAnimationController = new SurfaceRotationAnimationController();
// Check whether the current screen contains any secure content.
boolean isSecure = displayContent.hasSecureWindowOnScreen();
final int displayId = displayContent.getDisplayId();
final SurfaceControl.Transaction t = mService.mTransactionFactory.get();
try {
//进行截图
SurfaceControl.LayerCaptureArgs args =
new SurfaceControl.LayerCaptureArgs.Builder(displayContent.getSurfaceControl())
.setCaptureSecureLayers(true)
.setAllowProtected(true)
.setSourceCrop(new Rect(0, 0, width, height))
// Exclude rounded corner overlay from screenshot buffer. Rounded
// corner overlay windows are un-rotated during rotation animation
// for a seamless transition.
.setExcludeLayers(displayContent.findRoundedCornerOverlays())
.build();
SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
SurfaceControl.captureLayers(args);
//省略
//创建了RotationLayer的surfaceflinger图层
String name = "RotationLayer";
mScreenshotLayer = displayContent.makeOverlay()
.setName(name)
.setOpaque(true)
.setSecure(isSecure)
.setCallsite("ScreenRotationAnimation")
.setBLASTLayer()
.build();
//省略
t.show(mScreenshotLayer);
t.show(mBackColorSurface);
} catch (OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate freeze surface", e);
}
//省略
//一般都是相等,相当于啥也没干,因为此时还没有差异
if (originalRotation == realOriginalRotation) {
setRotation(t, realOriginalRotation);//这个地方因为角度一样,故这次调用不是关键
} else {
// If the given original rotation is different from real original display rotation,
// this is playing non-zero degree rotation animation without display rotation change,
// so the snapshot doesn't need to be transformed.
mCurRotation = realOriginalRotation;
mSnapshotInitialMatrix.reset();
setRotationTransform(t, mSnapshotInitialMatrix);
}
t.apply();
}
关键代码都有注释: 看到ScreenRotationAnimation构造最主要工作就是创建了一个截图的mScreenshotLayer,并且显示再最上面层级, 但是大家注意哈,这里的构造中setRotation其实没有干啥哈,因为角度还没有变化,这里大家要注意不要被网络其他文章带偏。 在屏幕旋转后摆放截图位置部分需要理解一点预备知识: 因为屏幕旋转,肯定显示位置要发生变化的具体如下图
注意: 真正的摆放截图位置的触发是由sendNewConfiguration里面触发的,这里才会有最新的rotation和新的rotation进行deta插值,具体调用堆栈如下:
04-05 16:16:40.644 565 585 I WindowManager: setRotation mOriginalRotation = 0 rotation = 1 delta =3
04-05 16:16:40.644 565 585 I WindowManager: java.lang.Exception
04-05 16:16:40.644 565 585 I WindowManager: at com.android.server.wm.ScreenRotationAnimation.setRotation(ScreenRotationAnimation.java:325)
04-05 16:16:40.644 565 585 I WindowManager: at com.android.server.wm.DisplayContent.applyRotation(DisplayContent.java:1999)
04-05 16:16:40.644 565 585 I WindowManager: at com.android.server.wm.DisplayContent.applyRotationAndFinishFixedRotation(DisplayContent.java:5951)
04-05 16:16:40.644 565 585 I WindowManager: at com.android.server.wm.DisplayContent.onRequestedOverrideConfigurationChanged(DisplayContent.java:5921)
04-05 16:16:40.644 565 585 I WindowManager: at com.android.server.wm.DisplayContent.performDisplayOverrideConfigUpdate(DisplayContent.java:5891)
04-05 16:16:40.644 565 585 I WindowManager: at com.android.server.wm.RootWindowContainer.dispatchConfigurationToChild(RootWindowContainer.java:640)
04-05 16:16:40.644 565 585 I WindowManager: at com.android.server.wm.RootWindowContainer.dispatchConfigurationToChild(RootWindowContainer.java:169)
04-05 16:16:40.644 565 585 I WindowManager: at com.android.server.wm.ConfigurationContainer.onConfigurationChanged(ConfigurationContainer.java:152)
04-05 16:16:40.644 565 585 I WindowManager: at com.android.server.wm.WindowContainer.onConfigurationChanged(WindowContainer.java:510)
04-05 16:16:40.644 565 585 I WindowManager: at com.android.server.wm.ActivityTaskManagerService.updateGlobalConfigurationLocked(ActivityTaskManagerService.java:4303)
04-05 16:16:40.644 565 585 I WindowManager: at com.android.server.wm.DisplayContent.updateDisplayOverrideConfigurationLocked(DisplayContent.java:5863)
04-05 16:16:40.644 565 585 I WindowManager: at com.android.server.wm.DisplayContent.updateDisplayOverrideConfigurationLocked(DisplayContent.java:5840)
04-05 16:16:40.644 565 585 I WindowManager: at com.android.server.wm.DisplayContent.sendNewConfiguration(DisplayContent.java:1442)
04-05 16:16:40.644 565 585 I WindowManager: at com.android.server.wm.DisplayRotation.continueRotation(DisplayRotation.java:606)
04-05 16:16:40.644 565 585 I WindowManager: at com.android.server.wm.DisplayRotation.-$$Nest$mcontinueRotation(Unknown Source:0)
04-05 16:16:40.644 565 585 I WindowManager: at com.android.server.wm.DisplayRotation$2.lambda$continueRotateDisplay$0(DisplayRotation.java:234)
04-05 16:16:40.644 565 585 I WindowManager: at com.android.server.wm.DisplayRotation$2$$ExternalSyntheticLambda0.accept(Unknown Source:10)
04-05 16:16:40.644 565 585 I WindowManager: at com.android.internal.util.function.pooled.PooledLambdaImpl.doInvoke(PooledLambdaImpl.java:295)
04-05 16:16:40.644 565 585 I WindowManager: at com.android.internal.util.function.pooled.PooledLambdaImpl.invoke(PooledLambdaImpl.java:204)
04-05 16:16:40.644 565 585 I WindowManager: at com.android.internal.util.function.pooled.OmniFunction.run(OmniFunction.java:97)
04-05 16:16:40.644 565 585 I WindowManager: at android.os.Handler.handleCallback(Handler.java:942)
04-05 16:16:40.644 565 585 I WindowManager: at android.os.Handler.dispatchMessage(Handler.java:99)
04-05 16:16:40.644 565 585 I WindowManager: at android.os.Looper.loopOnce(Looper.java:201)
04-05 16:16:40.644 565 585 I WindowManager: at android.os.Looper.loop(Looper.java:288)
04-05 16:16:40.644 565 585 I WindowManager: at android.os.HandlerThread.run(HandlerThread.java:67)
具体的代码:
public void setRotation(SurfaceControl.Transaction t, int rotation) {
mCurRotation = rotation;
//注意这里mOriginalRotation是0 代表0度代表是new参数,rotation是1 代表90度,rotation成为old参数
int delta = deltaRotation(rotation, mOriginalRotation);
RotationAnimationUtils.createRotationMatrix(delta, mOriginalWidth, mOriginalHeight,
mSnapshotInitialMatrix);
setRotationTransform(t, mSnapshotInitialMatrix);
}
//计算delta这里是new - old,根据传递来的所以0-1 = -1,4-1 = 3即270
/** @return the rotation needed to rotate from oldRotation to newRotation. */
@Rotation
public static int deltaRotation(@Rotation int oldRotation, @Rotation int newRotation) {
int delta = newRotation - oldRotation;
if (delta < 0) delta += 4;
return delta;
}
//根据delta计算出对应的matrix
public static void createRotationMatrix(int rotation, int width, int height, Matrix outMatrix) {
switch (rotation) {
case Surface.ROTATION_0:
outMatrix.reset();
break;
case Surface.ROTATION_90:
outMatrix.setRotate(90, 0, 0);
outMatrix.postTranslate(height, 0);
break;
case Surface.ROTATION_180:
outMatrix.setRotate(180, 0, 0);
outMatrix.postTranslate(width, height);
break;
case Surface.ROTATION_270://这里可以看出270度情况,有旋转还y位置平移
outMatrix.setRotate(270, 0, 0);
outMatrix.postTranslate(0, width);
break;
}
}
//这个主要把matrix对象转变程对应float传递到surfaceflinger
private void setRotationTransform(SurfaceControl.Transaction t, Matrix matrix) {
if (mScreenshotLayer == null) {
return;
}
matrix.getValues(mTmpFloats);
float x = mTmpFloats[Matrix.MTRANS_X];
float y = mTmpFloats[Matrix.MTRANS_Y];
t.setPosition(mScreenshotLayer, x, y);
t.setMatrix(mScreenshotLayer,
mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
t.setAlpha(mScreenshotLayer, (float) 1.0);
t.show(mScreenshotLayer);
}
3、屏幕动画的过程分析
什么时候开始启动屏幕动画呢?前面相当于都是构造相关类,和对画面进行矩阵位置旋转,还没有看到动画?这里我们用wms课程老方法,我们知道只要是动画一般都会创建对应的leash图层,看看leash堆栈:
04-05 16:16:41.723 565 586 I WindowManager: createAnimationLeash type = screen_rotation
04-05 16:16:41.723 565 586 I WindowManager: java.lang.Exception
04-05 16:16:41.723 565 586 I WindowManager: at com.android.server.wm.SurfaceAnimator.createAnimationLeash(SurfaceAnimator.java:458)
04-05 16:16:41.723 565 586 I WindowManager: at com.android.server.wm.SurfaceAnimator.startAnimation(SurfaceAnimator.java:184)
04-05 16:16:41.723 565 586 I WindowManager: at com.android.server.wm.SurfaceAnimator.startAnimation(SurfaceAnimator.java:213)
04-05 16:16:41.723 565 586 I WindowManager: at com.android.server.wm.ScreenRotationAnimation$SurfaceRotationAnimationController.startAnimation(ScreenRotationAnimation.java:697)
04-05 16:16:41.723 565 586 I WindowManager: at com.android.server.wm.ScreenRotationAnimation$SurfaceRotationAnimationController.startDisplayRotation(ScreenRotationAnimation.java:580)
04-05 16:16:41.723 565 586 I WindowManager: at com.android.server.wm.ScreenRotationAnimation$SurfaceRotationAnimationController.startScreenRotationAnimation(ScreenRotationAnimation.java:563)
04-05 16:16:41.723 565 586 I WindowManager: at com.android.server.wm.ScreenRotationAnimation.startAnimation(ScreenRotationAnimation.java:422)
04-05 16:16:41.723 565 586 I WindowManager: at com.android.server.wm.ScreenRotationAnimation.dismiss(ScreenRotationAnimation.java:440)
04-05 16:16:41.723 565 586 I WindowManager: at com.android.server.wm.WindowManagerService.doStopFreezingDisplayLocked(WindowManagerService.java:6157)
04-05 16:16:41.723 565 586 I WindowManager: at com.android.server.wm.WindowManagerService.stopFreezingDisplayLocked(WindowManagerService.java:6116)
04-05 16:16:41.723 565 586 I WindowManager: at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:890)
04-05 16:16:41.723 565 586 I WindowManager: at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:784)
04-05 16:16:41.723 565 586 I WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:177)
04-05 16:16:41.723 565 586 I WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:126)
04-05 16:16:41.723 565 586 I WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:115)
04-05 16:16:41.723 565 586 I WindowManager: at com.android.server.wm.WindowSurfacePlacer$Traverser.run(WindowSurfacePlacer.java:57)
04-05 16:16:41.723 565 586 I WindowManager: at android.os.Handler.handleCallback(Handler.java:942)
04-05 16:16:41.723 565 586 I WindowManager: at android.os.Handler.dispatchMessage(Handler.java:99)
04-05 16:16:41.723 565 586 I WindowManager: at android.os.Looper.loopOnce(Looper.java:201)
04-05 16:16:41.723 565 586 I WindowManager: at android.os.Looper.loop(Looper.java:288)
04-05 16:16:41.723 565 586 I WindowManager: at android.os.HandlerThread.run(HandlerThread.java:67)
04-05 16:16:41.723 565 586 I WindowManager: at com.android.server.ServiceThread.run(ServiceThread.java:44)
可以看得出这里其实performSurfacePlacementNoTrace,只要所有参与动画窗口都已经根据最新configration准备好了(具体关注后期文章专门分析解冻条件),开始会进行解冻,解冻时候调用ScreenRotationAnimation.dismiss方法进行对应的旋转屏幕动画的触发,下面主要来从dismiss开始看:
public boolean dismiss(SurfaceControl.Transaction t, long maxAnimationDuration,
float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) {
//判断是否已经启动,第一次肯定false
if (!mStarted) {
//进入调用startAnimation
startAnimation(t, maxAnimationDuration, animationScale, finalWidth, finalHeight,
exitAnim, enterAnim);
}
return true;
}
下面来看关键的startAnimation
rivate boolean startAnimation(SurfaceControl.Transaction t, long maxAnimationDuration,
float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) {
//启动标志变为true
mStarted = true;
// Figure out how the screen has moved from the original rotation.
int delta = deltaRotation(mCurRotation, mOriginalRotation);//前面已经介绍了
final boolean customAnim;//一般为false
if (exitAnim != 0 && enterAnim != 0) {
//省略
} else {//系统默认动画加载对应xml
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.rotation_animation_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;
}
}
//省略
if (customAnim) {
mSurfaceRotationAnimationController.startCustomAnimation();
} else {
//调用了startScreenRotationAnimation
mSurfaceRotationAnimationController.startScreenRotationAnimation();
}
return true;
}
下面来看startScreenRotationAnimation
void startScreenRotationAnimation() {
try {
mService.mSurfaceAnimationRunner.deferStartingAnimations();
//启动DiplayContent自身相关动画,其实这里对应的是前面Enter
mDisplayAnimator = startDisplayRotation();
//启动前面说的原来的竖屏截图动画,这里对应是前面的Exit
mScreenshotRotationAnimator = startScreenshotRotationAnimation();
//还有一个color,暂时忽略
startColorAnimation();
} finally {
mService.mSurfaceAnimationRunner.continueStartingAnimations();
}
}
private SurfaceAnimator startDisplayRotation() {
//注意因为这里不像之前有对应的windowcontainer,这里就要单独构造出对应的SurfaceAnimator.Animatable
return startAnimation(initializeBuilder()
//注意设置leash的parent是mDisplayContent的SurfaceControl,这里为啥单独设置这个呢?还是因为没有windowcontainer,所以无法getParent
.setAnimationLeashParent(mDisplayContent.getSurfaceControl())
//把自己surfacecontrol设置为WindowLayer,这个其实就是代表0-31层级的叶子容器
.setSurfaceControl(mDisplayContent.getWindowingLayer())
.setParentSurfaceControl(mDisplayContent.getSurfaceControl())
.setWidth(mDisplayContent.getSurfaceWidth())
.setHeight(mDisplayContent.getSurfaceHeight())
.build(),
createWindowAnimationSpec(mRotateEnterAnimation),
this::onAnimationEnd);
}
private SurfaceAnimator startScreenshotRotationAnimation() {
return startAnimation(initializeBuilder()
//设置surfacecontrol为mScreenshotLayer
.setSurfaceControl(mScreenshotLayer)
//设置parent为mDisplayContent.getOverlayLayer()
.setAnimationLeashParent(mDisplayContent.getOverlayLayer())
.build(),
createWindowAnimationSpec(mRotateExitAnimation),
this::onAnimationEnd);
}
好上面执行完基本就和之前窗口动画都一样了,这里我们放慢动画过程截取某一个阶段看看:
明显RotationLayer属于截图Layer,后面Activity属于DisplayContent的Layer,DisplayContent这个图层Layer执行动作是竖屏到横屏旋转,而ShotscreenLayer明显是又是横屏到竖屏的过程,具体可以看课程视频动画,这里blog就不上动画过程了
精彩文章
发表评论