Android TV切换系统输出分辨率的一些思考

Android 12 后的一些思考:是否可以使用原生的某些接口实现切换系统分辨率呢?

 

参考文章:

https://blog.csdn.net/u014535072/article/details/108692559

 

从源码中看到的可能相关的内容:

 /frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java

中的方法:

        @Override
        public void setDisplayProperties(int displayId, boolean hasContent,
                float requestedRefreshRate, int requestedMode, float requestedMinRefreshRate,
                float requestedMaxRefreshRate, boolean requestedMinimalPostProcessing,
                boolean inTraversal) {
            setDisplayPropertiesInternal(displayId, hasContent, requestedRefreshRate,
                    requestedMode, requestedMinRefreshRate, requestedMaxRefreshRate,
                    requestedMinimalPostProcessing, inTraversal);
        }

 

获取支持的Display mode:

 

获取Display info的参看

/packages/apps/Launcher3/src/com/android/launcher3/util/DisplayController.java

private final DisplayManager mDM;        
mDM = context.getSystemService(DisplayManager.class);
Display display = mDM.getDisplay(DEFAULT_DISPLAY);

基础的Display类

/frameworks/base/core/java/android/view/Display.java

    /**
     * Returns the active mode of the display.
     */
    public Mode getMode() {
        synchronized (mLock) {
            updateDisplayInfoLocked();
            return mDisplayInfo.getMode();
        }
    }

    /**
     * Gets the supported modes of this display.
     */
    public Mode[] getSupportedModes() {
        synchronized (mLock) {
            updateDisplayInfoLocked();
            final Display.Mode[] modes = mDisplayInfo.supportedModes;
            return Arrays.copyOf(modes, modes.length);
        }
    }

 

Display::Mode的定义:

http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/core/java/android/view/Display.java#1696

 

一个例子demo

http://aospxref.com/android-12.0.0_r3/xref/cts/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/ModeSwitchingTestActivity.java#66

        DisplayManager displayManager = getSystemService(DisplayManager.class);
        Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY);

        List<Display.Mode> modeList = findTestModes(display);

        Display.Mode lastMode = display.getMode();
    private List<Display.Mode> findTestModes(Display display) {
        Display.Mode activeMode = display.getMode();

        List<Display.Mode> modeList = new ArrayList<>();
        // Find a mode to test refresh rate switch - the mode with smallest refresh rate and
        // the same resolution as the active mode
        Arrays.stream(display.getSupportedModes())
                .filter(mode -> !mode.equals(activeMode))
                .filter(mode -> isResolutionEqual(mode, activeMode))
                .min(Comparator.comparingDouble(Display.Mode::getRefreshRate))
                .ifPresent(modeList::add);

        // Find a mode to test seamless mode switch.
        if (modeList.size() > 0 && !DisplayUtil.isModeSwitchSeamless(activeMode, modeList.get(0))
                && activeMode.getAlternativeRefreshRates().length > 0) {
            Arrays.stream(display.getSupportedModes())
                    .filter(mode -> !mode.equals(activeMode))
                    .filter(mode -> DisplayUtil.isModeSwitchSeamless(activeMode, mode))
                    .findFirst()
                    .ifPresent(modeList::add);
        }

        // Find a mode to test resolution switch - the first 16:9 mode with resolution less
        // than the active mode.
        Arrays.stream(display.getSupportedModes())
                .filter(mode -> !mode.equals(activeMode))
                .filter(mode -> !isResolutionEqual(mode, activeMode))
                .filter(this::is16to9)
                .max(Comparator.comparing(Display.Mode::getPhysicalHeight))
                .ifPresent(modeList::add);

        return modeList;
    }

 

我目前遇到的问题是不是可以直接在apk中加上这一个来通知到 WM 、SurfaceFLinger呢?

        private Display.Mode mNextMode;
        @Override
        public void runTest() {
            Window window = mContext.getWindow();
            WindowManager.LayoutParams params = window.getAttributes();
            params.preferredDisplayModeId = mNextMode.getModeId();
            window.setAttributes(params);
        }

 

 

 

另一个可能的途径:

 /frameworks/base/core/java/android/view/SurfaceControl.java

    /**
     * @hide
     */
    public static boolean setDesiredDisplayModeSpecs(IBinder displayToken,
            DesiredDisplayModeSpecs desiredDisplayModeSpecs) {
        if (displayToken == null) {
            throw new IllegalArgumentException("displayToken must not be null");
        }
        if (desiredDisplayModeSpecs == null) {
            throw new IllegalArgumentException("desiredDisplayModeSpecs must not be null");
        }
        if (desiredDisplayModeSpecs.defaultMode < 0) {
            throw new IllegalArgumentException("defaultMode must be non-negative");
        }

        return nativeSetDesiredDisplayModeSpecs(displayToken, desiredDisplayModeSpecs);
    }
        // Verify that this will reapply the desired modes.
        verify(mSurfaceControlProxy).setDesiredDisplayModeSpecs(display.token,
                new SurfaceControl.DesiredDisplayModeSpecs(
                        /* baseModeId */ 2,
                        /* allowGroupSwitching */ false,
                        /* primaryRange */ 60f, 60f,
                        /* appRange */ 60f, 60f
                ));

 

 

 

 

SurfaceFlinger

void SurfaceFlinger::loadDisplayModes(PhysicalDisplayId displayId, DisplayModes& outModes,
                                       DisplayModePtr& outActiveMode) const {
    
    activeModeHwcId = getHwComposer().getActiveMode(displayId);
}

只有这里去HWC 获取 getActiveMode

 

 

 

 

 

/frameworks/base/core/java/android/view/SurfaceControl.java

通知到SurfaceFlinger???

setDisplaySize

--> DisplayState::eDisplaySizeChanged

--> eDisplayTransactionNeeded

--> processDisplayHotplugEventsLocked

--> loadDisplayModes

--> getHwComposer().getActiveMode(displayId);

 

 

获取displayToken

private Bitmap captureScreenshot(Rect crop) {
        int width = crop.width();
        int height = crop.height();
        Bitmap screenshot = null;
        final Display display = getDefaultDisplay();
        final DisplayAddress address = display.getAddress();
        if (!(address instanceof DisplayAddress.Physical)) {
            Log.e(TAG, "Skipping Screenshot - Default display does not have a physical address: "
                    + display);
        } else {
            final DisplayAddress.Physical physicalAddress = (DisplayAddress.Physical) address;

            final IBinder displayToken = SurfaceControl.getPhysicalDisplayToken(
                    physicalAddress.getPhysicalDisplayId());
            final SurfaceControl.DisplayCaptureArgs captureArgs =
                    new SurfaceControl.DisplayCaptureArgs.Builder(displayToken)
                            .setSourceCrop(crop)
                            .setSize(width, height)
                            .build();
            final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
                    SurfaceControl.captureDisplay(captureArgs);
            screenshot = screenshotBuffer == null ? null : screenshotBuffer.asBitmap();
        }
        return screenshot;
    }

 

posted on 2022-05-14 14:36  二的次方  阅读(1149)  评论(2编辑  收藏  举报