上篇博客中我們一直提到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的聯繫等),後續也要分析下。