Android6.0 旋轉屏幕(二)旋轉設備

上篇博客中我們一直提到updateRotationUnchecked函數,這篇博客我們就來分析下這個函數,這個函數可以說是旋轉屏幕的一個核心函數,我們主要看下updateRotationUncheckedLocked和sendNewConfiguration函數,當updateRotationUncheckedLocked返回true代表設備已經旋轉,這個時候要調用sendNewConfiguration函數通知AMS來使相應的Activity重新Launch等。

  1. public void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {
  2. long origId = Binder.clearCallingIdentity();
  3. boolean changed;
  4. synchronized(mWindowMap) {
  5. changed = updateRotationUncheckedLocked(false);
  6. if (!changed || forceRelayout) {
  7. getDefaultDisplayContentLocked().layoutNeeded = true;
  8. performLayoutAndPlaceSurfacesLocked();
  9. }
  10. }
  11. if (changed || alwaysSendConfiguration) {
  12. sendNewConfiguration();//後續分析
  13. }
  14. Binder.restoreCallingIdentity(origId);
  15. }

sendNewConfiguration我們放到下篇博客分析,這裏我們先分析updateRotationUncheckedLocked函數。


PhoneWindowManager的rotationForOrientationLw獲取rotation

下面是部分代碼,我們先調用PhoneWindowManager的rotationForOrientationLw函數來獲取rotation,然後與之前的mRotation對比是否有變化,沒有變化直接返回false。有變化將mRotation重新賦值。

  1. ......
  2. int rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation);
  3. boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(
  4. mForcedAppOrientation, rotation);
  5. if (mRotation == rotation && mAltOrientation == altOrientation) {
  6. // No change.
  7. return false;
  8. }
  9. mRotation = rotation;
  10. mAltOrientation = altOrientation;
  11. ......

PhoneWindowManager的rotationForOrientationLw函數我們就不分析了,就是獲取sensor的rotation,然後計算返回我們需要的rotation。我們繼續看updateRotationUncheckedLocked函數的剩下代碼。


updateDisplayAndOrientationLocked DisplayInfo數據放入display中

