Android屏幕旋转DisplayRotation - Android15
- 1、初始化监听WindowOrientationListener
-
- [1.1 updateOrientationListenerLw状态更新](#1.1 updateOrientationListenerLw状态更新)
- [1.2 WindowOrientationListener中SensorEventListener处理](#1.2 WindowOrientationListener中SensorEventListener处理)
- [2、 DisplayRotation界面方向更新](#2、 DisplayRotation界面方向更新)
-
- [2.1 传递给屏幕对应的`LogicalDisplay`](#2.1 传递给屏幕对应的
LogicalDisplay) - [2.2 通过`LogicalDisplay`传递给`SurfaceComposerClient`](#2.2 通过
LogicalDisplay传递给SurfaceComposerClient)
- [2.1 传递给屏幕对应的`LogicalDisplay`](#2.1 传递给屏幕对应的
- 3、灭屏时注销OrientationJudge监听
1、初始化监听WindowOrientationListener
Android主副屏显示-Android14 每个屏幕对应
LogicalDisplay,添加对应DisplayContent,而DisplayRotation是DisplayContent成员。
DisplayRotation中初始化:
OrientationListener继承WindowOrientationListenermSettingsObserver.observe()中判断启用mOrientationListener.enable()
frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java
java
DisplayRotation(WindowManagerService service, DisplayContent displayContent,
DisplayAddress displayAddress, DisplayPolicy displayPolicy,
DisplayWindowSettings displayWindowSettings, Context context, Object lock,
@NonNull DeviceStateController deviceStateController,
@NonNull DisplayRotationCoordinator displayRotationCoordinator) {
//.....................
if (isDefaultDisplay) {
final Handler uiHandler = UiThread.getHandler();
mOrientationListener =
new OrientationListener(mContext, uiHandler, defaultRotation);
mOrientationListener.setCurrentRotation(mRotation);
mSettingsObserver = new SettingsObserver(uiHandler);
mSettingsObserver.observe();
if (mSupportAutoRotation && isFoldable(mContext)) {
mFoldController = new FoldController();
} else {
mFoldController = null;
}
} else {
mFoldController = null;
}
}
1.1 updateOrientationListenerLw状态更新
屏幕关闭,如果已启用,则应始终禁用监听器。
屏幕已打开,当前app具有基于传感器的方向,如果尚未启用,请启用监听器。
屏幕已打开,当前app没有传感器方向,如果已启用,请禁用侦听器。
屏幕已打开,当前app具有基于传感器的方向,如果需要,可以启用监听器。
屏幕已打开,当前app具有基于鼻传感器的方向,什么都不做。
frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java
java
private void updateOrientationListenerLw() {
if (mOrientationListener == null || !mOrientationListener.canDetectOrientation()) {
// If sensor is turned off or nonexistent for some reason.
return;
}
final boolean screenOnEarly = mDisplayPolicy.isScreenOnEarly();
final boolean awake = mDisplayPolicy.isAwake();
final boolean keyguardDrawComplete = mDisplayPolicy.isKeyguardDrawComplete();
final boolean windowManagerDrawComplete = mDisplayPolicy.isWindowManagerDrawComplete();
// Could have been invoked due to screen turning on or off or
// change of the currently visible window's orientation.
ProtoLog.v(WM_DEBUG_ORIENTATION,
"screenOnEarly=%b, awake=%b, currentAppOrientation=%d, "
+ "orientationSensorEnabled=%b, keyguardDrawComplete=%b, "
+ "windowManagerDrawComplete=%b",
screenOnEarly, awake, mCurrentAppOrientation, mOrientationListener.mEnabled,
keyguardDrawComplete, windowManagerDrawComplete);
boolean disable = true;
// If the orientation listener uses a wake sensor, keep the orientation listener on if the
// screen is on (regardless of wake state). This allows the AoD to rotate.
//
// Note: We postpone the rotating of the screen until the keyguard as well as the
// window manager have reported a draw complete or the keyguard is going away in dismiss
// mode.
if (screenOnEarly
&& (awake || mOrientationListener.shouldStayEnabledWhileDreaming())
&& ((keyguardDrawComplete && windowManagerDrawComplete))) {
if (needSensorRunning()) {
disable = false;
// Enable listener if not already enabled.
if (!mOrientationListener.mEnabled) {
mOrientationListener.enable();
}
}
}
// Check if sensors need to be disabled.
if (disable) {
mOrientationListener.disable();
}
}
1.2 WindowOrientationListener中SensorEventListener处理
1、
TYPE_DEVICE_ORIENTATION优先使用该sensor,并且优先使用该sensor的WakeUp类型,使用继承SensorEventListener的OrientationSensorJudge处理数据,int reportedRotation = (int) event.values[0];直接上方向,不需要额外处理2、
TYPE_ACCELEROMETER默认USE_GRAVITY_SENSOR = false,所以使用该sensor,使用继承SensorEventListener的AccelSensorJudge处理数据,比较复杂,最终isTiltAngleAcceptableLocked(nearestRotation, tiltAngle) && isOrientationAngleAcceptableLocked(nearestRotation, orientationAngle)各种角度计算后赋值给mPredictedRotation3、最终传感器方向赋值给
mProposedRotation,通过mOrientationListener.getProposedRotation()获取sensor方向
java
private WindowOrientationListener(Context context, Handler handler,
@Surface.Rotation int defaultRotation, int rate) {
mContext = context;
mHandler = handler;
mDefaultRotation = defaultRotation;
mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
mRate = rate;
List<Sensor> l = mSensorManager.getSensorList(Sensor.TYPE_DEVICE_ORIENTATION);
Sensor wakeUpDeviceOrientationSensor = null;
Sensor nonWakeUpDeviceOrientationSensor = null;
/**
* Prefer the wakeup form of the sensor if implemented.
* It's OK to look for just two types of this sensor and use
* the last found. Typical devices will only have one sensor of
* this type.
*/
for (Sensor s : l) {
if (s.isWakeUpSensor()) {
wakeUpDeviceOrientationSensor = s;
} else {
nonWakeUpDeviceOrientationSensor = s;
}
}
if (wakeUpDeviceOrientationSensor != null) {
mSensor = wakeUpDeviceOrientationSensor;
} else {
mSensor = nonWakeUpDeviceOrientationSensor;
}
if (mSensor != null) {
mOrientationJudge = new OrientationSensorJudge();
}
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);
}
}
}
2、 DisplayRotation界面方向更新
2.1 传递给屏幕对应的LogicalDisplay
1、
updateRotationUnchecked > rotationForOrientation > mRotation = rotation;对象mRotation更新2、通过
DisplayContent中setDisplayInfoOverride()将包含方向信息mDisplayInfo传递给LogicalDisplay中mOverrideDisplayInfo
frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java
java
int rotationForOrientation(@ScreenOrientation int orientation,
@Surface.Rotation int lastRotation) {
ProtoLog.v(WM_DEBUG_ORIENTATION,
"rotationForOrientation(orient=%s (%d), last=%s (%d)); user=%s (%d) %s",
ActivityInfo.screenOrientationToString(orientation), orientation,
Surface.rotationToString(lastRotation), lastRotation,
Surface.rotationToString(mUserRotation), mUserRotation,
mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED
? "USER_ROTATION_LOCKED" : "");
if (isFixedToUserRotation()) {
return mUserRotation;
}
@Surface.Rotation
int sensorRotation = mOrientationListener != null
? mOrientationListener.getProposedRotation() // may be -1
: -1;
if (mFoldController != null && mFoldController.shouldIgnoreSensorRotation()) {
sensorRotation = -1;
}
if (mDeviceStateController.shouldReverseRotationDirectionAroundZAxis(mDisplayContent)) {
sensorRotation = RotationUtils.reverseRotationDirectionAroundZAxis(sensorRotation);
}
mLastSensorRotation = sensorRotation;
if (sensorRotation < 0) {
sensorRotation = lastRotation;
}
final int lidState = mDisplayPolicy.getLidState();
final int dockMode = mDisplayPolicy.getDockMode();
final boolean hdmiPlugged = mDisplayPolicy.isHdmiPlugged();
final boolean carDockEnablesAccelerometer =
mDisplayPolicy.isCarDockEnablesAccelerometer();
final boolean deskDockEnablesAccelerometer =
mDisplayPolicy.isDeskDockEnablesAccelerometer();
@Surface.Rotation
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 (lidState == LID_OPEN && mLidOpenRotation >= 0) {
// Ignore sensor when lid switch is open and rotation is forced.
preferredRotation = mLidOpenRotation;
} else if (dockMode == Intent.EXTRA_DOCK_STATE_CAR
&& (carDockEnablesAccelerometer || mCarDockRotation >= 0)) {
// Ignore sensor when in car dock unless explicitly enabled.
// This case can override the behavior of NOSENSOR, and can also
// enable 180 degree rotation while docked.
preferredRotation = carDockEnablesAccelerometer ? sensorRotation : mCarDockRotation;
} else if ((dockMode == Intent.EXTRA_DOCK_STATE_DESK
|| dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
|| dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK)
&& (deskDockEnablesAccelerometer || mDeskDockRotation >= 0)
&& !(orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED
|| orientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR)) {
// Ignore sensor when in desk dock unless explicitly enabled.
// This case can enable 180 degree rotation while docked.
preferredRotation = deskDockEnablesAccelerometer ? sensorRotation : mDeskDockRotation;
} else if (hdmiPlugged && mDemoHdmiRotationLock) {
// Ignore sensor when plugged into HDMI when demo HDMI rotation lock enabled.
// Note that the dock orientation overrides the HDMI orientation.
preferredRotation = mDemoHdmiRotation;
} else if (hdmiPlugged && dockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED
&& mUndockedHdmiRotation >= 0) {
// Ignore sensor when plugged into HDMI and an undocked orientation has
// been specified in the configuration (only for legacy devices without
// full multi-display support).
// Note that the dock orientation overrides the HDMI orientation.
preferredRotation = mUndockedHdmiRotation;
} else if (mDemoRotationLock) {
// Ignore sensor when demo rotation lock is enabled.
// Note that the dock orientation and HDMI rotation lock override this.
preferredRotation = mDemoRotation;
} else if (mDisplayPolicy.isPersistentVrModeEnabled()) {
// While in VR, apps always prefer a portrait rotation. This does not change
// any apps that explicitly set landscape, but does cause sensors be ignored,
// and ignored any orientation lock that the user has set (this conditional
// should remain above the ORIENTATION_LOCKED conditional below).
preferredRotation = mPortraitRotation;
} else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
// Application just wants to remain locked in the last rotation.
preferredRotation = lastRotation;
} else if (!mSupportAutoRotation) {
if (mFixedToUserRotation == IWindowManager.FIXED_TO_USER_ROTATION_IF_NO_AUTO_ROTATION) {
preferredRotation = mUserRotation;
} else {
// If we don't support auto-rotation then bail out here and ignore
// the sensor and any rotation lock settings.
preferredRotation = -1;
}
} else if (((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE
|| isTabletopAutoRotateOverrideEnabled())
&& (orientation == ActivityInfo.SCREEN_ORIENTATION_USER
|| orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|| orientation == ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
|| orientation == ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
|| orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER))
|| orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
|| orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
|| orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|| orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) {
// Otherwise, use sensor only if requested by the application or enabled
// by default for USER or UNSPECIFIED modes. Does not apply to NOSENSOR.
if (sensorRotation != Surface.ROTATION_180
|| getAllowAllRotations() == ALLOW_ALL_ROTATIONS_ENABLED
|| orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
|| orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER) {
preferredRotation = sensorRotation;
} else {
preferredRotation = lastRotation;
}
} 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) {
// Apply rotation lock. Does not apply to NOSENSOR or specific rotations.
// The idea is that the user rotation expresses a weak preference for the direction
// of gravity and as NOSENSOR is never affected by gravity, then neither should
// NOSENSOR be affected by rotation lock (although it will be affected by docks).
// Also avoid setting user rotation when app has preference over one particular rotation
// to avoid leaving the rotation to the reverse of it which has the compatible
// orientation, but isn't what app wants, when the user rotation is the reverse of the
// preferred rotation.
preferredRotation = mUserRotation;
} else {
// No overriding preference.
// We will do exactly what the application asked us to do.
preferredRotation = -1;
}
switch (orientation) {
case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
// Return portrait unless overridden.
if (isAnyPortrait(preferredRotation)) {
return preferredRotation;
}
return mPortraitRotation;
case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
// Return landscape unless overridden.
if (isLandscapeOrSeascape(preferredRotation)) {
return preferredRotation;
}
return mLandscapeRotation;
case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
// Return reverse portrait unless overridden.
if (isAnyPortrait(preferredRotation)) {
return preferredRotation;
}
return mUpsideDownRotation;
case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
// Return seascape unless overridden.
if (isLandscapeOrSeascape(preferredRotation)) {
return preferredRotation;
}
return mSeascapeRotation;
case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:
// Return either landscape rotation.
if (isLandscapeOrSeascape(preferredRotation)) {
return preferredRotation;
}
if (isLandscapeOrSeascape(lastRotation)) {
return lastRotation;
}
return mLandscapeRotation;
case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:
// Return either portrait rotation.
if (isAnyPortrait(preferredRotation)) {
return preferredRotation;
}
if (isAnyPortrait(lastRotation)) {
return lastRotation;
}
return mPortraitRotation;
default:
// For USER, UNSPECIFIED, NOSENSOR, SENSOR and FULL_SENSOR,
// just return the preferred orientation we already calculated.
if (preferredRotation >= 0) {
return preferredRotation;
}
return Surface.ROTATION_0;
}
}
frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
java
private void setDisplayInfoOverride() {
mWmService.mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(mDisplayId,
mDisplayInfo);
if (mLastDisplayInfoOverride == null) {
mLastDisplayInfoOverride = new DisplayInfo();
}
mLastDisplayInfoOverride.copyFrom(mDisplayInfo);
}
private DisplayInfo updateDisplayAndOrientation(Configuration outConfig) {
// Use the effective "visual" dimensions based on current rotation
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;
// Update application display metrics.
final DisplayCutout displayCutout = calculateDisplayCutoutForRotation(rotation);
final RoundedCorners roundedCorners = calculateRoundedCornersForRotation(rotation);
final DisplayShape displayShape = calculateDisplayShapeForRotation(rotation);
final Rect appFrame = mDisplayPolicy.getDecorInsetsInfo(rotation, dw, dh).mNonDecorFrame;
mDisplayInfo.rotation = rotation;
mDisplayInfo.logicalWidth = dw;
mDisplayInfo.logicalHeight = dh;
mDisplayInfo.logicalDensityDpi = mBaseDisplayDensity;
mDisplayInfo.physicalXDpi = mBaseDisplayPhysicalXDpi;
mDisplayInfo.physicalYDpi = mBaseDisplayPhysicalYDpi;
mDisplayInfo.appWidth = appFrame.width();
mDisplayInfo.appHeight = appFrame.height();
if (isDefaultDisplay) {
mDisplayInfo.getLogicalMetrics(mRealDisplayMetrics,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
}
mDisplayInfo.displayCutout = displayCutout.isEmpty() ? null : displayCutout;
mDisplayInfo.roundedCorners = roundedCorners;
mDisplayInfo.displayShape = displayShape;
mDisplayInfo.getAppMetrics(mDisplayMetrics);
if (mDisplayScalingDisabled) {
mDisplayInfo.flags |= Display.FLAG_SCALING_DISABLED;
} else {
mDisplayInfo.flags &= ~Display.FLAG_SCALING_DISABLED;
}
computeSizeRanges(mDisplayInfo, rotated, dw, dh, mDisplayMetrics.density, outConfig,
false /* overrideConfig */);
setDisplayInfoOverride();
if (isDefaultDisplay) {
mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(mDisplayMetrics,
mCompatDisplayMetrics);
}
onDisplayInfoChanged();
return mDisplayInfo;
}
frameworks/base/services/core/java/com/android/server/display/LogicalDisplay.java
java
public boolean setDisplayInfoOverrideFromWindowManagerLocked(DisplayInfo info) {
if (info != null) {
if (mOverrideDisplayInfo == null) {
mOverrideDisplayInfo = new DisplayInfo(info);
mInfo.set(null);
return true;
} else if (!mOverrideDisplayInfo.equals(info)) {
mOverrideDisplayInfo.copyFrom(info);
mInfo.set(null);
return true;
}
} else if (mOverrideDisplayInfo != null) {
mOverrideDisplayInfo = null;
mInfo.set(null);
return true;
}
return false;
}
2.2 通过LogicalDisplay传递给SurfaceComposerClient
- Android主副屏显示-Android14 中
configureDisplayLocked刷新获取displayInfo = getDisplayInfoLocked();, 新增DisplayInfoOverrides.java单独处理device.setProjectionLocked(t, orientation, mTempLayerStackRect, mTempDisplayRect):最终更新到sf中SurfaceComposerClient::Transaction::setDisplayProjection- 内置屏幕才包含
FLAG_ROTATES_WITH_CONTENT,跟随逻辑屏旋转orientation = displayInfo.rotation;
frameworks/base/services/core/java/com/android/server/wm/utils/DisplayInfoOverrides.java
java
/**
* Set of DisplayInfo fields that are overridden in DisplayManager using values from
* WindowManager
*/
public static final DisplayInfoFieldsUpdater WM_OVERRIDE_FIELDS = (out, source) -> {
out.appWidth = source.appWidth;
out.appHeight = source.appHeight;
out.smallestNominalAppWidth = source.smallestNominalAppWidth;
out.smallestNominalAppHeight = source.smallestNominalAppHeight;
out.largestNominalAppWidth = source.largestNominalAppWidth;
out.largestNominalAppHeight = source.largestNominalAppHeight;
out.logicalWidth = source.logicalWidth;
out.logicalHeight = source.logicalHeight;
out.physicalXDpi = source.physicalXDpi;
out.physicalYDpi = source.physicalYDpi;
out.rotation = source.rotation;
out.displayCutout = source.displayCutout;
out.logicalDensityDpi = source.logicalDensityDpi;
out.roundedCorners = source.roundedCorners;
out.displayShape = source.displayShape;
};
/**
* Gets {@param base} DisplayInfo, overrides WindowManager-specific overrides using
* {@param override} and writes the result to {@param out}
*/
public static void copyDisplayInfoFields(@NonNull DisplayInfo out,
@NonNull DisplayInfo base,
@Nullable DisplayInfo override,
@NonNull DisplayInfoFieldsUpdater fields) {
out.copyFrom(base);
if (override != null) {
fields.setFields(out, override);
}
}
frameworks/base/services/core/java/com/android/server/display/LogicalDisplay.java
java
public void configureDisplayLocked(SurfaceControl.Transaction t,
DisplayDevice device,
boolean isBlanked) {
// Set the layer stack.
device.setLayerStackLocked(t, isBlanked ? BLANK_LAYER_STACK : mLayerStack, mDisplayId);
// Also inform whether the device is the same one sent to inputflinger for its layerstack.
// Prevent displays that are disabled from receiving input.
// TODO(b/188914255): Remove once input can dispatch against device vs layerstack.
device.setDisplayFlagsLocked(t,
(isEnabledLocked() && device.getDisplayDeviceInfoLocked().touch != TOUCH_NONE)
? SurfaceControl.DISPLAY_RECEIVES_INPUT
: 0);
// Set the color mode and allowed display mode.
if (device == mPrimaryDisplayDevice) {
device.setDesiredDisplayModeSpecsLocked(mDesiredDisplayModeSpecs);
device.setRequestedColorModeLocked(mRequestedColorMode);
} else {
// Reset to default for non primary displays
device.setDesiredDisplayModeSpecsLocked(
new DisplayModeDirector.DesiredDisplayModeSpecs());
device.setRequestedColorModeLocked(0);
}
device.setAutoLowLatencyModeLocked(mRequestedMinimalPostProcessing);
device.setGameContentTypeLocked(mRequestedMinimalPostProcessing);
// Only grab the display info now as it may have been changed based on the requests above.
final DisplayInfo displayInfo = getDisplayInfoLocked();
final DisplayDeviceInfo displayDeviceInfo = device.getDisplayDeviceInfoLocked();
// Set the viewport.
// This is the area of the logical display that we intend to show on the
// display device. For now, it is always the full size of the logical display.
mTempLayerStackRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
// Set the orientation.
// The orientation specifies how the physical coordinate system of the display
// is rotated when the contents of the logical display are rendered.
int orientation = Surface.ROTATION_0;
// FLAG_ROTATES_WITH_CONTENT is now handled in DisplayContent. When the flag
// mAlwaysRotateDisplayDeviceEnabled is removed, we should also remove this check for
// ROTATES_WITH_CONTENT here and always set the orientation.
if ((displayDeviceInfo.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0
|| mAlwaysRotateDisplayDeviceEnabled) {
orientation = displayInfo.rotation;
}
// Apply the physical rotation of the display device itself.
orientation = (orientation + displayDeviceInfo.rotation) % 4;
// Set the frame.
// The frame specifies the rotated physical coordinates into which the viewport
// is mapped. We need to take care to preserve the aspect ratio of the viewport.
// Currently we maximize the area to fill the display, but we could try to be
// more clever and match resolutions.
boolean rotated = (orientation == Surface.ROTATION_90
|| orientation == Surface.ROTATION_270);
int physWidth = rotated ? displayDeviceInfo.height : displayDeviceInfo.width;
int physHeight = rotated ? displayDeviceInfo.width : displayDeviceInfo.height;
Rect maskingInsets = getMaskingInsets(displayDeviceInfo);
InsetUtils.rotateInsets(maskingInsets, orientation);
// Don't consider the masked area as available when calculating the scaling below.
physWidth -= maskingInsets.left + maskingInsets.right;
physHeight -= maskingInsets.top + maskingInsets.bottom;
var displayLogicalWidth = displayInfo.logicalWidth;
var displayLogicalHeight = displayInfo.logicalHeight;
if (mIsAnisotropyCorrectionEnabled && displayDeviceInfo.type == Display.TYPE_EXTERNAL
&& displayDeviceInfo.xDpi > 0 && displayDeviceInfo.yDpi > 0) {
if (displayDeviceInfo.xDpi > displayDeviceInfo.yDpi * DisplayDevice.MAX_ANISOTROPY) {
var scalingFactor = displayDeviceInfo.yDpi / displayDeviceInfo.xDpi;
if (rotated) {
displayLogicalWidth = (int) ((float) displayLogicalWidth * scalingFactor + 0.5);
} else {
displayLogicalHeight = (int) ((float) displayLogicalHeight * scalingFactor
+ 0.5);
}
} else if (displayDeviceInfo.xDpi * DisplayDevice.MAX_ANISOTROPY
< displayDeviceInfo.yDpi) {
var scalingFactor = displayDeviceInfo.xDpi / displayDeviceInfo.yDpi;
if (rotated) {
displayLogicalHeight = (int) ((float) displayLogicalHeight * scalingFactor
+ 0.5);
} else {
displayLogicalWidth = (int) ((float) displayLogicalWidth * scalingFactor + 0.5);
}
}
}
// Determine whether the width or height is more constrained to be scaled.
// physWidth / displayInfo.logicalWidth => letter box
// or physHeight / displayInfo.logicalHeight => pillar box
//
// We avoid a division (and possible floating point imprecision) here by
// multiplying the fractions by the product of their denominators before
// comparing them.
int displayRectWidth, displayRectHeight;
if ((displayInfo.flags & Display.FLAG_SCALING_DISABLED) != 0 || mDisplayScalingDisabled) {
displayRectWidth = displayLogicalWidth;
displayRectHeight = displayLogicalHeight;
} else if (physWidth * displayLogicalHeight
< physHeight * displayLogicalWidth) {
// Letter box.
displayRectWidth = physWidth;
displayRectHeight = displayLogicalHeight * physWidth / displayLogicalWidth;
} else {
// Pillar box.
displayRectWidth = displayLogicalWidth * physHeight / displayLogicalHeight;
displayRectHeight = physHeight;
}
int displayRectTop = (physHeight - displayRectHeight) / 2;
int displayRectLeft = (physWidth - displayRectWidth) / 2;
mTempDisplayRect.set(displayRectLeft, displayRectTop,
displayRectLeft + displayRectWidth, displayRectTop + displayRectHeight);
// Now add back the offset for the masked area.
mTempDisplayRect.offset(maskingInsets.left, maskingInsets.top);
if (orientation == Surface.ROTATION_0) {
mTempDisplayRect.offset(mDisplayOffsetX, mDisplayOffsetY);
} else if (orientation == Surface.ROTATION_90) {
mTempDisplayRect.offset(mDisplayOffsetY, -mDisplayOffsetX);
} else if (orientation == Surface.ROTATION_180) {
mTempDisplayRect.offset(-mDisplayOffsetX, -mDisplayOffsetY);
} else { // Surface.ROTATION_270
mTempDisplayRect.offset(-mDisplayOffsetY, mDisplayOffsetX);
}
mDisplayPosition.set(mTempDisplayRect.left, mTempDisplayRect.top);
device.setProjectionLocked(t, orientation, mTempLayerStackRect, mTempDisplayRect);
}
3、灭屏时注销OrientationJudge监听
DisplayRotation更新时灭屏状态screenOnEarly = mDisplayPolicy.isScreenOnEarly(),注销sensor监听,尤其是使用wake sensor
java
private void updateOrientationListenerLw() {
if (mOrientationListener == null || !mOrientationListener.canDetectOrientation()) {
// If sensor is turned off or nonexistent for some reason.
return;
}
final boolean screenOnEarly = mDisplayPolicy.isScreenOnEarly();
final boolean awake = mDisplayPolicy.isAwake();
final boolean keyguardDrawComplete = mDisplayPolicy.isKeyguardDrawComplete();
final boolean windowManagerDrawComplete = mDisplayPolicy.isWindowManagerDrawComplete();
// Could have been invoked due to screen turning on or off or
// change of the currently visible window's orientation.
ProtoLog.v(WM_DEBUG_ORIENTATION,
"screenOnEarly=%b, awake=%b, currentAppOrientation=%d, "
+ "orientationSensorEnabled=%b, keyguardDrawComplete=%b, "
+ "windowManagerDrawComplete=%b",
screenOnEarly, awake, mCurrentAppOrientation, mOrientationListener.mEnabled,
keyguardDrawComplete, windowManagerDrawComplete);
boolean disable = true;
// If the orientation listener uses a wake sensor, keep the orientation listener on if the
// screen is on (regardless of wake state). This allows the AoD to rotate.
//
// Note: We postpone the rotating of the screen until the keyguard as well as the
// window manager have reported a draw complete or the keyguard is going away in dismiss
// mode.
if (screenOnEarly
&& (awake || mOrientationListener.shouldStayEnabledWhileDreaming())
&& ((keyguardDrawComplete && windowManagerDrawComplete))) {
if (needSensorRunning()) {
disable = false;
// Enable listener if not already enabled.
if (!mOrientationListener.mEnabled) {
mOrientationListener.enable();
}
}
}
// Check if sensors need to be disabled.
if (disable) {
mOrientationListener.disable();
}
}