Android 开机动画优化之序列帧旋转90度

问题背景:

公司项目是个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的矩阵变换,先入门,然后看一下源码。

 

posted on 2023-05-24 18:58  luke4212  阅读(240)  评论(0编辑  收藏  举报

导航