Android wm size显示缩放问题

        如果使用过wm size命令来修改Android的分辨率的人,应该都会发现wm size分辨无论是超过还是低于屏幕分辨率,但最终显示时,显示屏上仍有一个维度必定是匹配屏幕的。

 

        那么这个东西是在哪导致的呢。实际上通过dumpsys display来看,display的分辨率确实是自己所设置的那个,然而显示的却不是,因为真实的显示屏分辨率是有限的。Android原生框架就考虑了这个,因此在将这个显示的分辨率设置底层SF/hwc时,做了一个等比例的缩放,使界面没有明显的压缩畸变感,也能完整地显示在屏幕上。

分析

        这部分代码是在LogicalDisplay.configureDisplayLocked这个方法中实现的,我们先来看一下这段源码:

    public void configureDisplayLocked(SurfaceControl.Transaction t,
            DisplayDevice device,
            boolean isBlanked) {
        // Set the layer stack.
        device.setLayerStackLocked(t, isBlanked ? BLANK_LAYER_STACK : mLayerStack);

        // Set the color mode and allowed display mode.
        if (device == mPrimaryDisplayDevice) {
            device.setDesiredDisplayModeSpecsLocked(mDesiredDisplayModeSpecs);
            device.setRequestedColorModeLocked(mRequestedColorMode);
        } else {
            // Reset to default for non primary displays
            device.setDesiredDisplayModeSpecsLocked(
                    new DisplayModeDirector.DesiredDisplayModeSpecs());
            device.setRequestedColorModeLocked(0);
        }

        device.setAutoLowLatencyModeLocked(mRequestedMinimalPostProcessing);
        device.setGameContentTypeLocked(mRequestedMinimalPostProcessing);

        // Only grab the display info now as it may have been changed based on the requests above.
        final DisplayInfo displayInfo = getDisplayInfoLocked();
        final DisplayDeviceInfo displayDeviceInfo = device.getDisplayDeviceInfoLocked();

        // 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;

        // 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;

        Rect maskingInsets = getMaskingInsets(displayDeviceInfo);
        InsetUtils.rotateInsets(maskingInsets, orientation);
        // Don't consider the masked area as available when calculating the scaling below.
        physWidth -= maskingInsets.left + maskingInsets.right;
        physHeight -= maskingInsets.top + maskingInsets.bottom;

        // 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 || mDisplayScalingDisabled) {
            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);

        // Now add back the offset for the masked area.
        mTempDisplayRect.offset(maskingInsets.left, maskingInsets.top);

        if (orientation == Surface.ROTATION_0) {
            mTempDisplayRect.offset(mDisplayOffsetX, mDisplayOffsetY);
        } else if (orientation == Surface.ROTATION_90) {
            mTempDisplayRect.offset(mDisplayOffsetY, -mDisplayOffsetX);
        } else if (orientation == Surface.ROTATION_180) {
            mTempDisplayRect.offset(-mDisplayOffsetX, -mDisplayOffsetY);
        } else {  // Surface.ROTATION_270
            mTempDisplayRect.offset(-mDisplayOffsetY, mDisplayOffsetX);
        }

        mDisplayPosition.set(mTempDisplayRect.left, mTempDisplayRect.top);
        device.setProjectionLocked(t, orientation, mTempLayerStackRect, mTempDisplayRect);
    }

        这里面有几个值需要我们去关注:displayInfo.logicalWidth、displayInfo.logicalHeight、displayDeviceInfo.width、displayDeviceInfo.height。displayDeviceInfo是原始display的宽高数据,displayInfo是我们设置的宽高数据。

        接下来我们就可以看到,当display被设置为不可scaling或mDisplayScalingDisabled,那么,真实的显示宽高就是我们设置的宽高。

        否则,就是需要进行显示的缩放。

        当physWidth * displayInfo.logicalHeight  < physHeight * displayInfo.logicalWidth,我们转换一下公式:

\frac{displayInfo.logicalWidth}{physWidth} > \frac{displayInfo.logicalHeight}{physHeight}

        如果设置宽度和真实宽度的比例大于设置高度和真实高度的比例,也就是说如果按比例缩放,那么宽度则会超出显示屏的真实宽度,因此需要限制宽度,即缩放后显示的宽度为显示屏宽度,而高度则按比例缩小。

        反之,则是高度的比例大于宽度的比例,显示的高度限制为显示屏高度,宽度则按比例缩小。

        因此我们所设置的分辨率宽高比与显示屏的宽高比不一样时,就会出现有一个维度(宽度或高度)不是占满全屏的。

        当比例一致时,则不会出现此问题。

需求

        书接上回,上一篇描述了一个客户需求,当屏幕的某个维度被对称裁剪后,我们完全可以通过wm size的方式来达到我们的需求。但如果是两个维度同时裁剪,设置不是对称裁剪时,我们需要对configureDisplayLocked的逻辑进行修改了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值