做网站的微信号株洲seo推广
frameworks 之 屏幕旋转
- 1 初始化和传感器监听
- 2 旋转的判断,开始冻屏以及动画准备
- 2.1 旋转的判断
- 2.2 准备进退动画
- 2.3 屏幕冻结
- 2.4 通知systemUi,并等待回调
- 3 更新动画以及DisplayInfo
- 3.1 更新DisplayInfo 和 Configuration信息
- 3.2 通知更新
- 3.2.1 Application的通知
- 3.2.2 容器的大小通知
- 3.3 Activity界面更新
- 3.3.1 重建Activity
- 3.3.2 非重建
- 4 动画的播放
- 4.1 停止冻屏
- 4.1 播放动画
- 5 堆栈
- 5.1 更新当前app屏幕配置
- 5.2 传感器上报
- 5.3开始冻屏幕
- 5.4 创建旋转动画
- 5.5 冻结触发时机
讲解 屏幕旋转的起点到冻屏以及解冻的时机
涉及到的类如下
- frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java
- frameworks/base/services/java/com/android/server/SystemServer.java
- frameworks/base/services/core/java/com/android/server/wm/WindowOrientationListener.java
- frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
- frameworks/base/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
- frameworks/base/services/core/java/com/android/server/wm/TaskFragment.java
- frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
- frameworks/base/services/core/java/com/android/server/wm/WindowProcessController.java
- frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
- frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
- frameworks/base/services/core/java/com/android/server/wm/ConfigurationContainer.java
- frameworks/base/services/core/java/com/android/server/wm/WindowAnimator.java
- frameworks/base/core/jni/android_hardware_SensorManager.cpp
1 初始化和传感器监听
SystemServer 启动执行 startBootstrapServices 方法时候,就会启动对应的传感器监听
private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {...// 启动传感器服务t.traceBegin("StartSensorService");mSystemServiceManager.startService(SensorService.class);t.traceEnd(); }
DisplayContent 初始化的时候,会构造 DisplayRotation 类,该类主要负责监听和管控当前屏幕应用的旋转策略等。
DisplayContent(Display display, RootWindowContainer root) {// 初始化屏幕旋转相关,包括监听等mDisplayRotation = new DisplayRotation(mWmService, this);
}
而 DisplayRotation 的构造方法,
- 会判断是否默认屏幕,是的会创建对应的OrientationListener,该监听继承自windowOrientationListener
- 注册对应的SettingsObserver, 监听用户切换锁定屏幕的操作
DisplayRotation(...) {...// 如果是默认屏幕,创建对应的 OrientationListener,会有对应的监听if (isDefaultDisplay) {final Handler uiHandler = UiThread.getHandler();// OrientationListener继承windowOrientationListener,里面会初始化,// 有变化时候 SystemSensorManager 会触发dispatchSensorEvent 方法,// 而该方法又会触发该父类WindowOrientationListener的onSensorChanged,在onSensorChanged会进行判断是否改变,// 改变的话会调用子类即为OrientationListener的onProposedRotationChanged方法mOrientationListener = new OrientationListener(mContext, uiHandler);mOrientationListener.setCurrentRotation(mRotation);mSettingsObserver = new SettingsObserver(uiHandler);mSettingsObserver.observe();}
}
DisplayRotation 有一些比较重要的方法
- updateOrientation 方法更新对应的应用程序方向策略。
该方法每次当应用进入resume状态的时候,则会一次调用该方法(具体调用可以看堆栈第一个)
boolean updateOrientation(@ScreenOrientation int newOrientation, boolean forceUpdate) {// 更新当前APP的方向设置放到 mCurrentAppOrientationif (newOrientation == mLastOrientation && !forceUpdate) {return false;}mLastOrientation = newOrientation;if (newOrientation != mCurrentAppOrientation) {mCurrentAppOrientation = newOrientation;if (isDefaultDisplay) {// 有改变则注册或者移除对应的监听updateOrientationListenerLw();}}return updateRotationUnchecked(forceUpdate);}
- updateOrientationListenerLw 方法会根据当前的配置和系统设置,调用mOrientationListener 的 enable 或者disable 去移除或者注册对应的监听。 具体逻辑在 WindowOrientationListener基类。
private void updateOrientationListenerLw() {...boolean disable = true;...if (screenOnEarly&& (awake || mOrientationListener.shouldStayEnabledWhileDreaming())&& ((keyguardDrawComplete && windowManagerDrawComplete))) {if (needSensorRunning()) { // 判断是否需要运行disable = false;// Enable listener if not already enabled.if (!mOrientationListener.mEnabled) {...mOrientationListener.enable(true /* clearCurrentRotation */);}}}// Check if sensors need to be disabled.if (disable) {mOrientationListener.disable();}}
- needSensorRunning 会根据当前用户设置,判断是否需要监听
private boolean needSensorRunning() {...// 就算设置为屏幕锁定,但是有mSupportAutoRotation,也会返回true可用if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) {...return mSupportAutoRotation &&mShowRotationSuggestions == Settings.Secure.SHOW_ROTATION_SUGGESTIONS_ENABLED;}return mSupportAutoRotation;}
WindowOrientationListener 的构造方法,获取对应的SensorManager,实际为SystemSensorManager(继承这SensorManager), 并创建对应AccelSensorJudge,当调用enable的时候会将该监听通过 mSensorManager 注册给底层。
private WindowOrientationListener(Context context, Handler handler, int rate) {...// 获取对应的感应器管理类mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);..// enable的时候会调用 regiter注册该AccelSensorJudge监听if (mOrientationJudge == null) {mSensor = mSensorManager.getDefaultSensor(USE_GRAVITY_SENSOR? Sensor.TYPE_GRAVITY : Sensor.TYPE_ACCELEROMETER);if (mSensor != null) {// Create listener only if sensors do existmOrientationJudge = new AccelSensorJudge(context);}} }
注册
public void enable(boolean clearCurrentRotation) {synchronized (mLock) {...if (mSensor.getType() == Sensor.TYPE_ACCELEROMETER) {mSensorManager.registerListener(mOrientationJudge, mSensor, mRate, DEFAULT_BATCH_LATENCY, mHandler);} else {mSensorManager.registerListener(mOrientationJudge, mSensor, mRate, mHandler);}mEnabled = true;}}
当底层有变化的时候,android_hardware_SensorManager.handleEvent 接收对应的事件会通过 调用java层SystemSensorManager的 dispatchSensorEvent 方法。
virtual int handleEvent(int fd, int events, void* data) {JNIEnv* env = AndroidRuntime::getJNIEnv();ASensorEvent buffer[16];while ((n = q->read(buffer, 16)) > 0) {for (int i=0 ; i<n ; i++) {}else {...if (receiverObj.get()) {// 通知到java层env->CallVoidMethod(receiverObj.get(),gBaseEventQueueClassInfo.dispatchSensorEvent,buffer[i].sensor,mFloatScratch,status,buffer[i].timestamp);}}}mSensorQueue->sendAck(buffer, n);}}
而 SystemSensorManager 的 dispatchSensorEvent 方法,会调用之前注册进入的listener(AccelSensorJudge) 的 onSensorChanged 方法
protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy){...mListener.onSensorChanged(t);
}
查看 AccelSensorJudge的onSensorChanged 方法,会经过一系列判断,如果判断到方向跟之前的方向不一致,则调用 OrientationListener的onProposedRotationChanged 方法
public void onSensorChanged(SensorEvent event) {// Tell the listener.if (proposedRotation != oldProposedRotation && proposedRotation >= 0) {if (LOG) {Slog.v(TAG, "Proposed rotation changed! proposedRotation=" + proposedRotation+ ", oldProposedRotation=" + oldProposedRotation);}onProposedRotationChanged(proposedRotation);}}
OrientationListener 的onProposedRotationChanged 方法启动了一个任务
@Overridepublic void onProposedRotationChanged(int rotation) {ProtoLog.v(WM_DEBUG_ORIENTATION, "onProposedRotationChanged, rotation=%d", rotation);Runnable r = mRunnableCache.get(rotation, null);if (r == null) {r = new UpdateRunnable(rotation);mRunnableCache.put(rotation, r);}getHandler().post(r);}
该任务的 run 方法会调用 WMS的updateRotation,这样就开始进入屏幕旋转
public void run() {// Send interaction power boost to improve redraw performance.mService.mPowerManagerInternal.setPowerBoost(Boost.INTERACTION, 0);// 模式不是锁定屏幕的就会返回false,所以会执行下面updateRotation方法// 传进去的是 mCurrentAppOrientation 变量,表示if (isRotationChoicePossible(mCurrentAppOrientation)) {final boolean isValid = isValidRotationChoice(mRotation);sendProposedRotationChangeToStatusBarInternal(mRotation, isValid);} else {// 执行旋转mService.updateRotation(false /* alwaysSendConfiguration */,false /* forceRelayout */);}}
2 旋转的判断,开始冻屏以及动画准备
updateRotation 又会调用 updateRotationUnchecked 方法。该方法主要
- 遍历调用RootWindowContainer的displayContent,调用 updateRotationUnchecked 判断是否需要旋转
- 当有变化的时候,DisplayRotation 对应mIsWaitingForRemoteRotation 变量也为true。
private void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {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");// 进行对旋转的判断,判断是否需要旋转final boolean rotationChanged = displayContent.updateRotationUnchecked();...// 因为 mIsWaitingForRemoteRotation,在通知sytemUi那会置为true,在回调回来才会变为false// 所以 pendingRemoteRotation为truefinal boolean pendingRemoteRotation = rotationChanged&& (displayContent.getDisplayRotation().isWaitingForRemoteRotation()|| displayContent.mTransitionController.isCollecting());
}
displayContent的updateRotationUnchecked,又会调用 mDisplayRotation的updateRotationUnchecked 方法
- 判断是否有没在动画过程,判断有则返回false
- 通过 mService.mDisplayFrozen 判断是否冻结
- 调用 rotationForOrientation 结合当前的app屏幕配置 和当前屏幕的旋转角度,计算对应旋转角度
- 如果计算出来和当前一样,则不处理
- 将计算出来的角度赋值给变量mRotation,这里更新了DisplayRotation的最新角度
- 标记 WMS 为冻屏,并启动一个延时任务
- 判断是否马上进行旋转,一般不是 会调用prepareNormalRotationAnimation 不是的话准备进退出动画资源,一般都为0非自定义
- 调用 startRemoteRotation 通知到systemUi,等待回调通知准备结束。
boolean updateRotationUnchecked(boolean forceUpdate) {// 判断是否动画中if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {...ProtoLog.v(WM_DEBUG_ORIENTATION, "Deferring rotation, animation in progress.");return false;}// 是否冻结if (mService.mDisplayFrozen) {...ProtoLog.v(WM_DEBUG_ORIENTATION,"Deferring rotation, still finishing previous rotation");return false;}...// mRotation为旋转角度, mLastOrientation 为当前的app屏幕配置final int oldRotation = mRotation;final int lastOrientation = mLastOrientation;// 计算出当前的旋转角度final int rotation = rotationForOrientation(lastOrientation, oldRotation);// 如果计算出来和当前一样,则不处理if (oldRotation == rotation) {// No change.return false;}// 将要旋转的角度赋值给rotationmRotation = rotation;// 设置标记mLayoutNeeded为truemDisplayContent.setLayoutNeeded();// 标记为冻屏,并发送一个任务防止无变化2秒超时mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;mService.mH.sendNewMessageDelayed(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT,mDisplayContent, WINDOW_FREEZE_TIMEOUT_DURATION);// 判断是否马上进行旋转,不是的话准备进退出动画资源,一般都为0非自定义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.// 传入新的旋转角度和旧的角度,// 会调用 DisplayRotationController.onRotateDisplay 给到systemUistartRemoteRotation(oldRotation, mRotation);
}
2.1 旋转的判断
rotationForOrientation 方法
- 通过mOrientationListener.getProposedRotation() 获取传感器当前的角度。
- 计算要的角度,并保存到 preferredRotation变量。
- 最后根据这些app的orientation屏幕属性算出对应的实际需要角度
int rotationForOrientation(@ScreenOrientation int orientation,@Surface.Rotation int lastRotation) {...// 获取传感器的角度int sensorRotation = mOrientationListener != null? mOrientationListener.getProposedRotation() // may be -1: -1;if (sensorRotation < 0) {sensorRotation = lastRotation;}...// 计算要的角度final int preferredRotation;if (!isDefaultDisplay) {// For secondary displays we ignore things like displays sensors, docking mode and// rotation lock, and always prefer user rotation.preferredRotation = mUserRotation;} else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED&& orientation != ActivityInfo.SCREEN_ORIENTATION_NOSENSOR&& orientation != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE&& orientation != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT&& orientation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE&& orientation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT) {preferredRotation = mUserRotation;} // 最后根据这些app的orientation屏幕属性算出对应的实际需要角度switch (orientation) {case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:// Return portrait unless overridden.if (isAnyPortrait(preferredRotation)) {return preferredRotation;}return mPortraitRotation;...}}
2.2 准备进退动画
prepareNormalRotationAnimation 主要
- 通过 selectRotationAnimation 方法,选出exit,enter 的动画资源ID,正常都没自定义动画,都是返回0
- 在调用 WMS 的 startFreezingDisplay , 开始冻结。
void prepareNormalRotationAnimation() {cancelSeamlessRotation();// 返回全屏窗口进入和退出动画,不是值为0final RotationAnimationPair anim = selectRotationAnimation();// 开启冻结屏幕mService.startFreezingDisplay(anim.mExit, anim.mEnter, mDisplayContent);}
2.3 屏幕冻结
startFreezingDisplay 方法主要
- 判断标志位mDisplayFrozen是否为true已冻结,是的话返回,否则 将标志位 mDisplayFrozen 置为true
- 将对应的进出动画资源保存下来
- 创建ScreenRotationAnimation动画管理类
- 调用 displayContent的setRotationAnimation 将创建的ScreenRotationAnimation 保存到 displayContent的mScreenRotationAnimation 中
void startFreezingDisplay(int exitAnim, int enterAnim, DisplayContent displayContent,int overrideOriginalRotation) {// 判断是否冻结了if (mDisplayFrozen || displayContent.getDisplayRotation().isRotatingSeamlessly()) {return;}....mAtmService.startLaunchPowerMode(POWER_MODE_REASON_FREEZE_DISPLAY);// 设置标记为true和时间mDisplayFrozen = true;mDisplayFreezeTime = SystemClock.elapsedRealtime();...// 保存对应的进出动画mExitAnimId = exitAnim;mEnterAnimId = enterAnim;...final int originalRotation = overrideOriginalRotation != ROTATION_UNDEFINED? overrideOriginalRotation: displayContent.getDisplayInfo().rotation;// ScreenRotationAnimation 构造方法里面会创建截图图层,设置旋转动画事务,传进入的角度还是没改变// setRotationAnimation 将创建的赋值给变量mScreenRotationAnimationdisplayContent.setRotationAnimation(new ScreenRotationAnimation(displayContent,originalRotation));}
2.4 通知systemUi,并等待回调
startRemoteRotation 会传入对应新旧角度
- 标记变量 mIsWaitingForRemoteRotation 为 true
- 调用 WMS 的DisplayRotationController 的 onRotateDisplay 方法,通知SystemUI 开始旋转。,并且传入参数为AIDL 的 mRemoteRotationCallback 。
- 回调接收到后,会通过handle 发送消息,触发 continueRotation 方法。
private void startRemoteRotation(int fromRotation, int toRotation) {if (mService.mDisplayRotationController == null) {return;}// 设置标记为为truemIsWaitingForRemoteRotation = true;try {// mRemoteRotationCallback 是AIDL,对端执行完会触发该回调mService.mDisplayRotationController.onRotateDisplay(mDisplayContent.getDisplayId(),fromRotation, toRotation, mRemoteRotationCallback);// 添加会移除的回调mService.mH.removeCallbacks(mDisplayRotationHandlerTimeout);mService.mH.postDelayed(mDisplayRotationHandlerTimeout, REMOTE_ROTATION_TIMEOUT_MS);} catch (RemoteException e) {mIsWaitingForRemoteRotation = false;return;}}
private final IDisplayWindowRotationCallback mRemoteRotationCallback =new IDisplayWindowRotationCallback.Stub() {@Overridepublic void continueRotateDisplay(int targetRotation,WindowContainerTransaction t) {synchronized (mService.getWindowManagerLock()) {// 执行 continueRotation继续做旋转逻辑mService.mH.sendMessage(PooledLambda.obtainMessage(DisplayRotation::continueRotation, DisplayRotation.this,targetRotation, t));}}};
3 更新动画以及DisplayInfo
触发回调的 continueRotation 方法,该方法会触发 displayContent 的 sendNewConfiguration 方法。
private void continueRotation(int targetRotation, WindowContainerTransaction t) {synchronized (mService.mGlobalLock) {// 判断和当前的是否一致if (targetRotation != mRotation || !mIsWaitingForRemoteRotation) {// Drop it, this is either coming from an outdated remote rotation; or, we've// already moved on.return;}....try {// 更新相关DisplayInfo信息,包括rotation变量,和通知applicaiton和各个窗口触发onConfigurationChanged回调mDisplayContent.sendNewConfiguration();if (t != null) {mService.mAtmService.mWindowOrganizerController.applyTransaction(t);}} finally {mService.mAtmService.continueWindowLayout();}}}
sendNewConfiguration 方法
- 会判断 isWaitingForRemoteRotation 方法是否在等待更新中
- 调用 updateDisplayOverrideConfigurationLocked 开始更新,并返回是否要更新的操作
void sendNewConfiguration() {if (!isReady()) {return;}// 这里也会判断if (mDisplayRotation.isWaitingForRemoteRotation()) {return;}// 在这里会判断是否需要更新,并更新对应的display信息final boolean configUpdated = updateDisplayOverrideConfigurationLocked();if (configUpdated) {return;}...}
updateDisplayOverrideConfigurationLocked 方法
- 创建 Configuration 变量
- 将创建的 Configuration 变量 传进入 computeScreenConfiguration方法开始计算,计算后并更新到该变量
- 将更新好的变量传进 updateDisplayOverrideConfigurationLocked开始更新
boolean updateDisplayOverrideConfigurationLocked() {...// 创建新的ConfigurationConfiguration values = new Configuration();// 开始将对应的信息放到values,并更新对应的数值computeScreenConfiguration(values);...// 将对应的values,传进去,开始更新updateDisplayOverrideConfigurationLocked(values, null /* starting */,false /* deferResume */, mAtmService.mTmpUpdateConfigurationResult);return mAtmService.mTmpUpdateConfigurationResult.changes != 0;}
3.1 更新DisplayInfo 和 Configuration信息
computeScreenConfiguration 方法主要用于计算对应的角度
- 调用updateDisplayAndOrientation ,更新对应的DisplayInfo信息,这时候更新displayInfo的rotation
- calculateBounds 计算显示范围 保存mTmpBounds
- 将其他信息更新 config 字段
void computeScreenConfiguration(Configuration config) {// updateDisplayAndOrientation 更新对应的display信息,并返回final DisplayInfo displayInfo = updateDisplayAndOrientation(config.uiMode, config);// 计算,并设置到对应的config信息calculateBounds(displayInfo, mTmpBounds);config.windowConfiguration.setBounds(mTmpBounds);config.windowConfiguration.setMaxBounds(mTmpBounds);config.windowConfiguration.setWindowingMode(getWindowingMode());config.windowConfiguration.setDisplayWindowingMode(getWindowingMode());final int dw = displayInfo.logicalWidth;final int dh = displayInfo.logicalHeight;// 计算app显示的相关信息,涉及inset一些计算,并也赋值到config里面computeScreenAppConfiguration(config, dw, dh, displayInfo.rotation, config.uiMode,displayInfo.displayCutout);...}
updateDisplayAndOrientation方法通过DisplayRotation获取对应的旋转角度,然后更新给displayInfo,这里也更新了其他属性。
private DisplayInfo updateDisplayAndOrientation(int uiMode, Configuration outConfig) {// Use the effective "visual" dimensions based on current rotation// 从DisplayRotation 中获取需要旋转的角度,因为在计算后如果有改变已经赋值final int rotation = getRotation();final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);// 如果是横屏,则将对应的宽高交换final int dw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;final int dh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;...// 这里更新对应displayInfo信息,角度宽高mDisplayInfo.rotation = rotation;....// 设置矩阵宽高mBaseDisplayRect.set(0, 0, dw, dh);
}
3.2 通知更新
updateDisplayOverrideConfigurationLocked 将对应的values,传进去,开始更新
- 调用 ATMS的 updateGlobalConfigurationLocked 方法,开始通知各个app
- 调用 ensureConfigAndVisibilityAfterUpdate ,deferResume为fasle 不延迟,获取当前最顶端的activityRecord进行通知更改
boolean updateDisplayOverrideConfigurationLocked(Configuration values,ActivityRecord starting, boolean deferResume,ActivityTaskManagerService.UpdateConfigurationResult result) {...try {if (values != null) {if (mDisplayId == DEFAULT_DISPLAY) {// Override configuration of the default display duplicates global config, so// we're calling global config update instead for default display. It will also// apply the correct override config.// 获取屏幕会走这里,调用ATMS的方法,开始通知各个appchanges = mAtmService.updateGlobalConfigurationLocked(values,false /* initLocale */, false /* persistent */,UserHandle.USER_NULL /* userId */);} else {changes = performDisplayOverrideConfigUpdate(values);}}// deferResume为fasle 不延迟,获取当前最顶端的activityRecord进行通知更改if (!deferResume) {kept = mAtmService.ensureConfigAndVisibilityAfterUpdate(starting, changes);}} ...}
updateGlobalConfigurationLocked 方法进行通知操作
- 调用 updateFrom 判断对应的配置跟当前是否改变,并赋值给mTempConfig ,并判断是否有改变,没改变返回0
- 打印对应改变
- 获取每个进程,调用对应appliciton的onConfigurationChanged进行通知,此时调用的WindowProcessController的onConfigurationChanged
- 发送广播通知,在AMS发送
- 从rootWindowContatiner 开始遍历,通知各个窗口
int updateGlobalConfigurationLocked(@NonNull Configuration values, boolean initLocale,boolean persistent, int userId) {mTempConfig.setTo(getGlobalConfiguration());// 判断对应的配置跟当前是否改变,并赋值给mTempConfigfinal int changes = mTempConfig.updateFrom(values);if (changes == 0) {return 0;}...// 打印改变Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + mTempConfig);...// 获取每个进程,调用对应appliciton的onConfigurationChangedSparseArray<WindowProcessController> pidMap = mProcessMap.getPidMap();for (int i = pidMap.size() - 1; i >= 0; i--) {final int pid = pidMap.keyAt(i);final WindowProcessController app = pidMap.get(pid);ProtoLog.v(WM_DEBUG_CONFIGURATION, "Update process config of %s to new "+ "config %s", app.mName, mTempConfig);// 这里调用每个进程的 onConfigurationChanged,在 updateConfiguration,会调用通知唤醒客户端app.onConfigurationChanged(mTempConfig);}// 发送广播通知,在AMS发送final Message msg = PooledLambda.obtainMessage(ActivityManagerInternal::broadcastGlobalConfigurationChanged,mAmInternal, changes, initLocale);mH.sendMessage(msg);// Update stored global config and notify everyone about the change.// 从rootWindowContatiner 开始遍历,通知各个窗口mRootWindowContainer.onConfigurationChanged(mTempConfig);return changes;}
3.2.1 Application的通知
WindowProcessController 的onConfigurationChanged 如下,关键会调用 updateConfiguration 方法
@Overridepublic void onConfigurationChanged(Configuration newGlobalConfig) {// 因为没子类,所以不会dispatchConfigurationToChildsuper.onConfigurationChanged(newGlobalConfig);updateConfiguration();}
而 updateConfiguration 又会调 dispatchConfiguration
private void updateConfiguration() {...// 调用 dispatchConfiguration 开始进行分发dispatchConfiguration(config);}
dispatchConfiguration 也是调用了 clinet的ConfigurationChangeItem。该方法会通知各个进程的application的 ConfigurationChange方法。
void dispatchConfiguration(Configuration config) {mHasPendingConfigurationChange = false;...try {config.seq = mAtm.increaseConfigurationSeqLocked();// 调用 ConfigurationChangeItem 开始通知mAtm.getLifecycleManager().scheduleTransaction(mThread,ConfigurationChangeItem.obtain(config));setLastReportedConfiguration(config);} catch (Exception e) {Slog.e(TAG_CONFIGURATION, "Failed to schedule configuration change", e);}}
3.2.2 容器的大小通知
容器的通知从 rootWindowContatiner 的onConfigurationChanged开始,该super方法在 ConfigurationContainer 中,在里面调用 dispatchConfigurationToChild。
@Overridepublic void onConfigurationChanged(Configuration newParentConfig) {// 在super方法进行处理,里面会调用 dispatchConfigurationToChildsuper.onConfigurationChanged(newParentConfig);updateSurfacePositionNonOrganized();scheduleAnimation();}
而 基类ConfigurationContainer的 onConfigurationChanged 会调用 dispatchConfigurationToChild,此时遍历的孩子为displayContent。
public void onConfigurationChanged(Configuration newParentConfig) {...// 调用 开始遍历每个子类,RootWindowContainer有重写dispatchConfigurationToChild 调用dispatchConfigurationToChild进分分发for (int i = getChildCount() - 1; i >= 0; --i) {dispatchConfigurationToChild(getChildAt(i), mFullConfiguration);}}
所以该方法又等于调用 rootWindowContatiner的 dispatchConfigurationToChild,如果是默认的屏幕的话 会走
performDisplayOverrideConfigUpdate 方法,child 会displayContent.
@Overridevoid dispatchConfigurationToChild(DisplayContent child, Configuration config) {if (child.isDefaultDisplay) {// The global configuration is also the override configuration of default display.// 默认屏幕走 performDisplayOverrideConfigUpdate,调用displayContent的performDisplayOverrideConfigUpdatechild.performDisplayOverrideConfigUpdate(config);} else {child.onConfigurationChanged(config);}}
performDisplayOverrideConfigUpdate 会判断是否有改变,有改变的话 调用 onRequestedOverrideConfigurationChanged,通知
int performDisplayOverrideConfigUpdate(Configuration values) {mTempConfig.setTo(getRequestedOverrideConfiguration());final int changes = mTempConfig.updateFrom(values);if (changes != 0) {Slog.i(TAG, "Override config changes=" + Integer.toHexString(changes) + " "+ mTempConfig + " for displayId=" + mDisplayId);// 开始通知onRequestedOverrideConfigurationChanged(mTempConfig);...}return changes;}
onRequestedOverrideConfigurationChanged 主要内容
- 通过 getRequestedOverrideConfiguration 获取当前的配置
- 从 overrideConfiguration获取要旋转的角度
- 判断是否角度改变,,调用 applyRotation 重新设置矩阵,这时候角度变了。applyRotationAndFinishFixedRotation 会调用 applyRotation 方法。然后获取之前构建的 ScreenRotationAnimation,在调用 他的 setRotation,更新矩阵
- 调用基类WindowContainer的方法判断显示区域是否变化,变化则执行onResize
public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {// 获取的是当前的final Configuration currOverrideConfig = getRequestedOverrideConfiguration();final int currRotation = currOverrideConfig.windowConfiguration.getRotation();final int overrideRotation = overrideConfiguration.windowConfiguration.getRotation();// 对比下角度,旋转不相等,调用 applyRotation 重新设置矩阵,这时候角度变了if (currRotation != ROTATION_UNDEFINED && overrideRotation != ROTATION_UNDEFINED&& currRotation != overrideRotation) {applyRotationAndFinishFixedRotation(currRotation, overrideRotation);}mCurrentOverrideConfigurationChanges = currOverrideConfig.diff(overrideConfiguration);// 调用基类WindowContainer的方法判断显示区域是否变化,变化则执行onResizesuper.onRequestedOverrideConfigurationChanged(overrideConfiguration);mCurrentOverrideConfigurationChanges = 0;mWmService.setNewDisplayOverrideConfiguration(currOverrideConfig, this);mAtmService.addWindowLayoutReasons(ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED);}
applyRotationAndFinishFixedRotation 方法会调用 applyRotation
private void applyRotationAndFinishFixedRotation(int oldRotation, int newRotation) {final WindowToken rotatedLaunchingApp = mFixedRotationLaunchingApp;if (rotatedLaunchingApp == null) {applyRotation(oldRotation, newRotation);return;}rotatedLaunchingApp.finishFixedRotationTransform(() -> applyRotation(oldRotation, newRotation));setFixedRotationLaunchingAppUnchecked(null);}
调用 ScreenRotationAnimation 的setRotation设置传入的角度为新的角度了,所以可以更新最新的变换矩阵
private void applyRotation(final int oldRotation, final int rotation) {...// startFreezingDisplay 的时候已经构建了screenRotationAnimationScreenRotationAnimation screenRotationAnimation = rotateSeamlessly? null : getRotationAnimation();...if (screenRotationAnimation != null && screenRotationAnimation.hasScreenshot()) {// 再次调用setRotation设置变换矩阵screenRotationAnimation.setRotation(transaction, rotation);}...}
WindowContainer 的onRequestedOverrideConfigurationChanged方法,
- 又会调用ConfigurationContainer的onRequestedOverrideConfigurationChanged方法, 又会调用 onConfigurationChanged 方法,
- 会判断是否有大小变化,有的话执行onResize 通知。
// WindowContainer 的 onRequestedOverrideConfigurationChangedpublic void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {...// 又会调用ConfigurationContainer的方法super.onRequestedOverrideConfigurationChanged(overrideConfiguration);if (mParent != null) {mParent.onDescendantOverrideConfigurationChanged();}if (diff == BOUNDS_CHANGE_NONE) {return;}// 又变化执行sizeif ((diff & BOUNDS_CHANGE_SIZE) == BOUNDS_CHANGE_SIZE) {onResize();} else {onMovedByResize();}}// ConfigurationContainer 的方法public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {// Pre-compute this here, so we don't need to go through the entire Configuration when// writing to proto (which has significant cost if we write a lot of empty configurations).mHasOverrideConfiguration = !Configuration.EMPTY.equals(overrideConfiguration);mRequestedOverrideConfiguration.setTo(overrideConfiguration);final Rect newBounds = mRequestedOverrideConfiguration.windowConfiguration.getBounds();if (mHasOverrideConfiguration && providesMaxBounds()&& diffRequestedOverrideMaxBounds(newBounds) != BOUNDS_CHANGE_NONE) {mRequestedOverrideConfiguration.windowConfiguration.setMaxBounds(newBounds);}// Update full configuration of this container and all its children.final ConfigurationContainer parent = getParent();// 执行onConfigurationChanged,遍历子viewdispatchConfigurationToChildonConfigurationChanged(parent != null ? parent.getConfiguration() : Configuration.EMPTY);}
经过循环都会调用到 windoState的 onResize 方法。
- 当有Surface的时候,并且可见,添加到 WMS的 resizingWindows 数组中。
void onResize() {final ArrayList<WindowState> resizingWindows = mWmService.mResizingWindows;// 当dispatchConfigchange添加到MWS的 resizingWindowsif (mHasSurface && !isGoneForLayout() && !resizingWindows.contains(this)) {ProtoLog.d(WM_DEBUG_RESIZE, "onResize: Resizing %s", this);resizingWindows.add(this);}if (isGoneForLayout()) {mResizedWhileGone = true;}super.onResize();}
添加到数组后,当 界面重新绘制 执行 performSurfacePlacementNoTrace 的方法时候。会执行 handleResizingWindows 方法。将数组的获取出来,然后执行 WindowState 的 reportResized 方法。
private void handleResizingWindows() {for (int i = mWmService.mResizingWindows.size() - 1; i >= 0; i--) {WindowState win = mWmService.mResizingWindows.get(i);if (win.mAppFreezing || win.getDisplayContent().mWaitingForConfig) {// Don't remove this window until rotation has completed and is not waiting for the// complete configuration.continue;}win.reportResized();mWmService.mResizingWindows.remove(i);}}
reportResized 方法,首先会判断是否重启,如果是重启则不需要通知了,不然则调用 viewRootImpl 添加一开始的W类通知viewRootImpl 执行resized方法。
void reportResized() {// If the activity is scheduled to relaunch, skip sending the resized to ViewRootImpl now// since it will be destroyed anyway. This also prevents the client from receiving// windowing mode change before it is destroyed.// 如果是重启的则不需要了if (mActivityRecord != null && mActivityRecord.isRelaunching()) {return;}....try {// 调用viewRootImpl的W类,通知到viewRootImpl那边mClient.resized(mClientWindowFrames, reportDraw, mLastReportedConfiguration,forceRelayout, alwaysConsumeSystemBars, displayId);if (drawPending && reportOrientation && mOrientationChanging) {mOrientationChangeRedrawRequestTime = SystemClock.elapsedRealtime();ProtoLog.v(WM_DEBUG_ORIENTATION,"Requested redraw for orientation change: %s", this);}...}}
3.3 Activity界面更新
上面 DisplayContent 的 updateDisplayOverrideConfigurationLocked 执行后,除了执行 ATMS 的updateGlobalConfigurationLocked 后 还会执行 ensureConfigAndVisibilityAfterUpdate。
- 通过 getTopDisplayFocusedRootTask 获取最顶端的Task
- 如果有变化,通过 topRunningActivity 获取对应的 ActivityRecord
- 执行 ensureActivityConfiguration 开始更新 ActivityRecord 界面
boolean ensureConfigAndVisibilityAfterUpdate(ActivityRecord starting, int changes) {boolean kept = true;// 获取对定的堆栈final Task mainRootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();// mainRootTask is null during startup.if (mainRootTask != null) {if (changes != 0 && starting == null) {// If the configuration changed, and the caller is not already// in the process of starting an activity, then find the top// activity to check if its configuration needs to change.// 有打开activity,并且有改变,获取对应的 ActivityRecordstarting = mainRootTask.topRunningActivity();}if (starting != null) {// 调用方法进行通知kept = starting.ensureActivityConfiguration(changes,false /* preserveWindow */);// And we need to make sure at this point that all other activities// are made visible with the correct configuration.mRootWindowContainer.ensureActivitiesVisible(starting, changes,!PRESERVE_WINDOWS);}}return kept;}
ensureActivitiesVisible 方法主要判断
- 通过 shouldRelaunchLocked 判断是否需要重新加载Activity.
- 如果需要 重建,则执行 startFreezingScreenLocked,开始冻结显示
- 在调用 relaunchActivityLocked 进行重建通知。
- 如果没变化 则调用 scheduleConfigurationChanged 触发对应的 configurationChanged
boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow,boolean ignoreVisibility) {...// Figure out how to handle the changes between the configurations.ProtoLog.v(WM_DEBUG_CONFIGURATION, "Checking to restart %s: changed=0x%s, "+ "handles=0x%s, mLastReportedConfiguration=%s", info.name,Integer.toHexString(changes), Integer.toHexString(info.getRealConfigChanged()),mLastReportedConfiguration);// 这里开始判断是否要relaunch操作if (shouldRelaunchLocked(changes, mTmpConfig) || forceNewConfig) {// Aha, the activity isn't handling the change, so DIE DIE DIE.configChangeFlags |= changes;// 开始冻结对应的显示startFreezingScreenLocked(globalChanges);forceNewConfig = false;...// 执行relaunch和resume等操作relaunchActivityLocked(preserveWindow);}// All done... tell the caller we weren't able to keep this activity around.return false;}...if (displayChanged) {scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig);} else {// 没重建的时候,通知客户端ActivityConfigurationChangeItem,会根据传过去的config更新宽高等scheduleConfigurationChanged(newMergedOverrideConfig);}stopFreezingScreenLocked(false);return true;}
shouldRelaunchLocked 方法主要获取对应配置文件配置,从 ActivityInfo 获取对应的 configChanged,在用当前的变化跟配置取反与,得出是否不等于0,表示要重载该界面。
private boolean shouldRelaunchLocked(int changes, Configuration changesConfig) {int configChanged = info.getRealConfigChanged();....// 从activityInfo获取config配置的标志位取反跟有改变的标志位进行与,大于0则表示是因为没配置所以要变更// 得出这次变化是否要重启动activityreturn (changes&(~configChanged)) != 0;}
3.3.1 重建Activity
判断到需要 relaunch后,就会执行 startFreezingScreenLocked 方法。一直调用则会调用到 startFreezingScreen 方法。
- 将变量 mFreezingScreen 设置 true
- 注册WMS registerAppFreezeListener 对应的监听
- 对 WMS 的 mAppsFreezingScreen 进行递增,只有为0的时候,才会解冻。
- 当mAppsFreezingScreen为1的时候,也会调用 WMS的startFreezingDisplay 开始冻结屏幕
- 在遍历下面的子容器的 onStartFreezingScreen 方法。将 各个容器的变量 设置为 mAppFreezing 为true
void startFreezingScreen(int overrideOriginalDisplayRotation) {...ProtoLog.i(WM_DEBUG_ORIENTATION,"Set freezing of %s: visible=%b freezing=%b visibleRequested=%b. %s",appToken, isVisible(), mFreezingScreen, mVisibleRequested,new RuntimeException().fillInStackTrace());...final boolean forceRotation = overrideOriginalDisplayRotation != ROTATION_UNDEFINED;if (!mFreezingScreen) {// 进行冻结 ,将 mFreezingScreen 设置为truemFreezingScreen = true;mWmService.registerAppFreezeListener(this);// 对wms进行++mWmService.mAppsFreezingScreen++;if (mWmService.mAppsFreezingScreen == 1) {if (forceRotation) {// Make sure normal rotation animation will be applied.mDisplayContent.getDisplayRotation().cancelSeamlessRotation();}mWmService.startFreezingDisplay(0 /* exitAnim */, 0 /* enterAnim */,mDisplayContent, overrideOriginalDisplayRotation);mWmService.mH.removeMessages(H.APP_FREEZE_TIMEOUT);mWmService.mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 2000);}}if (forceRotation) {// The rotation of the real display won't change, so in order to unfreeze the screen// via {@link #checkAppWindowsReadyToShow}, the windows have to be able to call// {@link WindowState#reportResized} (it is skipped if the window is freezing) to update// the drawn state.return;}// 遍历下面的容器final int count = mChildren.size();for (int i = 0; i < count; i++) {final WindowState w = mChildren.get(i);w.onStartFreezingScreen();}}
冻结后,执行 relaunchActivityLocked 进行Activity的重建。该方法
- 调用 startRelaunching 进行 标记。
- 创建 ActivityRelaunchItem 通知 Activity进行重建
- 根据情况调用 ResumeActivityItem 或者 PauseActivityItem 进行通知
void relaunchActivityLocked(boolean preserveWindow) {...try {ProtoLog.i(WM_DEBUG_STATES, "Moving to %s Relaunching %s callers=%s" ,(andResume ? "RESUMED" : "PAUSED"), this, Debug.getCallers(6));forceNewConfig = false;startRelaunching();// 调用 ActivityRelaunchItem 通知界面端重建final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(pendingResults,pendingNewIntents, configChangeFlags,new MergedConfiguration(getProcessGlobalConfiguration(),getMergedOverrideConfiguration()),preserveWindow);final ActivityLifecycleItem lifecycleItem;// 判断是否要通知哪个生命周期if (andResume) {lifecycleItem = ResumeActivityItem.obtain(isTransitionForward());} else {lifecycleItem = PauseActivityItem.obtain();}final ClientTransaction transaction = ClientTransaction.obtain(app.getThread(), appToken);transaction.addCallback(callbackItem);transaction.setLifecycleStateRequest(lifecycleItem);mAtmService.getLifecycleManager().scheduleTransaction(transaction);} catch (RemoteException e) {ProtoLog.i(WM_DEBUG_STATES, "Relaunch failed %s", e);}}
3.3.2 非重建
没重建的时候,调用 scheduleConfigurationChanged ,通知客户端ActivityConfigurationChangeItem,会根据传过去的config更新宽高等
private void scheduleConfigurationChanged(Configuration config) {if (!attachedToProcess()) {ProtoLog.w(WM_DEBUG_CONFIGURATION, "Can't report activity configuration "+ "update - client not running, activityRecord=%s", this);return;}try {ProtoLog.v(WM_DEBUG_CONFIGURATION, "Sending new config to %s, "+ "config: %s", this, config);mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,ActivityConfigurationChangeItem.obtain(config));} catch (RemoteException e) {// If process died, whatever.}}
4 动画的播放
4.1 停止冻屏
动画的播放 在 WMS的stopFreezingDisplayLocked 执行,具体执行可查看最后的堆栈打印。可以看到 触发停止冻屏是在 performSurfacePlacementNoTrace 方法触发。会根据 mOrientationChangeComplete 变量判断是否完成。
mOrientationChangeComplete 变量的赋值时机
- 当执行WindowAnimator的animate 动画时候会变为true
- 当执行 windowState的setOrientationChanging 会变为false
- 当对应需要改变的 WindowAnimator的prepareSurfaceLocked会判断是否需要改变并且还没绘制完成设置为false
void performSurfacePlacementNoTrace() {// 根据变量mOrientationChangeComplete 判断是否要停止冻屏// 该方法从 performSurfacePlacementNoTrace// mOrientationChangeComplete 发生改变的时机有3个// 1.当执行WindowAnimator的animate 动画时候会变为true// 2.当执行 windowState的setOrientationChanging 会变为false// 3.当对应需要改变的 WindowAnimator的prepareSurfaceLocked会判断是否需要改变并且还没绘制完成设置为falseif (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();}
}
执行动画的时候,变为 true
private void animate(long frameTimeNs, long vsyncId) {...final RootWindowContainer root = mService.mRoot;mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;mBulkUpdateParams = 0;// 执行动画时候,变为trueroot.mOrientationChangeComplete = true;...}
当需要旋转的时候设置为false
void setOrientationChanging(boolean changing) {mOrientationChangeTimedOut = false;if (mOrientationChanging == changing) {return;}mOrientationChanging = changing;if (changing) {mLastFreezeDuration = 0;if (mWmService.mRoot.mOrientationChangeComplete&& mDisplayContent.waitForUnfreeze(this)) {// 需要旋转的时候变为falsemWmService.mRoot.mOrientationChangeComplete = false;}} else {// The orientation change is completed. If it was hidden by the animation, reshow it.mDisplayContent.finishFadeRotationAnimation(this);}}
当WindowStateAnimator 动画在准备的时候,
- 判断对应的容器是否旋转并且还没绘制好的时候
- 通过 waitForUnfreeze 里面isHandledToken会判断token是否为底部栏,状态栏,忽略该视图
- // 将当前的windowState 放到 mLastWindowFreezeSource 变量,标记是因为哪个windowState导致冻屏
void prepareSurfaceLocked(SurfaceControl.Transaction t) {// 判断屏幕是否旋转中if (w.getOrientationChanging()) {if (!w.isDrawn()) { // 还没绘制好的的时候// 里面isHandledToken会判断token是否为底部栏,状态栏if (w.mDisplayContent.waitForUnfreeze(w)) {w.mWmService.mRoot.mOrientationChangeComplete = false;// 将当前的windowState 放到 mLastWindowFreezeSource 变量// 标记是因为哪个windowState导致冻屏mAnimator.mLastWindowFreezeSource = w;}ProtoLog.v(WM_DEBUG_ORIENTATION,"Orientation continue waiting for draw in %s", w);} else {w.setOrientationChanging(false);ProtoLog.v(WM_DEBUG_ORIENTATION, "Orientation change complete in %s", w);}}
}
wms的 stopFreezingDisplayLocked 方法,会有一系列变量的判断
- mDisplayFrozen 判断是否有启动冻屏
- 判断 waitingForRemoteRotation以及mAppsFreezingScreen是否大于0,只有等于0 才执行
- 打印解冻的日志
- 调用 screenRotationAnimation的dismiss 方法开始播放动画,并调用 apply 应用。
void stopFreezingDisplayLocked() {if (!mDisplayFrozen) {return;}....// 判断 waitingForRemoteRotation以及mAppsFreezingScreen是否大于0,只有等于0 才执行if (waitingForConfig || waitingForRemoteRotation || mAppsFreezingScreen > 0|| mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_ACTIVE|| mClientFreezingScreen || numOpeningApps > 0) {ProtoLog.d(WM_DEBUG_ORIENTATION, "stopFreezingDisplayLocked: Returning "+ "waitingForConfig=%b, waitingForRemoteRotation=%b, "+ "mAppsFreezingScreen=%d, mWindowsFreezingScreen=%d, "+ "mClientFreezingScreen=%b, mOpeningApps.size()=%d",waitingForConfig, waitingForRemoteRotation,mAppsFreezingScreen, mWindowsFreezingScreen,mClientFreezingScreen, numOpeningApps);return;}....// 打印冻结的原因StringBuilder sb = new StringBuilder(128);sb.append("Screen frozen for ");TimeUtils.formatDuration(mLastDisplayFreezeDuration, sb);// 打印对应的原因if (mLastFinishedFreezeSource != null) {sb.append(" due to ");sb.append(mLastFinishedFreezeSource);}ProtoLog.i(WM_ERROR, "%s", sb.toString());....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 windowif (!displayContent.getDisplayRotation().validateRotationAnimation(mExitAnimId, mEnterAnimId, false /* forceDefault */)) {mExitAnimId = mEnterAnimId = 0;}// 调用dismiss播放动画if (screenRotationAnimation.dismiss(mTransaction, MAX_ANIMATION_DURATION,getTransitionAnimationScaleLocked(), displayInfo.logicalWidth,displayInfo.logicalHeight, mExitAnimId, mEnterAnimId)) {mTransaction.apply();}}
4.1 播放动画
dismiss的方法又会调用 startAnimation 开始了播放动画。
public boolean dismiss(SurfaceControl.Transaction t, long maxAnimationDuration,float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) {...if (!mStarted) {mEndLuma = RotationAnimationUtils.getLumaOfSurfaceControl(mDisplayContent.getDisplay(),mDisplayContent.getWindowingLayer());// 启动动画startAnimation(t, maxAnimationDuration, animationScale, finalWidth, finalHeight,exitAnim, enterAnim);}...return true;}
startAnimation 方法主要逻辑
- 通过 deltaRotation 计算差值
- 根据exitAnim 和enterAnim 获取进场退出动画, 一般exitAnim 和enterAnim都为0,赋值到 mRotateExitAnimation,mRotateEnterAnimation
- 对 进出动画进行设置,包含时长等。
- 调用 mSurfaceRotationAnimationController的startScreenRotationAnimation 开始旋转动画
private boolean startAnimation(SurfaceControl.Transaction t, long maxAnimationDuration,float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) {// 计算差值int delta = deltaRotation(mCurRotation, mOriginalRotation);final boolean customAnim;// 据exitAnim 和enterAnim 获取进场退出动画,一般exitAnim 和enterAnim都为0// 赋值到 mRotateExitAnimation,mRotateEnterAnimationif (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 {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;}}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);......// 旋转动画为falseif (customAnim) {mSurfaceRotationAnimationController.startCustomAnimation();} else {// 这里开始旋转动画mSurfaceRotationAnimationController.startScreenRotationAnimation();}return true;}
startScreenRotationAnimation 方法分别
- 调用 startDisplayRotation 启动屏幕旋转动画
- 调用 startScreenshotRotationAnimation 启动截屏动画
void startScreenRotationAnimation() {try {mService.mSurfaceAnimationRunner.deferStartingAnimations();mDisplayAnimator = startDisplayRotation(); // 启动屏幕旋转动画mScreenshotRotationAnimator = startScreenshotRotationAnimation(); //启动截屏startColorAnimation();} finally {mService.mSurfaceAnimationRunner.continueStartingAnimations();}}
startDisplayRotation 分别设置 displayContent的图层和SurfaceControl,然后调用 startAnimation 方法
private SurfaceAnimator startDisplayRotation() {return startAnimation(initializeBuilder().setAnimationLeashParent(mDisplayContent.getSurfaceControl()).setSurfaceControl(mDisplayContent.getWindowingLayer()) // 设置DisplayContent的图层.setParentSurfaceControl(mDisplayContent.getSurfaceControl())// 设置DisplayContent的SurfaceControl.setWidth(mDisplayContent.getSurfaceWidth()).setHeight(mDisplayContent.getSurfaceHeight()).build(),createWindowAnimationSpec(mRotateEnterAnimation),this::onAnimationEnd);}
startScreenshotRotationAnimation 通过 setAnimationLeashParent 设置图层为屏幕的,在构造的时候可以挂载到上面,然后调用 startAnimation 方法
private SurfaceAnimator startScreenshotRotationAnimation() {// setAnimationLeashParent 设置图层为屏幕的,在构造的时候可以挂载到上面return startAnimation(initializeBuilder().setSurfaceControl(mScreenshotLayer).setAnimationLeashParent(mDisplayContent.getOverlayLayer()).build(),createWindowAnimationSpec(mRotateExitAnimation),this::onAnimationEnd);}
startAnimation
- 会先创建对应SurfaceAnimator,因为他不像windowState已经拥有
- 创建本地动画LocalAnimationAdapter
- 在调用 animator的 startAnimation进行动画播放,后续的动画播放可以参考本文《frameworks 之 Splash开屏动画》
private SurfaceAnimator startAnimation(SurfaceAnimator.Animatable animatable,LocalAnimationAdapter.AnimationSpec animationSpec,OnAnimationFinishedCallback animationFinishedCallback) {// 创造对应的SurfaceAnimator,不像windowState的SurfaceAnimator animator = new SurfaceAnimator(animatable, animationFinishedCallback, mService);// 创建本地动画LocalAnimationAdapter localAnimationAdapter = new LocalAnimationAdapter(animationSpec, mService.mSurfaceAnimationRunner);animator.startAnimation(mDisplayContent.getPendingTransaction(),localAnimationAdapter, false, ANIMATION_TYPE_SCREEN_ROTATION);return animator;}
在创建图层createAnimationLeash 的时候的时候就会 获取对应的**animatable.getAnimationLeashParent()**挂载到对应的图层上。
这样屏幕旋转的动画就完成了。
5 堆栈
5.1 更新当前app屏幕配置
updateOrientation:377, DisplayRotation (com.android.server.wm)
updateOrientation:1619, DisplayContent (com.android.server.wm)
updateOrientation:1566, DisplayContent (com.android.server.wm)
ensureVisibilityAndConfig:1867, RootWindowContainer (com.android.server.wm)
resumeTopActivity:1244, TaskFragment (com.android.server.wm)
resumeTopActivityInnerLocked:5037, Task (com.android.server.wm)
resumeTopActivityUncheckedLocked:4971, Task (com.android.server.wm)
resumeTopActivityUncheckedLocked:4985, Task (com.android.server.wm)
resumeFocusedTasksTopActivities:2399, RootWindowContainer (com.android.server.wm)
resumeTargetRootTaskIfNeeded:2788, ActivityStarter (com.android.server.wm)
recycleTask:2113, ActivityStarter (com.android.server.wm)
startActivityInner:1762, ActivityStarter (com.android.server.wm)
startActivityUnchecked:1594, ActivityStarter (com.android.server.wm)
executeRequest:1195, ActivityStarter (com.android.server.wm)
execute:674, ActivityStarter (com.android.server.wm)
startHomeActivity:179, ActivityStartController (com.android.server.wm)
startHomeOnTaskDisplayArea:1605, RootWindowContainer (com.android.server.wm)
lambda$startHomeOnDisplay$12$RootWindowContainer:1546, RootWindowContainer (com.android.server.wm)
apply:-1, RootWindowContainer$$ExternalSyntheticLambda10 (com.android.server.wm)
reduceOnAllTaskDisplayAreas:554, TaskDisplayArea (com.android.server.wm)
reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
reduceOnAllTaskDisplayAreas:2091, WindowContainer (com.android.server.wm)
startHomeOnDisplay:1545, RootWindowContainer (com.android.server.wm)
startHomeOnDisplay:5842, ActivityTaskManagerService$LocalService (com.android.server.wm)
startDockOrHome:5106, PhoneWindowManager (com.android.server.policy)
startDockOrHome:5111, PhoneWindowManager (com.android.server.policy)
launchHomeFromHotKey:3254, PhoneWindowManager (com.android.server.policy)
launchHomeFromHotKey:3211, PhoneWindowManager (com.android.server.policy)
handleShortPressOnHome:1351, PhoneWindowManager (com.android.server.policy)
access$2200:240, PhoneWindowManager (com.android.server.policy)
lambda$handleHomeButton$0$PhoneWindowManager$DisplayHomeButtonHandler:1501, PhoneWindowManager$DisplayHomeButtonHandler (com.android.server.policy)
run:-1, PhoneWindowManager$DisplayHomeButtonHandler$$ExternalSyntheticLambda0 (com.android.server.policy)
handleCallback:938, Handler (android.os)
dispatchMessage:99, Handler (android.os)
loopOnce:201, Looper (android.os)
loop:288, Looper (android.os)
run:67, HandlerThread (android.os)
run:44, ServiceThread (com.android.server)
run:45, UiThread (com.android.server)
5.2 传感器上报
onSensorChanged:867, WindowOrientationListener$AccelSensorJudge (com.android.server.wm)
dispatchSensorEvent:886, SystemSensorManager$SensorEventQueue (android.hardware)
nativePollOnce:-1, MessageQueue (android.os)
next:335, MessageQueue (android.os)
loopOnce:161, Looper (android.os)
loop:288, Looper (android.os)
run:67, HandlerThread (android.os)
run:44, ServiceThread (com.android.server)
run:45, UiThread (com.android.server)
5.3开始冻屏幕
startRemoteRotation:564, DisplayRotation (com.android.server.wm)
updateRotationUnchecked:536, DisplayRotation (com.android.server.wm)
updateRotationUnchecked:1962, DisplayContent (com.android.server.wm)
updateRotationUnchecked:4146, WindowManagerService (com.android.server.wm)
updateRotation:4127, WindowManagerService (com.android.server.wm)
run:1556, DisplayRotation$OrientationListener$UpdateRunnable (com.android.server.wm)
handleCallback:938, Handler (android.os)
dispatchMessage:99, Handler (android.os)
loopOnce:201, Looper (android.os)
loop:288, Looper (android.os)
run:67, HandlerThread (android.os)
run:44, ServiceThread (com.android.server)
run:45, UiThread (com.android.server)
startFreezingDisplay:5924, WindowManagerService (com.android.server.wm)
startFreezingScreen:6030, ActivityRecord (com.android.server.wm)
startFreezingScreen:6002, ActivityRecord (com.android.server.wm)
startFreezingScreenLocked:5997, ActivityRecord (com.android.server.wm)
startFreezingScreenLocked:5979, ActivityRecord (com.android.server.wm)
ensureActivityConfiguration:8535, ActivityRecord (com.android.server.wm)
ensureActivityConfiguration:8407, ActivityRecord (com.android.server.wm)
ensureConfigAndVisibilityAfterUpdate:4871, ActivityTaskManagerService (com.android.server.wm)
updateDisplayOverrideConfigurationLocked:5812, DisplayContent (com.android.server.wm)
updateDisplayOverrideConfigurationLocked:5780, DisplayContent (com.android.server.wm)
sendNewConfiguration:1479, DisplayContent (com.android.server.wm)
continueRotation:606, DisplayRotation (com.android.server.wm)
access$200:83, DisplayRotation (com.android.server.wm)
lambda$continueRotateDisplay$0:228, DisplayRotation$2 (com.android.server.wm)
accept:-1, DisplayRotation$2$$ExternalSyntheticLambda0 (com.android.server.wm)
doInvoke:295, PooledLambdaImpl (com.android.internal.util.function.pooled)
invoke:204, PooledLambdaImpl (com.android.internal.util.function.pooled)
run:97, OmniFunction (com.android.internal.util.function.pooled)
handleCallback:938, Handler (android.os)
dispatchMessage:99, Handler (android.os)
loopOnce:201, Looper (android.os)
loop:288, Looper (android.os)
run:67, HandlerThread (android.os)
run:44, ServiceThread (com.android.server)
5.4 创建旋转动画
createAnimationLeash:448, SurfaceAnimator (com.android.server.wm)
startAnimation:181, SurfaceAnimator (com.android.server.wm)
startAnimation:205, SurfaceAnimator (com.android.server.wm)
startAnimation:701, ScreenRotationAnimation$SurfaceRotationAnimationController (com.android.server.wm)
startDisplayRotation:584, ScreenRotationAnimation$SurfaceRotationAnimationController (com.android.server.wm)
startScreenRotationAnimation:568, ScreenRotationAnimation$SurfaceRotationAnimationController (com.android.server.wm)
startAnimation:427, ScreenRotationAnimation (com.android.server.wm)
dismiss:445, ScreenRotationAnimation (com.android.server.wm)
stopFreezingDisplayLocked:6043, WindowManagerService (com.android.server.wm)
performSurfacePlacementNoTrace:950, RootWindowContainer (com.android.server.wm)
performSurfacePlacement:823, RootWindowContainer (com.android.server.wm)
performSurfacePlacementLoop:184, WindowSurfacePlacer (com.android.server.wm)
performSurfacePlacement:130, WindowSurfacePlacer (com.android.server.wm)
performSurfacePlacement:115, WindowSurfacePlacer (com.android.server.wm)
run:57, WindowSurfacePlacer$Traverser (com.android.server.wm)
handleCallback:938, Handler (android.os)
dispatchMessage:99, Handler (android.os)
loopOnce:201, Looper (android.os)
loop:288, Looper (android.os)
run:67, HandlerThread (android.os)
run:44, ServiceThread (com.android.server)
5.5 冻结触发时机
stopFreezingDisplayLocked:5986, WindowManagerService (com.android.server.wm)
performSurfacePlacementNoTrace:957, RootWindowContainer (com.android.server.wm)
performSurfacePlacement:824, RootWindowContainer (com.android.server.wm)
performSurfacePlacementLoop:184, WindowSurfacePlacer (com.android.server.wm)
performSurfacePlacement:130, WindowSurfacePlacer (com.android.server.wm)
relayoutWindow:2430, WindowManagerService (com.android.server.wm)
relayout:252, Session (com.android.server.wm)
onTransact:745, IWindowSession$Stub (android.view)
onTransact:170, Session (com.android.server.wm)
execTransactInternal:1179, Binder (android.os)
execTransact:1143, Binder (android.os)