wm命令(wm size)修改屏幕尺寸

wm size可以查看当前屏幕分辨率,也可以设置屏幕分辨率(当然也就一般调试问题wm size)。

eg: wm size 720x1280

这里要注意了乘号不是*,是x字母

一、Wm源码

我们先来看下wm源码,Wm.java中关于wm size部分。

    private void runDisplaySize() throws Exception {
        String size = nextArg();
        int w, h;
        if (size == null) {
            Point initialSize = new Point();
            Point baseSize = new Point();
            try {
                mWm.getInitialDisplaySize(Display.DEFAULT_DISPLAY, initialSize);
                mWm.getBaseDisplaySize(Display.DEFAULT_DISPLAY, baseSize);
                System.out.println("Physical size: " + initialSize.x + "x" + initialSize.y);
                if (!initialSize.equals(baseSize)) {
                    System.out.println("Override size: " + baseSize.x + "x" + baseSize.y);
                }
            } catch (RemoteException e) {
            }
            return;
        } else if ("reset".equals(size)) {
            w = h = -1;
        } else {
            int div = size.indexOf('x');
            if (div <= 0 || div >= (size.length()-1)) {
                System.err.println("Error: bad size " + size);
                return;
            }
            String wstr = size.substring(0, div);
            String hstr = size.substring(div+1);
            try {
                w = parseDimension(wstr);
                h = parseDimension(hstr);
            } catch (NumberFormatException e) {
                System.err.println("Error: bad number " + e);
                return;
            }
        }

        try {
            if (w >= 0 && h >= 0) {
                // TODO(multidisplay): For now Configuration only applies to main screen.
                mWm.setForcedDisplaySize(Display.DEFAULT_DISPLAY, w, h);
            } else {
                mWm.clearForcedDisplaySize(Display.DEFAULT_DISPLAY);
            }
        } catch (RemoteException e) {
        }
    }

当没有参数时会WMS中的initialSize和baseSize,如果有参数,最终会调用WMS的setForcedDisplaySize函数,如果是reset就调用WMS的clearForcedDisplaySize函数重置分辨率。

二、WMS设置分辨率

