当前位置: 首页 > article >正文

frameworks 之屏幕旋转

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 的构造方法,

  1. 会判断是否默认屏幕,是的会创建对应的OrientationListener,该监听继承自windowOrientationListener
  2. 注册对应的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 有一些比较重要的方法

  1. updateOrientation 方法更新对应的应用程序方向策略
    该方法每次当应用进入resume状态的时候,则会一次调用该方法(具体调用可以看堆栈第一个)
	boolean updateOrientation(@ScreenOrientation int newOrientation, boolean forceUpdate) {
        // 更新当前APP的方向设置放到 mCurrentAppOrientation
        if (newOrientation == mLastOrientation && !forceUpdate) {
            return false;
        }
        mLastOrientation = newOrientation;
        if (newOrientation != mCurrentAppOrientation) {
            mCurrentAppOrientation = newOrientation;
            if (isDefaultDisplay) {
            	// 有改变则注册或者移除对应的监听
                updateOrientationListenerLw();
            }
        }
        return updateRotationUnchecked(forceUpdate);
    }
  1. 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();
        }
    }
  1. 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 exist
                mOrientationJudge = 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层SystemSensorManagerdispatchSensorEvent 方法。

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);
}

查看 AccelSensorJudgeonSensorChanged 方法,会经过一系列判断,如果判断到方向跟之前的方向不一致,则调用 OrientationListeneronProposedRotationChanged 方法

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 方法启动了一个任务

@Override
        public 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 方法。该方法主要

  1. 遍历调用RootWindowContainer的displayContent,调用 updateRotationUnchecked 判断是否需要旋转
  2. 当有变化的时候,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为true
                    final boolean pendingRemoteRotation = rotationChanged
                            && (displayContent.getDisplayRotation().isWaitingForRemoteRotation()
                            || displayContent.mTransitionController.isCollecting());
}

displayContent的updateRotationUnchecked,又会调用 mDisplayRotationupdateRotationUnchecked 方法

  1. 判断是否有没在动画过程,判断有则返回false
  2. 通过 mService.mDisplayFrozen 判断是否冻结
  3. 调用 rotationForOrientation 结合当前的app屏幕配置 和当前屏幕的旋转角度,计算对应旋转角度
  4. 如果计算出来和当前一样,则不处理
  5. 将计算出来的角度赋值给变量mRotation这里更新了DisplayRotation的最新角度
  6. 标记 WMS 为冻屏,并启动一个延时任务
  7. 判断是否马上进行旋转,一般不是 会调用prepareNormalRotationAnimation 不是的话准备进退出动画资源,一般都为0非自定义
  8. 调用 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;
        }
        // 将要旋转的角度赋值给rotation
        mRotation = rotation;
        // 设置标记mLayoutNeeded为true
        mDisplayContent.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 给到systemUi
        startRemoteRotation(oldRotation, mRotation);
}

2.1 旋转的判断

rotationForOrientation 方法

  1. 通过mOrientationListener.getProposedRotation() 获取传感器当前的角度。
  2. 计算要的角度,并保存到 preferredRotation变量。
  3. 最后根据这些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 主要

  1. 通过 selectRotationAnimation 方法,选出exit,enter 的动画资源ID,正常都没自定义动画,都是返回0
  2. 在调用 WMS 的 startFreezingDisplay , 开始冻结。
	void prepareNormalRotationAnimation() {
        cancelSeamlessRotation();
        // 返回全屏窗口进入和退出动画,不是值为0
        final RotationAnimationPair anim = selectRotationAnimation();
        // 开启冻结屏幕
        mService.startFreezingDisplay(anim.mExit, anim.mEnter, mDisplayContent);
    }

2.3 屏幕冻结

startFreezingDisplay 方法主要

  1. 判断标志位mDisplayFrozen是否为true已冻结,是的话返回,否则 将标志位 mDisplayFrozen 置为true
  2. 将对应的进出动画资源保存下来
  3. 创建ScreenRotationAnimation动画管理类
  4. 调用 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 将创建的赋值给变量mScreenRotationAnimation
        displayContent.setRotationAnimation(new ScreenRotationAnimation(displayContent,
                originalRotation));
    }

