车机手机互联模拟Overlay屏幕竖屏显示适配分析

背景:

在研究系统自带模拟屏幕相关源码时候,发现Overlays这个模拟屏幕有如下自动适配现象:
在这里插入图片描述
大家可以看到手机屏幕自身是竖屏,但是模拟屏幕是横屏情况,这里看到会有一个自动的竖屏数据放到横屏中间,然后两边啥也不显示。
在这里插入图片描述
但是横屏情况下明显模拟屏幕Overlay是全部分覆盖的
在这里插入图片描述
疑问点:
横屏情况比较好理解,因为只需要对录屏的数据进行等比例缩放既可以,但是竖屏数据就明显需要额外处理,让竖屏居中显示,不然直接等比例缩放,肯定会产生形变。所以核心问题只有一个那就是分析追踪出如何实现的竖屏自适配显示在模拟屏幕的上。

问题线索探索猜想1:

必须知道背景知识:
模拟屏幕其实本质是一个窗口,也是有view展示的,具体如下:

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

 private void createWindow() {
        LayoutInflater inflater = LayoutInflater.from(mContext);

        mWindowContent = inflater.inflate(
                com.android.internal.R.layout.overlay_display_window, null);
        mWindowContent.setOnTouchListener(mOnTouchListener);

        mTextureView = (TextureView)mWindowContent.findViewById(
                com.android.internal.R.id.overlay_display_window_texture);
        mTextureView.setPivotX(0);
        mTextureView.setPivotY(0);
        mTextureView.getLayoutParams().width = mWidth;
        mTextureView.getLayoutParams().height = mHeight;
        mTextureView.setOpaque(false);
        mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);

        mTitleTextView = (TextView)mWindowContent.findViewById(
                com.android.internal.R.id.overlay_display_window_title);
        mTitleTextView.setText(mTitle);

        mWindowParams = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY);
        mWindowParams.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
        if (mSecure) {
            mWindowParams.flags |= WindowManager.LayoutParams.FLAG_SECURE;
        }
        if (DISABLE_MOVE_AND_RESIZE) {
            mWindowParams.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
        }
        mWindowParams.privateFlags |=
                WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
        mWindowParams.alpha = WINDOW_ALPHA;
        mWindowParams.gravity = Gravity.TOP | Gravity.LEFT;
        mWindowParams.setTitle(mTitle);
//省略部分
    }

可以看到模拟器屏幕显示是靠overlay_display_window展示:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:background="#000000">
    <TextureView android:id="@+id/overlay_display_window_texture"
               android:layout_width="0px"
               android:layout_height="0px" />
    <TextView android:id="@+id/overlay_display_window_title"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:layout_gravity="top|center_horizontal" />
</FrameLayout>

可以看到就是个FrameLayout布局包含如下两个:
一个TextureView显示在底层
这个主要就是来提供对应的Surface来显示真实的屏幕数据,类似SurfaceView一样,大小一般就是整个模拟屏幕大小

一个TextView显示在上层用来显示模拟屏幕的名字
在这里插入图片描述
在这里插入图片描述

有了上面知识背景后猜想:
有没有可能模拟屏幕窗口显示的textureview会根据情况自身调整自己大小位置?

在这里插入图片描述
即是不是会识别当前显示屏幕数据是竖屏还是横屏,来调整TextureView大小
验证猜想,其实验证是不是这种还是比较方便,只需要开启一下全局布局边界既可以,当然也可以代码中调试。
在这里插入图片描述

从上面就可以看出,这种猜想错误

问题线索探索猜想2:

必备背景:
可以考虑通过dumpsys SurfaceFlinger来看看各个图层展示情况,哪怕是模拟屏幕也是需要在sf中有相关的图层的
执行命令:
adb shell dumpsys SurfaceFlinger
正常屏幕的layer

