在做android开发的过程中,我们难免会遇到显示旋屏的需求,特别是在一些广告机类的应用和产品中,旋屏是家常便饭。还是那句话,如果厂家的BSP够完善,那么做起来就很方便,只需修改一些参数就行。但如果厂家的BSP没把这功能加上,做旋屏也够你折腾一阵子了。一般把旋屏集成在BSP里面的也只有消费类的厂家,做embedded的厂家的BSP相对没有那么完善。所以说做消费类的工程师难免不会有点娇生惯养。我们有时间还是得有自己的钻研。
说回旋屏,在android原生系统上,有通过gsensor 判断重力的方向,并旋转屏幕的功能。但,如果我们想在出厂的时候把屏幕按照我们的需求旋转到特定的位置,如90度,180度等。该怎么办。其中有一个思路就是缘用gsensor这条通路,调用相应的api来实现。究竟这个想法能否实现,如果有兴趣的话可以自行研究。这里讲的是另外一种方式。
说到rotation,很多人会联想到在init.rc里面设置的“ro.sf.hwrotation”的属性。所以在这里,我们善用系统的资源,利用这个“ro.sf.hwrotation”的属性来实现rotation的定制。
总结来说,android里面控制rotation的有三个位置,分别是:
Framework/native/services/surfaceflinger/SurfaceFlinger.cpp
Framework/native/ services/surfaceflinger/DisplayDevice.cpp
Framework/base/services/input/InputReader.cpp
SurfaceFlinger.cpp和DisplayDevice.cpp是显示相关的rotation,InputReader.cpp是跟input事件相关的rotation,如touch等。具体不详细介绍。
这三个文件里面其实做的动作一样,就是去读取“ro.sf.hwrotation”的属性值,然后分别对这三个文件的:displayOrientation,displayOrientation,和hwrotation赋值。如InputReader.cpp的做法:
+#include
@@ -2925,8 +2927,30 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
+ char hwrotBuf[PROPERTY_VALUE_MAX];
+ int32_t hwrotation = DISPLAY_ORIENTATION_0;
+ if (property_get("ro.sf.hwrotation", hwrotBuf, NULL) > 0) {
+ switch (atoi(hwrotBuf)) {
+ case 90:
+ hwrotation = DISPLAY_ORIENTATION_90;
+ break;
+ case 180:
+ hwrotation = DISPLAY_ORIENTATION_180;
+ break;
+ case 270:
+ hwrotation = DISPLAY_ORIENTATION_270;
+ break;
+ }
+ }
+
@@ -2937,12 +2961,21 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
mDeviceMode = DEVICE_MODE_DISABLED;
return;
}
+ newViewport.orientation = (newViewport.orientation + hwrotation) % 4;
} else {
+ if ((hwrotation == DISPLAY_ORIENTATION_90 ||
+ hwrotation == DISPLAY_ORIENTATION_270)) {
+ int tmp = rawWidth;
+ rawWidth = rawHeight;
+ rawHeight = tmp;
+ }
newViewport.setNonDisplayViewport(rawWidth, rawHeight);
+ newViewport.orientation = hwrotation;
}
- if (mViewport != newViewport) {
+ bool viewportChanged = mViewport != newViewport;
+ if (viewportChanged) {
mViewport = newViewport;
- viewportChanged = true;
+// viewportChanged = true;
由于这三个文件修改的内容大同小异,所以拿一个文件说明。
改完后,我们发现只需要在 init.rc 里面修改“ro.sf.hwrotation”的值(0,90,180,270),就可以设置不同方向的输出。不过这种修改的方法是在android动态logo才能生效。在uboot跟kernel的阶段,如果需要,就修改平台的相应代码,底层的代码跟android层面上的有所区别,对于uboot跟kernel而言,就是要修改到具体的代码处,把变量指定好。这里不去分析,因为不同的平台修改的地方不一样。
通过上面过程的修改,我们就可以实现在出厂的时候定制任意方向的rotation。但仔细一想,这种方式是有局限性的,如果想改变输出方向,就得重新烧录系统。
于是我们想,怎样去实现在apk层面去控制rotation的输出,有一种思路就是分别在SurfaceFlinger.cpp ,DisplayDevice.cpp,InputReader.cpp里面导出相应的api,提供apk调用。这种做法,需要多framework熟悉的工程师来完成。写应用不是本人的强项,所以在这里就不献丑了。所以在这里,还有另一种实现方式。具体思路怎样呢?我们看到,上面设置rotation的方法是围绕一个“ro.sf.hwrotation”来实现的。而“ro.sf.hwrotation”也只不过是在系统里面定义的一个属性。这个属性是可以变的,是可以被我们自由控制的。所以想到这里,我们就可以从属性方面作为切入点。说到这里思路就很明确了,有兴趣可以自行发散思维,不难。