2.4 通知systemUi,并等待回调

startRemoteRotation 会传入对应新旧角度

  1. 标记变量 mIsWaitingForRemoteRotation 为 true
  2. 调用 WMS 的DisplayRotationControlleronRotateDisplay 方法,通知SystemUI 开始旋转。,并且传入参数为AIDL 的 mRemoteRotationCallback
  3. 回调接收到后,会通过handle 发送消息,触发 continueRotation 方法。
	private void startRemoteRotation(int fromRotation, int toRotation) {
        if (mService.mDisplayRotationController == null) {
            return;
        }
        // 设置标记为为true
        mIsWaitingForRemoteRotation = 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() {
                @Override
                public 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 方法

  1. 会判断 isWaitingForRemoteRotation 方法是否在等待更新中
  2. 调用 updateDisplayOverrideConfigurationLocked 开始更新,并返回是否要更新的操作
	void sendNewConfiguration() {
        if (!isReady()) {
            return;
        }
        // 这里也会判断
        if (mDisplayRotation.isWaitingForRemoteRotation()) {
            return;
        }
        // 在这里会判断是否需要更新,并更新对应的display信息
        final boolean configUpdated = updateDisplayOverrideConfigurationLocked();
        if (configUpdated) {
            return;
        }
        ...
   }

updateDisplayOverrideConfigurationLocked 方法

  1. 创建 Configuration 变量
  2. 将创建的 Configuration 变量 传进入 computeScreenConfiguration方法开始计算,计算后并更新到该变量
  3. 将更新好的变量传进 updateDisplayOverrideConfigurationLocked开始更新
	boolean updateDisplayOverrideConfigurationLocked() {
        ...
        // 创建新的Configuration
        Configuration 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 方法主要用于计算对应的角度

  1. 调用updateDisplayAndOrientation ,更新对应的DisplayInfo信息,这时候更新displayInfo的rotation
  2. calculateBounds 计算显示范围 保存mTmpBounds
  3. 将其他信息更新 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,传进去,开始更新

  1. 调用 ATMS的 updateGlobalConfigurationLocked 方法,开始通知各个app
  2. 调用 ensureConfigAndVisibilityAfterUpdatedeferResume为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的方法,开始通知各个app
                    changes = 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 方法进行通知操作

  1. 调用 updateFrom 判断对应的配置跟当前是否改变,并赋值给mTempConfig ,并判断是否有改变,没改变返回0
  2. 打印对应改变
  3. 获取每个进程,调用对应appliciton的onConfigurationChanged进行通知,此时调用的WindowProcessControlleronConfigurationChanged
  4. 发送广播通知,在AMS发送
  5. rootWindowContatiner 开始遍历,通知各个窗口
int updateGlobalConfigurationLocked(@NonNull Configuration values, boolean initLocale,
            boolean persistent, int userId) {

        mTempConfig.setTo(getGlobalConfiguration());
        // 判断对应的配置跟当前是否改变,并赋值给mTempConfig
        final int changes = mTempConfig.updateFrom(values);
        if (changes == 0) {
            return 0;
        }
        ...
        // 打印改变
        Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + mTempConfig);
        ...
        // 获取每个进程,调用对应appliciton的onConfigurationChanged
        SparseArray<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 方法

	@Override
    public void onConfigurationChanged(Configuration newGlobalConfig) {
        // 因为没子类,所以不会dispatchConfigurationToChild
        super.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 容器的大小通知

容器的通知从 rootWindowContatineronConfigurationChanged开始,该super方法在 ConfigurationContainer 中,在里面调用 dispatchConfigurationToChild

	@Override
    public void onConfigurationChanged(Configuration newParentConfig) {
        // 在super方法进行处理,里面会调用 dispatchConfigurationToChild
        super.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.

	@Override
    void dispatchConfigurationToChild(DisplayContent child, Configuration config) {
        if (child.isDefaultDisplay) {
            // The global configuration is also the override configuration of default display.
            // 默认屏幕走 performDisplayOverrideConfigUpdate,调用displayContent的performDisplayOverrideConfigUpdate
            child.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 主要内容

  1. 通过 getRequestedOverrideConfiguration 获取当前的配置
  2. overrideConfiguration获取要旋转的角度
  3. 判断是否角度改变,,调用 applyRotation 重新设置矩阵,这时候角度变了applyRotationAndFinishFixedRotation 会调用 applyRotation 方法。然后获取之前构建的 ScreenRotationAnimation,在调用 他的 setRotation,更新矩阵
  4. 调用基类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的方法判断显示区域是否变化,变化则执行onResize
        super.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 的时候已经构建了screenRotationAnimation
        ScreenRotationAnimation screenRotationAnimation = rotateSeamlessly
                ? null : getRotationAnimation();
       ...
        if (screenRotationAnimation != null && screenRotationAnimation.hasScreenshot()) {
            // 再次调用setRotation设置变换矩阵
            screenRotationAnimation.setRotation(transaction, rotation);
        }
        ...
    }

WindowContaineronRequestedOverrideConfigurationChanged方法,

  1. 又会调用ConfigurationContainer的onRequestedOverrideConfigurationChanged方法, 又会调用 onConfigurationChanged 方法,
  2. 会判断是否有大小变化,有的话执行onResize 通知
	// WindowContainer 的 onRequestedOverrideConfigurationChanged
	public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
		...
        // 又会调用ConfigurationContainer的方法
        super.onRequestedOverrideConfigurationChanged(overrideConfiguration);
        if (mParent != null) {
            mParent.onDescendantOverrideConfigurationChanged();
        }

        if (diff == BOUNDS_CHANGE_NONE) {
            return;
        }
        // 又变化执行size
        if ((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,遍历子viewdispatchConfigurationToChild
        onConfigurationChanged(parent != null ? parent.getConfiguration() : Configuration.EMPTY);
    }

经过循环都会调用到 windoState的 onResize 方法。

  1. 当有Surface的时候,并且可见,添加到 WMS的 resizingWindows 数组中。
	void onResize() {
        final ArrayList<WindowState> resizingWindows = mWmService.mResizingWindows;
        // 当dispatchConfigchange添加到MWS的 resizingWindows
        if (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

  1. 通过 getTopDisplayFocusedRootTask 获取最顶端的Task
  2. 如果有变化,通过 topRunningActivity 获取对应的 ActivityRecord
  3. 执行 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,并且有改变,获取对应的 ActivityRecord
                starting = 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 方法主要判断

  1. 通过 shouldRelaunchLocked 判断是否需要重新加载Activity.
  2. 如果需要 重建,则执行 startFreezingScreenLocked,开始冻结显示
  3. 在调用 relaunchActivityLocked 进行重建通知。
  4. 如果没变化 则调用 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则表示是因为没配置所以要变更
        // 得出这次变化是否要重启动activity
        return (changes&(~configChanged)) != 0;
    }

3.3.1 重建Activity

判断到需要 relaunch后,就会执行 startFreezingScreenLocked 方法。一直调用则会调用到 startFreezingScreen 方法。

  1. 将变量 mFreezingScreen 设置 true
  2. 注册WMS registerAppFreezeListener 对应的监听
  3. WMS 的 mAppsFreezingScreen 进行递增,只有为0的时候,才会解冻。
  4. mAppsFreezingScreen为1的时候,也会调用 WMS的startFreezingDisplay 开始冻结屏幕
  5. 在遍历下面的子容器的 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 设置为true
            mFreezingScreen = 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的重建。该方法

  1. 调用 startRelaunching 进行 标记。
  2. 创建 ActivityRelaunchItem 通知 Activity进行重建
  3. 根据情况调用 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 变量的赋值时机

  1. 当执行WindowAnimator的animate 动画时候会变为true
  2. 当执行 windowState的setOrientationChanging 会变为false
  3. 当对应需要改变的 WindowAnimator的prepareSurfaceLocked会判断是否需要改变并且还没绘制完成设置为false
void performSurfacePlacementNoTrace() {
		// 根据变量mOrientationChangeComplete 判断是否要停止冻屏
        // 该方法从 performSurfacePlacementNoTrace
        // mOrientationChangeComplete 发生改变的时机有3个
        // 1.当执行WindowAnimator的animate 动画时候会变为true
        // 2.当执行 windowState的setOrientationChanging 会变为false
        // 3.当对应需要改变的 WindowAnimator的prepareSurfaceLocked会判断是否需要改变并且还没绘制完成设置为false
        if (mOrientationChangeComplete) {
            if (mWmService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
                mWmService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
                mWmService.mLastFinishedFreezeSource = mLastWindowFreezeSource;
                mWmService.mH.removeMessages(WINDOW_FREEZE_TIMEOUT);
            }
            mWmService.stopFreezingDisplayLocked();
        }
}

执行动画的时候,变为 true

	private void animate(long frameTimeNs, long vsyncId) {
       ...
        final RootWindowContainer root = mService.mRoot;
        mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
        mBulkUpdateParams = 0;
        // 执行动画时候,变为true
        root.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)) {
                // 需要旋转的时候变为false
                mWmService.mRoot.mOrientationChangeComplete = false;
            }
        } else {
            // The orientation change is completed. If it was hidden by the animation, reshow it.
            mDisplayContent.finishFadeRotationAnimation(this);
        }
    }

当WindowStateAnimator 动画在准备的时候,

  1. 判断对应的容器是否旋转并且还没绘制好的时候
  2. 通过 waitForUnfreeze 里面isHandledToken会判断token是否为底部栏,状态栏,忽略该视图
  3. // 将当前的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 方法,会有一系列变量的判断

  1. mDisplayFrozen 判断是否有启动冻屏
  2. 判断 waitingForRemoteRotation以及mAppsFreezingScreen是否大于0,只有等于0 才执行
  3. 打印解冻的日志
  4. 调用 screenRotationAnimationdismiss 方法开始播放动画,并调用 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 window
            if (!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 方法主要逻辑

  1. 通过 deltaRotation 计算差值
  2. 根据exitAnim 和enterAnim 获取进场退出动画, 一般exitAnim 和enterAnim都为0,赋值到 mRotateExitAnimation,mRotateEnterAnimation
  3. 对 进出动画进行设置,包含时长等
  4. 调用 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,mRotateEnterAnimation
        if (exitAnim != 0 && enterAnim != 0) {
            customAnim = true;
            mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, exitAnim);
            mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, enterAnim);
            mRotateAlphaAnimation = AnimationUtils.loadAnimation(mContext,
                    R.anim.screen_rotate_alpha);
        } else {
            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);
        ...
        ...
		// 旋转动画为false
        if (customAnim) {
            mSurfaceRotationAnimationController.startCustomAnimation();
        } else {
            // 这里开始旋转动画
            mSurfaceRotationAnimationController.startScreenRotationAnimation();
        }

        return true;
    }

startScreenRotationAnimation 方法分别

  1. 调用 startDisplayRotation 启动屏幕旋转动画
  2. 调用 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

  1. 会先创建对应SurfaceAnimator,因为他不像windowState已经拥有
  2. 创建本地动画LocalAnimationAdapter
  3. 在调用 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)

http://www.kler.cn/a/581259.html

相关文章:

  • 蓝桥杯备考:排队顺序(链表)
  • 中级网络工程师面试题参考示例(3)
  • 17、UDP怎么实现可靠传输【中高频】
  • spring-boot-starter和spring-boot-starter-web的关联
  • 【实战ES】实战 Elasticsearch:快速上手与深度实践-7.2.1Kubernetes Operator部署StatefulSet
  • KNN算法原理及python代码实现
  • 量子之歌2025财年Q2财报:净利润1.3亿元,多元化探索高成长赛道
  • 一键换肤的Qt-Advanced-Stylesheets
  • 从零开始学习PX4源码10(启动过程)
  • 网络信息安全专业(710207)网络安全攻防实训室建设方案
  • Cesium 入门教程(基于 vue3)
  • ubuntu20不同版本的cudnn切换
  • DeepSeek与Excel实现自动化办公:从基础到进阶的全面指南
  • PROC程序报无效的字符串或缓冲区长度问题
  • 初阶数据结构(C语言实现)——4.2队列
  • 支持selenium的chrome driver更新到134.0.6998.88
  • 13.boost项目总结(C++)
  • CoreWeave:从“微软专供”到OpenAI的座上宾
  • WPF 元素周期表
  • c++学习之QT综合项目一