下面我们主要看下WMS的setForcedDisplaySize函数:

    public void setForcedDisplaySize(int displayId, int width, int height) {
        ......
        final long ident = Binder.clearCallingIdentity();
        try {
            synchronized(mWindowMap) {
                // Set some sort of reasonable bounds on the size of the display that we
                // will try to emulate.
                final int MIN_WIDTH = 200;
                final int MIN_HEIGHT = 200;
                final int MAX_SCALE = 2;
                final DisplayContent displayContent = getDisplayContentLocked(displayId);
                if (displayContent != null) {
                    width = Math.min(Math.max(width, MIN_WIDTH),
                            displayContent.mInitialDisplayWidth * MAX_SCALE);
                    height = Math.min(Math.max(height, MIN_HEIGHT),
                            displayContent.mInitialDisplayHeight * MAX_SCALE);
                    setForcedDisplaySizeLocked(displayContent, width, height);
                    Settings.Global.putString(mContext.getContentResolver(),
                            Settings.Global.DISPLAY_SIZE_FORCED, width + "," + height);
                }
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }

最后调用了setForcedDisplaySizeLocked函数,这个函数主要设置了displayContent的mBaseDisplayWidth和mBaseDisplayHeight变量,然后调用了reconfigureDisplayLocked函数。

    private void setForcedDisplaySizeLocked(DisplayContent displayContent, int width, int height) {
        Slog.i(TAG, "Using new display size: " + width + "x" + height);

        synchronized(displayContent.mDisplaySizeLock) {
            displayContent.mBaseDisplayWidth = width;
            displayContent.mBaseDisplayHeight = height;
        }
        reconfigureDisplayLocked(displayContent);
    }

reconfigureDisplayLocked函数先调用了computeScreenConfigurationLocked函数,这个函数会通知DisplayManagerService相关设备的信息改变了,然后发送SEND_NEW_CONFIGURATION消息通知AMS(这个在http://blog.csdn.net/kc58236582/article/details/53735136博客中分析过了),以及调用performLayoutAndPlaceSurfacesLocked刷新系统。

    private void reconfigureDisplayLocked(DisplayContent displayContent) {
        // TODO: Multidisplay: for now only use with default display.
        if (!mDisplayReady) {
            return;
        }
        configureDisplayPolicyLocked(displayContent);
        displayContent.layoutNeeded = true;

        boolean configChanged = updateOrientationFromAppTokensLocked(false);
        mTempConfiguration.setToDefaults();
        mTempConfiguration.fontScale = mCurConfiguration.fontScale;
        computeScreenConfigurationLocked(mTempConfiguration);
        configChanged |= mCurConfiguration.diff(mTempConfiguration) != 0;

        if (configChanged) {
            mWaitingForConfig = true;
            startFreezingDisplayLocked(false, 0, 0);
            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
        }

        performLayoutAndPlaceSurfacesLocked();
    }
因此我们先看computeScreenConfigurationLocked函数,第一行就调用了updateDisplayAndOrientationLocked函数。

    void computeScreenConfigurationLocked(Configuration config) {
        final DisplayInfo displayInfo = updateDisplayAndOrientationLocked();

这个函数会获取displayContent的mBaseDisplayWidth和mBaseDisplayHeight,然后封装在displayInfo,最终调用mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager

    DisplayInfo updateDisplayAndOrientationLocked() {
        // TODO(multidisplay): For now, apply Configuration to main screen only.
        final DisplayContent displayContent = getDefaultDisplayContentLocked();

        // Use the effective "visual" dimensions based on current rotation
        final boolean rotated = (mRotation == Surface.ROTATION_90
                || mRotation == Surface.ROTATION_270);
        final int realdw = rotated ?
                displayContent.mBaseDisplayHeight : displayContent.mBaseDisplayWidth;
        final int realdh = rotated ?
                displayContent.mBaseDisplayWidth : displayContent.mBaseDisplayHeight;
        int dw = realdw;
        int dh = realdh;

        if (mAltOrientation) {
            if (realdw > realdh) {
                // Turn landscape into portrait.
                int maxw = (int)(realdh/1.3f);
                if (maxw < realdw) {
                    dw = maxw;
                }
            } else {
                // Turn portrait into landscape.
                int maxh = (int)(realdw/1.3f);
                if (maxh < realdh) {
                    dh = maxh;
                }
            }
        }

        // 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//设置到DisplayManagerService中去
                    displayContent.getDisplayId(), displayInfo);

            displayContent.mBaseDisplayRect.set(0, 0, dw, dh);
        }
        if (false) {
            Slog.i(TAG, "Set app display size: " + appWidth + " x " + appHeight);
        }

        mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(mDisplayMetrics,
                mCompatDisplayMetrics);
        return displayInfo;
    }

2.1 WMS传递DeviceInfo到DisplayManagerService中

WMS通过DeviceManagerService的setDisplayInfoOverrideFromWindowManager函数把DeviceInfo到DisplayManagerService中。

setDisplayInfoOverrideFromWindowManager函数之前分析过,这里我们再看下,直接调用了setDisplayInfoOverrideFromWindowManagerInternal函数

        @Override
        public void setDisplayInfoOverrideFromWindowManager(int displayId, DisplayInfo info) {
            setDisplayInfoOverrideFromWindowManagerInternal(displayId, info);
        }

而setDisplayInfoOverrideFromWindowManagerInternal方法,找到合适的LogicalDisplay,然后调用其setDisplayInfoOverrideFromWindowManagerLocked方法把DisplayInfo保存下来。

    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);
                }
            }
        }
    }
setDisplayInfoOverrideFromWindowManagerLocked只是把DeviceInfo保存在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;
    }

2.2 DisplayManagerService设置信息(屏幕长宽、旋转等)到SurfaceControl

然后会在WMS的刷新核心函数performLayoutAndPlaceSurfacesLockedInner调用了如下代码:

mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();

performTraversalInTransactionFromWindowManager函数直接调用了performTraversalInTransactionFromWindowManagerInternal函数

        @Override
        public void performTraversalInTransactionFromWindowManager() {
            performTraversalInTransactionFromWindowManagerInternal();
        }

performTraversalInTransactionFromWindowManagerInternal函数,我们主要看下performTraversalInTransactionLocked函数。

    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函数会遍历所有的DisplayDevice,然后调用configureDisplayInTransactionLocked函数。

    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();
        ......
        display.configureDisplayInTransactionLocked(device, info.state == Display.STATE_OFF);

        ......
    }
我们最后再来看LogicalDisplay的configureDisplayInTransactionLocked函数,会调用getDisplayInfoLocked函数,获取DisplayInfo,然后利用其displayInfo.logicalWidth, displayInfo.logicalHeight,新建一个矩阵,以及orientation,最后 device.setProjectionInTransactionLocked函数设置到SurfaceControl中去(有旋转、长宽矩阵)。(这里我们之前在 http://blog.csdn.net/kc58236582/article/details/53689526博客中分析过)
    public void configureDisplayInTransactionLocked(DisplayDevice device,
            boolean isBlanked) {
        ......
        final DisplayInfo displayInfo = getDisplayInfoLocked();
        final DisplayDeviceInfo displayDeviceInfo = device.getDisplayDeviceInfoLocked();

        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;

        // 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方法就是把mOverrideDisplayInfo数据放到mInfo中返回。mOverrideDisplayInfo就是之前在WMS的updateDisplayAndOrientationLocked调用DisplayManagerService的函数传入的数据。
    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;
    }






评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值