问题背景:
公司项目是个VR一体机,可以理解成眼镜,用户看的是横屏。
但是项目开始的代码基线是从手机迁移过来的,因此底层配置的是竖屏(即通过adb shell wm size输出的宽小于高),system server启动后在DisplayContent中修改了屏幕方向orientation=1。
我叙述一下实现播放开关机动画的方案
时序上是:开机动画 --》 system server修改方向 --》关机动画
对创建Layer(SurfaceControl)的参数进行修改
// 获取屏幕参数
DisplayInfo dinfo; status_t status = SurfaceComposerClient::getDisplayInfo(mDisplayToken, &dinfo); // aosp原生 //sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
// dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
sp<SurfaceControl> control;
if (mShuttingDown) {
control = session()->createSurface(String8("BootAnimation"), // 交换宽高,关机的时候播放横图
dinfo.h, dinfo.w, PIXEL_FORMAT_RGB_565);
} else {
control = session()->createSurface(String8("BootAnimation"), // 开机播放竖图,创建竖的Layer
dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
}
开机动画时(orientation=0,竖屏设备),用的序列帧方向是:
因为要让用户看到正的ABC。
关机动画时(orientation=1,横屏设备),用的序列帧方向是:
此时开关机动画看起来都是正常的。
我看pico应该也是这样搞的:https://developer-cn.pico-interactive.com/document/solution/242423/
优化方案:
我为什么想优化:一是觉得上面的代码不优雅,二是,也是比较重要的一点,项目计划对接ToB业务,要很多次的替换开机动画,每次都让合作方旋转90度序列帧,我觉得太麻烦,可以用代码解决就用代码解决。
不过优化的前提是,我不想修改改变屏幕方向的时机,怕出问题,毕竟项目跑了5、6年了。
比如可以在SurfaceFlinger初始化的时候改变屏幕方向(我试过,可以实现),但我对涉及的模块、功能掌握不好,况且如果能从绘制参数上修改,改动还是最小的。
思路是从surfaceflinger、libui的单元测试代码寻找方案,最终确认可以修改 layer_state_t 这个结构的参数。
具体见代码:
// 开机、关机都这样创建 SurfaceControl
sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"), dinfo.h, dinfo.w, PIXEL_FORMAT_RGB_565);
创建SurfaceControl时,DisplayInfo给的宽度、高度要做一下替换,因为你要用横图做动画。
然后对开机的SurfaceControl做变换
SurfaceComposerClient::Transaction t; t.setLayer(control, 0x40000000) .setMatrix(control, 0.0f, 1.0f, -1.0f, 0.0f) // 顺时针旋转90度 .setPosition(control, dinfo.w * 1.0f, 0.0f) // x方向做位移
// .setGeometry(control, Rect(0, 0, dinfo.h, dinfo.w), // Rect(0, 0, -dinfo.h, -dinfo.w), // NATIVE_WINDOW_TRANSFORM_ROT_90) .apply();
使用 setMatrix + setPosition 和 setGeometry 是等效的。
我解释一下:
后面追看了一下源码:
// Layer.cpp
bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix, bool allowNonRectPreservingTransforms) { ui::Transform t; t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); if (!allowNonRectPreservingTransforms && !t.preserveRects()) { ALOGW("Attempt to set rotation matrix without permission ACCESS_SURFACE_FLINGER ignored"); return false; } mCurrentState.sequence++; mCurrentState.requested_legacy.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); return true; }
// Transform.cpp
void Transform::set(float a, float b, float c, float d) { mat33& M(mMatrix); M[0][0] = a; M[1][0] = b; M[0][1] = c; M[1][1] = d; M[0][2] = 0; M[1][2] = 0; mType = UNKNOWN_TYPE; }
后面会替换成 3*3的矩阵,可能到Engine端会用这个矩阵吧。
关于Layer这个矩阵的解读,网上资料比较少,后面可以先看看View的矩阵变换,先入门,然后看一下源码。
标签:control,动画,matrix,序列帧,开机,90,Android,dinfo From: https://www.cnblogs.com/yulisuo/p/17429259.html