对android rotation的添加与定制

在做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”也只不过是在系统里面定义的一个属性。这个属性是可以变的,是可以被我们自由控制的。所以想到这里,我们就可以从属性方面作为切入点。说到这里思路就很明确了,有兴趣可以自行发散思维,不难。




你可能感兴趣的:(技术)