Android6.0 旋转屏幕(二)旋转设备

转载: https://blog.csdn.net/kc58236582/article/details/53689526

上篇博客中我们一直提到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的联系等),后续也要分析下。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值