- Output Layer 0x78310d6980(com.android.settings/com.android.settings.SubSettings#2021)
        Region visibleRegion (this=0x78310d6998, count=1)
    [  0,   0, 1080, 1920]
        Region visibleNonTransparentRegion (this=0x78310d6a00, count=1)
    [  0,   0, 1080, 1920]
        Region coveredRegion (this=0x78310d6a68, count=3)
    [  0,   0, 1080,  74]
    [134, 215, 854, 695]
    [  0, 1794, 1080, 1920]
        Region output visibleRegion (this=0x78310d6b40, count=1)
    [  0,   0, 1080, 1920]
        Region shadowRegion (this=0x78310d6ba8, count=1)
    [  0,   0,   0,   0]
        Region outputSpaceBlockingRegionHint (this=0x78310d6c40, count=1)
    [  0,   0,   0,   0]
      forceClientComposition=false clearClientTarget=true displayFrame=[0 0 1080 1920] sourceCrop=[0.000000 0.000000 1080.000000 1920.000000] bufferTransform=0 (0) dataspace=V0_SRGB (142671872) whitePointNits=-1.000000 dimmingRatio=1.000000 override buffer=0x0 override acquire fence=0x0 override display frame=[0 0 -1 -1] override dataspace=UNKNOWN (0) override display space=ProjectionSpace{bounds=Rect(0, 0, -1, -1), content=Rect(0, 0, -1, -1), orientation=ROTATION_0} override damage region=  Region  (this=0x78310d6cf0, count=1)
    [  0,   0,  -1,  -1]
 override visible region=  Region  (this=0x78310d6d58, count=1)
    [  0,   0,   0,   0]
 override peekThroughLayer=0x0 override disableBackgroundBlur=false 
      hwc: layer=0x088f composition=DEVICE (2) 

模拟屏幕的对应layer

- Output Layer 0x78310d7660(com.android.settings/com.android.settings.SubSettings#2021 (Mirror)#2074)
        Region visibleRegion (this=0x78310d7678, count=1)
    [225,   0, 495, 480]
        Region visibleNonTransparentRegion (this=0x78310d76e0, count=1)
    [225,   0, 495, 480]
        Region coveredRegion (this=0x78310d7748, count=3)
    [225,   0, 495,  19]
    [259,  54, 439, 174]
    [225, 449, 495, 480]
        Region output visibleRegion (this=0x78310d7820, count=1)
    [225,   0, 495, 480]
        Region shadowRegion (this=0x78310d7888, count=1)
    [  0,   0,   0,   0]
        Region outputSpaceBlockingRegionHint (this=0x78310d7920, count=1)
    [  0,   0,   0,   0]
      forceClientComposition=false clearClientTarget=false displayFrame=[225 0 495 480] sourceCrop=[0.000000 0.000000 1080.000000 1920.000000] bufferTransform=0 (0) dataspace=V0_SRGB (142671872) whitePointNits=-1.000000 dimmingRatio=1.000000 override buffer=0x0 override acquire fence=0x0 override display frame=[0 0 -1 -1] override dataspace=UNKNOWN (0) override display space=ProjectionSpace{bounds=Rect(0, 0, -1, -1), content=Rect(0, 0, -1, -1), orientation=ROTATION_0} override damage region=  Region  (this=0x78310d79d0, count=1)
    [  0,   0,  -1,  -1]
 override visible region=  Region  (this=0x78310d7a38, count=1)
    [  0,   0,   0,   0]
 override peekThroughLayer=0x0 override disableBackgroundBlur=false 

可以看出这里Activity Layer的visibleRegion就有较大区别
原始屏幕是
[ 0, 0, 1080, 1920]
模拟屏幕是
[225, 0, 495, 480]
这里就可以看出在模拟屏幕上其实Layer就是已经适配了模拟屏幕情况的,那么这个Layer这个visibleRegion谁导致呢?
可以继续sf的dump中查看到如下结果:

在这里插入图片描述
也就是这个geomLayerTransform导致的差异,那么这个geomLayerTransform又是谁决定呢?

这个就需要对Layer代码进行打印追踪,最后确定是如下:
在这里插入图片描述
有这里的mRequestedTransform决定,那么mRequestedTransform又是谁影响它的数据呢?
一般都是setMatrix和setPosition方法


bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix) {
    if (mRequestedTransform.dsdx() == matrix.dsdx && mRequestedTransform.dtdy() == matrix.dtdy &&
        mRequestedTransform.dtdx() == matrix.dtdx && mRequestedTransform.dsdy() == matrix.dsdy) {
        return false;
    }

    mRequestedTransform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);

    mDrawingState.sequence++;
    mDrawingState.modified = true;
    setTransactionFlags(eTransactionNeeded);
    return true;
}

bool Layer::setPosition(float x, float y) {
    if (mRequestedTransform.tx() == x && mRequestedTransform.ty() == y) {
        return false;
    }

    mRequestedTransform.set(x, y);

    mDrawingState.sequence++;
    mDrawingState.modified = true;
    setTransactionFlags(eTransactionNeeded);
    return true;
}

这里setMatrix和setPosition一般都是客户端进程的Transaction相关对SurfaceControl进行的设置,所以这里可以考虑去对应的SurfaceControl加入对应追踪,这个课程已经讲解很多遍了,就不需要多讲解。

这里最后上结论:
在这里插入图片描述
从这个堆栈找到对应代码如下:
在这里插入图片描述

哈哈,最后是不是看到了核心代码,就是竖屏高度对横屏高度进行等比例缩放,而后平移到了横屏屏幕的中间。

本文章更多详细代码和资料需要购买课程获取
hal+perfetto+surfaceflinger
https://mp.weixin.qq.com/s/LbVLnu1udqExHVKxd74ILg
在这里插入图片描述

私聊作者+v(androidframework007)

其他课程七件套专题:在这里插入图片描述
点击这里
https://mp.weixin.qq.com/s/Qv8zjgQ0CkalKmvi8tMGaw

视频试看:
https://www.bilibili.com/video/BV1wc41117L4/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值