上篇博客中我们一直提到updateRotationUnchecked函数,这篇博客我们就来分析下这个函数,这个函数可以说是旋转屏幕的一个核心函数,我们主要看下updateRotationUncheckedLocked和sendNewConfiguration函数,当updateRotationUncheckedLocked返回true代表设备已经旋转,这个时候要调用sendNewConfiguration函数通知AMS来使相应的Activity重新Launch等。
-
public void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {
-
long origId = Binder.clearCallingIdentity();
-
boolean changed;
-
synchronized(mWindowMap) {
-
changed = updateRotationUncheckedLocked(
false);
-
if (!changed || forceRelayout) {
-
getDefaultDisplayContentLocked().layoutNeeded =
true;
-
performLayoutAndPlaceSurfacesLocked();
-
}
-
}
-
-
if (changed || alwaysSendConfiguration) {
-
sendNewConfiguration();
//后续分析
-
}
-
-
Binder.restoreCallingIdentity(origId);
-
}
sendNewConfiguration我们放到下篇博客分析,这里我们先分析updateRotationUncheckedLocked函数。
PhoneWindowManager的rotationForOrientationLw获取rotation
下面是部分代码,我们先调用PhoneWindowManager的rotationForOrientationLw函数来获取rotation,然后与之前的mRotation对比是否有变化,没有变化直接返回false。有变化将mRotation重新赋值。
-
......
-
int rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation);
-
boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(
-
mForcedAppOrientation, rotation);
-
-
-
if (mRotation == rotation && mAltOrientation == altOrientation) {
-
// No change.
-
return
false;
-
}
-
-
mRotation = rotation;
-
mAltOrientation = altOrientation;
-
......
PhoneWindowManager的rotationForOrientationLw函数我们就不分析了,就是获取sensor的rotation,然后计算返回我们需要的rotation。我们继续看updateRotationUncheckedLocked函数的剩下代码。
updateDisplayAndOrientationLocked DisplayInfo数据放入display中
在updateRotationUncheckedLocked中还调用了updateDisplayAndOrientationLocked函数,我们也来看下,这个函数把各种数据更新下放到DisplayInfo中,最后调用了DisplayManagerService的setDisplayInfoOverrideFromWindowManager函数
-
DisplayInfo updateDisplayAndOrientationLocked() {
-
......
-
-
// Update application display metrics.
-
final
int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation);
-
final
int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation);
-
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-
synchronized(displayContent.mDisplaySizeLock) {
-
displayInfo.rotation = mRotation;
//旋转
-
displayInfo.logicalWidth = dw;
-
displayInfo.logicalHeight = dh;
-
displayInfo.logicalDensityDpi = displayContent.mBaseDisplayDensity;
-
displayInfo.appWidth = appWidth;
-
displayInfo.appHeight = appHeight;
-
displayInfo.getLogicalMetrics(mRealDisplayMetrics,
-
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
-
displayInfo.getAppMetrics(mDisplayMetrics);
-
if (displayContent.mDisplayScalingDisabled) {
-
displayInfo.flags |= Display.FLAG_SCALING_DISABLED;
-
}
else {
-
displayInfo.flags &= ~Display.FLAG_SCALING_DISABLED;
-
}
-
-
mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(
-
displayContent.getDisplayId(), displayInfo);
setDisplayInfoOverrideFromWindowManager就是调用了setDisplayInfoOverrideFromWindowManagerInternal
-
@
Override
-
public
void
setDisplayInfoOverrideFromWindowManager
(int displayId, DisplayInfo info) {
-
setDisplayInfoOverrideFromWindowManagerInternal(displayId, info);
-
}
setDisplayInfoOverrideFromWindowManagerInternal函数找到相应的display然后调用其setDisplayInfoOverrideFromWindowManagerLocked函数。
-
private void setDisplayInfoOverrideFromWindowManagerInternal(
-
int displayId, DisplayInfo info) {
-
synchronized (mSyncRoot) {
-
LogicalDisplay display = mLogicalDisplays.get(displayId);
-
if (display != null) {
-
if (display.setDisplayInfoOverrideFromWindowManagerLocked(info)) {
-
sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
-
scheduleTraversalLocked(
false);
-
}
-
}
-
}
-
}
最后到LogicalDisplay的setDisplayInfoOverrideFromWindowManagerLocked函数中,把DisplayInfo数据放到了mOverrideDisplayInfo中
-
public boolean setDisplayInfoOverrideFromWindowManagerLocked(DisplayInfo info) {
-
if (info != null) {
-
if (mOverrideDisplayInfo == null) {
-
mOverrideDisplayInfo =
new DisplayInfo(info);
-
mInfo = null;
-
return
true;
-
}
-
if (!mOverrideDisplayInfo.equals(info)) {
-
mOverrideDisplayInfo.copyFrom(info);
-
mInfo = null;
-
return
true;
-
}
-
}
else
if (mOverrideDisplayInfo != null) {
-
mOverrideDisplayInfo = null;
-
mInfo = null;
-
return
true;
-
}
-
return
false;
-
}
设置设备旋转
然后在updateRotationUncheckedLocked又调用了如下代码:
mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
这样我们又到了DisplayManagerService的performTraversalInTransactionFromWindowManager函数,然后又调用了performTraversalInTransactionFromWindowManagerInternal函数,我们来看下
-
private void performTraversalInTransactionFromWindowManagerInternal() {
-
synchronized (mSyncRoot) {
-
if (!mPendingTraversal) {
-
return;
-
}
-
mPendingTraversal =
false;
-
-
performTraversalInTransactionLocked();
-
}
-
-
// List is self-synchronized copy-on-write.
-
for (DisplayTransactionListener listener : mDisplayTransactionListeners) {
-
listener.onDisplayTransaction();
-
}
-
}
performTraversalInTransactionLocked函数,遍历所有的Device,先调用了configureDisplayInTransactionLocked函数,然后调用了各个Device的performTraversalInTransactionLocked,而普通的Device的为空,因此这里我们不关注这个函数。
-
private void performTraversalInTransactionLocked() {
-
// Clear all viewports before configuring displays so that we can keep
-
// track of which ones we have configured.
-
clearViewportsLocked();
-
-
// Configure each display device.
-
final
int count = mDisplayDevices.size();
-
for (
int i =
0; i < count; i++) {
-
DisplayDevice device = mDisplayDevices.get(i);
-
configureDisplayInTransactionLocked(device);
-
device.performTraversalInTransactionLocked();
-
}
-
-
// Tell the input system about these new viewports.
-
if (mInputManagerInternal != null) {
-
mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT);
-
}
-
}
下面我们主要看configureDisplayInTransactionLocked函数,这个函数就是找到那个LogicalDisplay 然后调用其configureDisplayInTransactionLocked函数
-
private void configureDisplayInTransactionLocked(DisplayDevice device) {
-
final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
-
final boolean ownContent = (info.flags & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) !=
0;
-
-
LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
-
if (!ownContent) {
-
if (display != null && !display.hasContentLocked()) {
-
// If the display does not have any content of its own, then
-
// automatically mirror the default logical display contents.
-
display = null;
-
}
-
if (display == null) {
-
display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY);
-
}
-
}
-
-
// Apply the logical display configuration to the display device.
-
if (display == null) {
-
// TODO: no logical display for the device, blank it
-
Slog.w(TAG,
"Missing logical display to use for physical display device: "
-
+ device.getDisplayDeviceInfoLocked());
-
return;
-
}
-
display.configureDisplayInTransactionLocked(device, info.state == Display.STATE_OFF);
LogicalDisplay 的configureDisplayInTransactionLocked函数,就是设置长宽,旋转角度等。
-
public void configureDisplayInTransactionLocked(DisplayDevice device,
-
boolean isBlanked) {
-
// Set the layer stack.
-
device.setLayerStackInTransactionLocked(isBlanked ? BLANK_LAYER_STACK : mLayerStack);
-
-
// Set the color transform and mode.
-
if (device == mPrimaryDisplayDevice) {
-
device.requestColorTransformAndModeInTransactionLocked(
-
mRequestedColorTransformId, mRequestedModeId);
-
}
else {
-
device.requestColorTransformAndModeInTransactionLocked(
0,
0);
// Revert to default.
-
}
-
-
// Only grab the display info now as it may have been changed based on the requests above.
-
final DisplayInfo displayInfo = getDisplayInfoLocked();
//获取mInfo
-
final DisplayDeviceInfo displayDeviceInfo = device.getDisplayDeviceInfoLocked();
//获取设备的info
-
-
// 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;
-
if ((displayDeviceInfo.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) !=
0) {
-
orientation = displayInfo.rotation;
-
}
-
-
// Apply the physical rotation of the display device itself.
-
orientation = (orientation + displayDeviceInfo.rotation) %
4;
//方向是根据传入的方向加上原有设备的方向除以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;
-
-
// 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) {
-
displayRectWidth = displayInfo.logicalWidth;
-
displayRectHeight = displayInfo.logicalHeight;
-
}
else
if (physWidth * displayInfo.logicalHeight
-
< physHeight * displayInfo.logicalWidth) {
-
// Letter box.
-
displayRectWidth = physWidth;
-
displayRectHeight = displayInfo.logicalHeight * physWidth / displayInfo.logicalWidth;
-
}
else {
-
// Pillar box.
-
displayRectWidth = displayInfo.logicalWidth * physHeight / displayInfo.logicalHeight;
-
displayRectHeight = physHeight;
-
}
-
int displayRectTop = (physHeight - displayRectHeight) /
2;
-
int displayRectLeft = (physWidth - displayRectWidth) /
2;
-
mTempDisplayRect.
set(displayRectLeft, displayRectTop,
-
displayRectLeft + displayRectWidth, displayRectTop + displayRectHeight);
-
-
mTempDisplayRect.left += mDisplayOffsetX;
-
mTempDisplayRect.right += mDisplayOffsetX;
-
mTempDisplayRect.top += mDisplayOffsetY;
-
mTempDisplayRect.bottom += mDisplayOffsetY;
-
device.setProjectionInTransactionLocked(orientation, mTempLayerStackRect, mTempDisplayRect);
-
}
我们来看下getDisplayInfoLocked函数就是获取mInfo的数据,而mOverrideDisplayInfo如有数据就要copy到mInfo中去。
-
public DisplayInfo getDisplayInfoLocked() {
-
if (mInfo == null) {
-
mInfo =
new DisplayInfo();
-
mInfo.copyFrom(mBaseDisplayInfo);
-
if (mOverrideDisplayInfo != null) {
-
mInfo.appWidth = mOverrideDisplayInfo.appWidth;
-
mInfo.appHeight = mOverrideDisplayInfo.appHeight;
-
mInfo.smallestNominalAppWidth = mOverrideDisplayInfo.smallestNominalAppWidth;
-
mInfo.smallestNominalAppHeight = mOverrideDisplayInfo.smallestNominalAppHeight;
-
mInfo.largestNominalAppWidth = mOverrideDisplayInfo.largestNominalAppWidth;
-
mInfo.largestNominalAppHeight = mOverrideDisplayInfo.largestNominalAppHeight;
-
mInfo.logicalWidth = mOverrideDisplayInfo.logicalWidth;
-
mInfo.logicalHeight = mOverrideDisplayInfo.logicalHeight;
-
mInfo.overscanLeft = mOverrideDisplayInfo.overscanLeft;
-
mInfo.overscanTop = mOverrideDisplayInfo.overscanTop;
-
mInfo.overscanRight = mOverrideDisplayInfo.overscanRight;
-
mInfo.overscanBottom = mOverrideDisplayInfo.overscanBottom;
-
mInfo.rotation = mOverrideDisplayInfo.rotation;
-
mInfo.logicalDensityDpi = mOverrideDisplayInfo.logicalDensityDpi;
-
mInfo.physicalXDpi = mOverrideDisplayInfo.physicalXDpi;
-
mInfo.physicalYDpi = mOverrideDisplayInfo.physicalYDpi;
-
}
-
}
-
return mInfo;
-
}
最后调用了DisplayDevice的setProjectionInTransactionLocked函数,然后调用了SurfaceControl的setDisplayProjection函数。
-
public final void setProjectionInTransactionLocked(int orientation,
-
Rect layerStackRect, Rect displayRect) {
-
if (mCurrentOrientation != orientation
-
|| mCurrentLayerStackRect == null
-
|| !mCurrentLayerStackRect.equals(layerStackRect)
-
|| mCurrentDisplayRect == null
-
|| !mCurrentDisplayRect.equals(displayRect)) {
-
mCurrentOrientation = orientation;
-
-
if (mCurrentLayerStackRect == null) {
-
mCurrentLayerStackRect =
new Rect();
-
}
-
mCurrentLayerStackRect.
set(layerStackRect);
-
-
if (mCurrentDisplayRect == null) {
-
mCurrentDisplayRect =
new Rect();
-
}
-
mCurrentDisplayRect.
set(displayRect);
-
-
SurfaceControl.setDisplayProjection(mDisplayToken,
-
orientation, layerStackRect, displayRect);
-
}
-
}
SurfaceControl.setDisplayProjection函数如下,这个函数最后又调用了JNI函数,最后是根据mDisplayToken来设置到相应的设备中去。
-
public static void setDisplayProjection(IBinder displayToken,
-
int orientation, Rect layerStackRect, Rect displayRect) {
-
if (displayToken == null) {
-
throw
new IllegalArgumentException(
"displayToken must not be null");
-
}
-
if (layerStackRect == null) {
-
throw
new IllegalArgumentException(
"layerStackRect must not be null");
-
}
-
if (displayRect == null) {
-
throw
new IllegalArgumentException(
"displayRect must not be null");
-
}
-
nativeSetDisplayProjection(displayToken, orientation,
-
layerStackRect.left, layerStackRect.top, layerStackRect.right, layerStackRect.bottom,
-
displayRect.left, displayRect.top, displayRect.right, displayRect.bottom);
-
}
这样updateRotationUncheckedLocked函数分析完了,当设备旋转了之后我们就要调用sendNewConfiguration,这个函数下篇博客分析。这里我们发现DisplayManagerService的相关流程还不是很熟悉(包括和SurfaceControl的联系等),后续也要分析下。