在updateRotationUncheckedLocked中還調用了updateDisplayAndOrientationLocked函數,我們也來看下,這個函數把各種數據更新下放到DisplayInfo中,最後調用了DisplayManagerService的setDisplayInfoOverrideFromWindowManager函數

  1. DisplayInfo updateDisplayAndOrientationLocked() {
  2. ......
  3. // Update application display metrics.
  4. final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation);
  5. final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation);
  6. final DisplayInfo displayInfo = displayContent.getDisplayInfo();
  7. synchronized(displayContent.mDisplaySizeLock) {
  8. displayInfo.rotation = mRotation;//旋轉
  9. displayInfo.logicalWidth = dw;
  10. displayInfo.logicalHeight = dh;
  11. displayInfo.logicalDensityDpi = displayContent.mBaseDisplayDensity;
  12. displayInfo.appWidth = appWidth;
  13. displayInfo.appHeight = appHeight;
  14. displayInfo.getLogicalMetrics(mRealDisplayMetrics,
  15. CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
  16. displayInfo.getAppMetrics(mDisplayMetrics);
  17. if (displayContent.mDisplayScalingDisabled) {
  18. displayInfo.flags |= Display.FLAG_SCALING_DISABLED;
  19. } else {
  20. displayInfo.flags &= ~Display.FLAG_SCALING_DISABLED;
  21. }
  22. mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(
  23. displayContent.getDisplayId(), displayInfo);
setDisplayInfoOverrideFromWindowManager就是調用了setDisplayInfoOverrideFromWindowManagerInternal

  1. @Override
  2. public void setDisplayInfoOverrideFromWindowManager(int displayId, DisplayInfo info) {
  3. setDisplayInfoOverrideFromWindowManagerInternal(displayId, info);
  4. }

setDisplayInfoOverrideFromWindowManagerInternal函數找到相應的display然後調用其setDisplayInfoOverrideFromWindowManagerLocked函數。

  1. private void setDisplayInfoOverrideFromWindowManagerInternal(
  2. int displayId, DisplayInfo info) {
  3. synchronized (mSyncRoot) {
  4. LogicalDisplay display = mLogicalDisplays.get(displayId);
  5. if (display != null) {
  6. if (display.setDisplayInfoOverrideFromWindowManagerLocked(info)) {
  7. sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
  8. scheduleTraversalLocked(false);
  9. }
  10. }
  11. }
  12. }

最後到LogicalDisplay的setDisplayInfoOverrideFromWindowManagerLocked函數中,把DisplayInfo數據放到了mOverrideDisplayInfo中

  1. public boolean setDisplayInfoOverrideFromWindowManagerLocked(DisplayInfo info) {
  2. if (info != null) {
  3. if (mOverrideDisplayInfo == null) {
  4. mOverrideDisplayInfo = new DisplayInfo(info);
  5. mInfo = null;
  6. return true;
  7. }
  8. if (!mOverrideDisplayInfo.equals(info)) {
  9. mOverrideDisplayInfo.copyFrom(info);
  10. mInfo = null;
  11. return true;
  12. }
  13. } else if (mOverrideDisplayInfo != null) {
  14. mOverrideDisplayInfo = null;
  15. mInfo = null;
  16. return true;
  17. }
  18. return false;
  19. }


設置設備旋轉

然後在updateRotationUncheckedLocked又調用瞭如下代碼:

            mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();

這樣我們又到了DisplayManagerService的performTraversalInTransactionFromWindowManager函數,然後又調用了performTraversalInTransactionFromWindowManagerInternal函數,我們來看下

  1. private void performTraversalInTransactionFromWindowManagerInternal() {
  2. synchronized (mSyncRoot) {
  3. if (!mPendingTraversal) {
  4. return;
  5. }
  6. mPendingTraversal = false;
  7. performTraversalInTransactionLocked();
  8. }
  9. // List is self-synchronized copy-on-write.
  10. for (DisplayTransactionListener listener : mDisplayTransactionListeners) {
  11. listener.onDisplayTransaction();
  12. }
  13. }

performTraversalInTransactionLocked函數,遍歷所有的Device,先調用了configureDisplayInTransactionLocked函數,然後調用了各個Device的performTraversalInTransactionLocked,而普通的Device的爲空,因此這裏我們不關注這個函數。

  1. private void performTraversalInTransactionLocked() {
  2. // Clear all viewports before configuring displays so that we can keep
  3. // track of which ones we have configured.
  4. clearViewportsLocked();
  5. // Configure each display device.
  6. final int count = mDisplayDevices.size();
  7. for (int i = 0; i < count; i++) {
  8. DisplayDevice device = mDisplayDevices.get(i);
  9. configureDisplayInTransactionLocked(device);
  10. device.performTraversalInTransactionLocked();
  11. }
  12. // Tell the input system about these new viewports.
  13. if (mInputManagerInternal != null) {
  14. mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT);
  15. }
  16. }

下面我們主要看configureDisplayInTransactionLocked函數,這個函數就是找到那個LogicalDisplay 然後調用其configureDisplayInTransactionLocked函數

  1. private void configureDisplayInTransactionLocked(DisplayDevice device) {
  2. final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
  3. final boolean ownContent = (info.flags & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) != 0;
  4. LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
  5. if (!ownContent) {
  6. if (display != null && !display.hasContentLocked()) {
  7. // If the display does not have any content of its own, then
  8. // automatically mirror the default logical display contents.
  9. display = null;
  10. }
  11. if (display == null) {
  12. display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY);
  13. }
  14. }
  15. // Apply the logical display configuration to the display device.
  16. if (display == null) {
  17. // TODO: no logical display for the device, blank it
  18. Slog.w(TAG, "Missing logical display to use for physical display device: "
  19. + device.getDisplayDeviceInfoLocked());
  20. return;
  21. }
  22. display.configureDisplayInTransactionLocked(device, info.state == Display.STATE_OFF);

LogicalDisplay 的configureDisplayInTransactionLocked函數,就是設置長寬,旋轉角度等。

  1. public void configureDisplayInTransactionLocked(DisplayDevice device,
  2. boolean isBlanked) {
  3. // Set the layer stack.
  4. device.setLayerStackInTransactionLocked(isBlanked ? BLANK_LAYER_STACK : mLayerStack);
  5. // Set the color transform and mode.
  6. if (device == mPrimaryDisplayDevice) {
  7. device.requestColorTransformAndModeInTransactionLocked(
  8. mRequestedColorTransformId, mRequestedModeId);
  9. } else {
  10. device.requestColorTransformAndModeInTransactionLocked(0, 0); // Revert to default.
  11. }
  12. // Only grab the display info now as it may have been changed based on the requests above.
  13. final DisplayInfo displayInfo = getDisplayInfoLocked();//獲取mInfo
  14. final DisplayDeviceInfo displayDeviceInfo = device.getDisplayDeviceInfoLocked();//獲取設備的info
  15. // Set the viewport.
  16. // This is the area of the logical display that we intend to show on the
  17. // display device. For now, it is always the full size of the logical display.
  18. mTempLayerStackRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
  19. // Set the orientation.
  20. // The orientation specifies how the physical coordinate system of the display
  21. // is rotated when the contents of the logical display are rendered.
  22. int orientation = Surface.ROTATION_0;
  23. if ((displayDeviceInfo.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0) {
  24. orientation = displayInfo.rotation;
  25. }
  26. // Apply the physical rotation of the display device itself.
  27. orientation = (orientation + displayDeviceInfo.rotation) % 4;//方向是根據傳入的方向加上原有設備的方向除以4
  28. // Set the frame.
  29. // The frame specifies the rotated physical coordinates into which the viewport
  30. // is mapped. We need to take care to preserve the aspect ratio of the viewport.
  31. // Currently we maximize the area to fill the display, but we could try to be
  32. // more clever and match resolutions.
  33. boolean rotated = (orientation == Surface.ROTATION_90
  34. || orientation == Surface.ROTATION_270);
  35. int physWidth = rotated ? displayDeviceInfo.height : displayDeviceInfo.width;//旋轉了長寬是否轉換
  36. int physHeight = rotated ? displayDeviceInfo.width : displayDeviceInfo.height;
  37. // Determine whether the width or height is more constrained to be scaled.
  38. // physWidth / displayInfo.logicalWidth => letter box
  39. // or physHeight / displayInfo.logicalHeight => pillar box
  40. //
  41. // We avoid a division (and possible floating point imprecision) here by
  42. // multiplying the fractions by the product of their denominators before
  43. // comparing them.
  44. int displayRectWidth, displayRectHeight;
  45. if ((displayInfo.flags & Display.FLAG_SCALING_DISABLED) != 0) {
  46. displayRectWidth = displayInfo.logicalWidth;
  47. displayRectHeight = displayInfo.logicalHeight;
  48. } else if (physWidth * displayInfo.logicalHeight
  49. < physHeight * displayInfo.logicalWidth) {
  50. // Letter box.
  51. displayRectWidth = physWidth;
  52. displayRectHeight = displayInfo.logicalHeight * physWidth / displayInfo.logicalWidth;
  53. } else {
  54. // Pillar box.
  55. displayRectWidth = displayInfo.logicalWidth * physHeight / displayInfo.logicalHeight;
  56. displayRectHeight = physHeight;
  57. }
  58. int displayRectTop = (physHeight - displayRectHeight) / 2;
  59. int displayRectLeft = (physWidth - displayRectWidth) / 2;
  60. mTempDisplayRect.set(displayRectLeft, displayRectTop,
  61. displayRectLeft + displayRectWidth, displayRectTop + displayRectHeight);
  62. mTempDisplayRect.left += mDisplayOffsetX;
  63. mTempDisplayRect.right += mDisplayOffsetX;
  64. mTempDisplayRect.top += mDisplayOffsetY;
  65. mTempDisplayRect.bottom += mDisplayOffsetY;
  66. device.setProjectionInTransactionLocked(orientation, mTempLayerStackRect, mTempDisplayRect);
  67. }

我們來看下getDisplayInfoLocked函數就是獲取mInfo的數據,而mOverrideDisplayInfo如有數據就要copy到mInfo中去。

  1. public DisplayInfo getDisplayInfoLocked() {
  2. if (mInfo == null) {
  3. mInfo = new DisplayInfo();
  4. mInfo.copyFrom(mBaseDisplayInfo);
  5. if (mOverrideDisplayInfo != null) {
  6. mInfo.appWidth = mOverrideDisplayInfo.appWidth;
  7. mInfo.appHeight = mOverrideDisplayInfo.appHeight;
  8. mInfo.smallestNominalAppWidth = mOverrideDisplayInfo.smallestNominalAppWidth;
  9. mInfo.smallestNominalAppHeight = mOverrideDisplayInfo.smallestNominalAppHeight;
  10. mInfo.largestNominalAppWidth = mOverrideDisplayInfo.largestNominalAppWidth;
  11. mInfo.largestNominalAppHeight = mOverrideDisplayInfo.largestNominalAppHeight;
  12. mInfo.logicalWidth = mOverrideDisplayInfo.logicalWidth;
  13. mInfo.logicalHeight = mOverrideDisplayInfo.logicalHeight;
  14. mInfo.overscanLeft = mOverrideDisplayInfo.overscanLeft;
  15. mInfo.overscanTop = mOverrideDisplayInfo.overscanTop;
  16. mInfo.overscanRight = mOverrideDisplayInfo.overscanRight;
  17. mInfo.overscanBottom = mOverrideDisplayInfo.overscanBottom;
  18. mInfo.rotation = mOverrideDisplayInfo.rotation;
  19. mInfo.logicalDensityDpi = mOverrideDisplayInfo.logicalDensityDpi;
  20. mInfo.physicalXDpi = mOverrideDisplayInfo.physicalXDpi;
  21. mInfo.physicalYDpi = mOverrideDisplayInfo.physicalYDpi;
  22. }
  23. }
  24. return mInfo;
  25. }

最後調用了DisplayDevice的setProjectionInTransactionLocked函數,然後調用了SurfaceControl的setDisplayProjection函數。

  1. public final void setProjectionInTransactionLocked(int orientation,
  2. Rect layerStackRect, Rect displayRect) {
  3. if (mCurrentOrientation != orientation
  4. || mCurrentLayerStackRect == null
  5. || !mCurrentLayerStackRect.equals(layerStackRect)
  6. || mCurrentDisplayRect == null
  7. || !mCurrentDisplayRect.equals(displayRect)) {
  8. mCurrentOrientation = orientation;
  9. if (mCurrentLayerStackRect == null) {
  10. mCurrentLayerStackRect = new Rect();
  11. }
  12. mCurrentLayerStackRect.set(layerStackRect);
  13. if (mCurrentDisplayRect == null) {
  14. mCurrentDisplayRect = new Rect();
  15. }
  16. mCurrentDisplayRect.set(displayRect);
  17. SurfaceControl.setDisplayProjection(mDisplayToken,
  18. orientation, layerStackRect, displayRect);
  19. }
  20. }
SurfaceControl.setDisplayProjection函數如下,這個函數最後又調用了JNI函數,最後是根據mDisplayToken來設置到相應的設備中去。
  1. public static void setDisplayProjection(IBinder displayToken,
  2. int orientation, Rect layerStackRect, Rect displayRect) {
  3. if (displayToken == null) {
  4. throw new IllegalArgumentException("displayToken must not be null");
  5. }
  6. if (layerStackRect == null) {
  7. throw new IllegalArgumentException("layerStackRect must not be null");
  8. }
  9. if (displayRect == null) {
  10. throw new IllegalArgumentException("displayRect must not be null");
  11. }
  12. nativeSetDisplayProjection(displayToken, orientation,
  13. layerStackRect.left, layerStackRect.top, layerStackRect.right, layerStackRect.bottom,
  14. displayRect.left, displayRect.top, displayRect.right, displayRect.bottom);
  15. }


這樣updateRotationUncheckedLocked函數分析完了,當設備旋轉了之後我們就要調用sendNewConfiguration,這個函數下篇博客分析。這裏我們發現DisplayManagerService的相關流程還不是很熟悉(包括和SurfaceControl的聯繫等),後續也要分析下。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章