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

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



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值