横屏 竖屏 代码流程

[Android移植] 关于android2.3调试g-sensor (2012-02-21 16:11:17)

标签:

it

android
本帖最后由 Code007 于 2011-12-6 10:13 编辑

由于工作上的需要,特地写了这么一份关于调试g-sensor的内容.
1.首先确定你要调试的设备的屏幕的横竖屏如何设置。
在代码中我们主要的流程如下:
os 启动后 :
WindowManagerService.java中ENABLE_SCREEN
–>performEnableScreen()
–>mPolicy.enableScreenAfterBoot()/setRotation()
–>setRotationUnchecked()
–>PhoneWindowManager.java中的rotationForOrientationLw()
–>Surface.setOrientation()
基本上流程就是如上,只要稍微跟踪一下就可以了。
下面大概对上面主要code进行注释说明:



  1. //下面的方法主要用于判断屏幕是否需要进行一个新的旋转
  2. public boolean setRotationUncheckedLocked(int rotation, int animFlags) {
  3.         boolean changed;
  4. //rotation从外面传入当前的rotation以及animFlags 最后的标签
  5. //如果rotation等于系统第一次启动则rotation赋值为mRequestedRotation此时为0
  6.         if (rotation == WindowManagerPolicy.USE_LAST_ROTATION) {
  7.             rotation = mRequestedRotation;
  8.         } else {
  9.             mRequestedRotation = rotation;
  10.             mLastRotationFlags = animFlags;
  11.         }
  12.         if (DEBUG_ORIENTATION) Slog.v(TAG, "Overwriting rotation value from " + rotation);
  13. //此时的rotation为老的rotation,下面通过mPolicy.rotationForOrientationLw()进行获取新的rotation
  14.         rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation,
  15.                 mRotation, mDisplayEnabled);
  16.         if (DEBUG_ORIENTATION) Slog.v(TAG, "new rotation is set to " + rotation);
  17.         changed = mDisplayEnabled && mRotation != rotation;
  18. //如果获取新的rotation与旧的rotation一样则不做改变
  19. //否则进入下面函数进行调整
  20.         if (changed) {
  21.             if (DEBUG_ORIENTATION) Slog.v(TAG,
  22.                     "Rotation changed to " + rotation
  23.                     + " from " + mRotation
  24.                     + " (forceApp=" + mForcedAppOrientation
  25.                     + ", req=" + mRequestedRotation + ")");
  26.             mRotation = rotation;
  27.             mWindowsFreezingScreen = true;
  28.             mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
  29.             mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT),
  30.                     2000);
  31.             mWaitingForConfig = true;
  32.             mLayoutNeeded = true;
  33.             startFreezingDisplayLocked();
  34.             Slog.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags);
  35.             mInputManager.setDisplayOrientation(0, rotation);
  36.             if (mDisplayEnabled) {
  37. //Surface.setOrientation()这里将进行调整Orientation
  38.                 Surface.setOrientation(0, rotation, animFlags);
  39.             }
  40.             for (int i=mWindows.size()-1; i>=0; i--) {
  41.                 WindowState w = mWindows.get(i);
  42.                 if (w.mSurface != null) {
  43.                     w.mOrientationChanging = true;
  44.                 }
  45.             }
  46.             for (int i=mRotationWatchers.size()-1; i>=0; i--) {
  47.                 try {
  48.                     mRotationWatchers.get(i).onRotationChanged(rotation);
  49.                 } catch (RemoteException e) {
  50.                 }
  51.             }
  52.         } //end if changed

  53.         return changed;
  54.     }
复制代码


下面在对rotationForOrientationLw()进行解析一下:
在setRotationUncheckedLocked()中的 mPolicy.rotationForOrientationLw()如是:



  1. otationForOrientationLw(int orientation, int lastRotation,
  2.             boolean displayEnabled) {

  3.         if (mPortraitRotation < 0) {
  4.             // Initialize the rotation angles for each orientation once.
  5.             Display d = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
  6.                     .getDefaultDisplay();
  7. //这里的d.getWidth() 和 d.getHeight()得到的是物理屏幕的宽高。
  8. //平板跟手机不一样。平板的宽比高大
  9. //(0度时位于//landscape模式,右转90度进入porit模式),
  10. //而手机是高比宽大(0度是位于porit模式,右转90度进入landscape模式)。
  11. //所以下面我做的是对平板的修改
  12.             if (d.getWidth() > d.getHeight()) {
  13.                 //mPortraitRotation = Surface.ROTATION_90;
  14.                 mPortraitRotation = Surface.ROTATION_270;
  15.                 mLandscapeRotation = Surface.ROTATION_0;
  16.                 //mUpsideDownRotation = Surface.ROTATION_270;
  17.                 mUpsideDownRotation = Surface.ROTATION_90;
  18.                 mSeascapeRotation = Surface.ROTATION_180;
  19.             } else {
  20.                 mPortraitRotation = Surface.ROTATION_0;
  21.                 //mLandscapeRotation = Surface.ROTATION_90;
  22.                 mLandscapeRotation = Surface.ROTATION_270;
  23.                 mUpsideDownRotation = Surface.ROTATION_180;
  24.                 //mSeascapeRotation = Surface.ROTATION_270;
  25.                 mSeascapeRotation = Surface.ROTATION_90;
  26.             }
  27.         }
  28. ......
  29. }
复制代码


2.如果g-sensor在旋转上有不旋转的方向或者方向不是很灵敏,则我们从下面进行分析:

主要流程如下:
–>WindowOrientationListener.java中的onSensorChanged()
–>computeNewOrientation()
–>filterOrientation()
–>calculateNewRotation()
calculateNewRotation()
–>mOrientationListener.onOrientationChanged()
PhoneWindowManager.java 中的onOrientationChanged()
–>mWindowManager.setRotation()

首先在android中的x,y,z定义如下摘自http://developer.android.com/ref ... re/SensorEvent.html
Class Overview

This class represents a Sensor event and holds informations such as the sensor’s type, the time-stamp, accuracy and of course the sensor’s data.

Definition of the coordinate system used by the SensorEvent API.

The coordinate-system is defined relative to the screen of the phone in its default orientation. The axes are not swapped when the device’s screen orientation changes.

The X axis is horizontal and points to the right, the Y axis is vertical and points up and the Z axis points towards the outside of the front face of the screen. In this system, coordinates behind the screen have negative Z values.

Sensors coordinate-system diagram.

Note: This coordinate system is different from the one used in the Android 2D APIs where the origin is in the top-left corner.

frameworks/base/core/java/android/view/WindowOrientationListener.java
WindowOrientationListener.java 是一个abstract class,它主要是把从gsensor获取到的数据转化为orientation.
每次sensor有进行改变时都会调用到以下函数进行计算Orientation。



  1. public void onSensorChanged(SensorEvent event) {
  2.             // the vector given in the SensorEvent points straight up (towards the sky) under ideal
  3.             // conditions (the phone is not accelerating).  i'll call this upVector elsewhere.
  4.             float x = event.values[_DATA_X];
  5.             float y = event.values[_DATA_Y];
  6.             float z = event.values[_DATA_Z];
  7.             float magnitude = vectorMagnitude(x, y, z);
  8.             float deviation = Math.abs(magnitude - SensorManager.STANDARD_GRAVITY);

  9.             handleAccelerationDistrust(deviation);

  10.             // only filter tilt when we're accelerating
  11.             float alpha = 1;
  12.             if (mAccelerationDistrust > 0) {
  13.                 alpha = ACCELERATING_LOWPASS_ALPHA;
  14.             }
  15.             float newTiltAngle = tiltAngle(z, magnitude);
  16.             mTiltAngle = lowpassFilter(newTiltAngle, mTiltAngle, alpha);

  17.             float absoluteTilt = Math.abs(mTiltAngle);
  18.             checkFullyTilted(absoluteTilt);
  19.             if (mTiltDistrust > 0) {
  20.                 return; // when fully tilted, ignore orientation entirely
  21.             }
  22. //下面通过x,y计算得到新的OrientationAngle,计算方法如下
  23. //        private float computeNewOrientation(float x, float y) {
  24. //           float orientationAngle = (float) -Math.atan2(-x, y) * RADIANS_TO_DEGREES;
  25.             // atan2 returns [-180, 180]; normalize to [0, 360]
  26. //            if (orientationAngle < 0) {
  27. //               orientationAngle += 360;
  28. //            }
  29. //            return orientationAngle;
  30. //        }
  31.             float newOrientationAngle = computeNewOrientation(x, y);
  32. //通过下面函数计算出Orientation的值。
  33.             filterOrientation(absoluteTilt, newOrientationAngle);
  34.             calculateNewRotation(mOrientationAngle, absoluteTilt);
  35.         }
复制代码


这里对calculateNewRotation进行分析前必须先对SensorEventListenerImpl类中的一些变量先进行解释:


  1. private static final int[][][] THRESHOLDS = new int[][][] {
  2. {{60, 180}, {180, 300}},
  3. {{0, 30}, {195, 315}, {315, 360}},
  4. {{0, 45}, {45, 165}, {330, 360}},

  5. // Handle situation where we are currently doing 180 rotation
  6. // but that is no longer allowed.
  7. {{0, 45}, {45, 135}, {135, 225}, {225, 315}, {315, 360}},
  8. };
  9. // See THRESHOLDS
  10. private static final int[][] ROTATE_TO = new int[][] {
  11. {ROTATION_90, ROTATION_270},
  12. {ROTATION_0, ROTATION_270, ROTATION_0},
  13. {ROTATION_0, ROTATION_90, ROTATION_0},
  14. {ROTATION_0, ROTATION_90, ROTATION_0, ROTATION_270, ROTATION_0},
  15. };

  16. private static final int[][][] THRESHOLDS_WITH_180 = new int[][][] {
  17. {{60, 165}, {165, 195}, {195, 300}},
  18. {{0, 30}, {165, 195}, {195, 315}, {315, 360}},
  19. {{0, 45}, {45, 165}, {165, 195}, {330, 360}},
  20. {{0, 45}, {45, 135}, {225, 315}, {315, 360}},
  21. };
  22. private static final int[][] ROTATE_TO_WITH_180 = new int[][] {
  23. {ROTATION_90, ROTATION_180, ROTATION_270},
  24. {ROTATION_0, ROTATION_180, ROTATION_90, ROTATION_0},
  25. {ROTATION_0, ROTATION_270, ROTATION_180, ROTATION_0},
  26. {ROTATION_0, ROTATION_90, ROTATION_270, ROTATION_0},
  27. };
  28. //当设备平放,屏幕朝正上方。以下四个常量分别代表:
  29. private static final int ROTATION_0 = 0;//初始情况。横/竖屏与一开始设置有关
  30. private static final int ROTATION_90 = 1;//右侧翻起侧立时,屏幕会旋转到这个方向。
  31. private static final int ROTATION_270 = 2;//左侧翻起度侧立时,屏幕会旋转到这个方向。
  32. private static final int ROTATION_180 = 3;//屏幕底部侧立时,屏幕会旋转到这个方向

  33. //如上则
  34. // {ROTATION_90, ROTATION_180, ROTATION_270}
  35. //对应落在的范围为 {{60, 165}, {165, 195}, {195, 300}}
  36. //{ROTATION_0, ROTATION_180, ROTATION_90, ROTATION_0}
  37. //对应落在的范围为 {{0, 30}, {165, 195}, {195, 315}, {315, 360}}
  38. //{ROTATION_0, ROTATION_270, ROTATION_180, ROTATION_0}
  39. //对应落在的范围为 {{0, 45}, {45, 165}, {165, 195}, {330, 360}}
  40. //{ROTATION_0, ROTATION_90, ROTATION_270, ROTATION_0}
  41. //对应落在的范围为{{0, 45}, {45, 135}, {225, 315}, {315, 360}}
  42. //所以如果需要微调的话只要修改对应的范围既可

  43. //当前屏幕旋转方向为ROTATION_0时,取int[][] threshold=THRESHOLDS_WITH_180[0];
  44. //此时的范围为:{{60, 165}, {165, 195}, {195, 300}}
  45. //当前屏幕旋转方向为ROTATION_90时,取int[][] threshold=THRESHOLDS_WITH_180[1];
  46. //此时的范围为:{{0, 30}, {165, 195}, {195, 315}, {315, 360}}
  47. //当前屏幕旋转方向为ROTATION_270时,取int[][] threshold=THRESHOLDS_WITH_180[2];
  48. //此时的范围为:{{0, 45}, {45, 165}, {165, 195}, {330, 360}}
  49. //当前屏幕旋转方向为ROTATION_180时,取int[][] threshold=THRESHOLDS_WITH_180[3];
  50. //此时的范围为:{{0, 45}, {45, 135}, {225, 315}, {315, 360}}

  51. //例如当前我们的位置为ROTATION_90那么此时我们的THRESHOLDS_WITH_180就
  52. //为{{0, 30}, {165, 195}, {195, 315}, {315, 360}}
  53. //,然后通过filterOrientation计算出的orientation值落在了第2个元素围内,则到ROTATE_TO_WITH_180找到对应的值,
  54. //这里为ROTATION_180,则此时把方向选装到ROTATION_180
复制代码



对上面的变量稍微了解后对下面的分析就很简单了。


  1. private void calculateNewRotation(float orientation, float tiltAngle) {
  2. //这里的orientation,tiltAngle,mRotation为gsensor获取到的最新的数据
  3.             if (localLOGV) Log.i(TAG, orientation + ", " + tiltAngle + ", " + mRotation);
  4. //是否允许180度旋转,这里定义的其实就是变成了360度旋转了,
  5. //如果mAllow180Rotation为false时,上面的变量中使用的为THRESHOLDS以及ROTATE_TO
  6. //如果为ture则为THRESHOLDS_WITH_180与ROTATE_TO_WITH_180
  7.             final boolean allow180Rotation = mAllow180Rotation;
  8.             int thresholdRanges[][] = allow180Rotation
  9.                     ? THRESHOLDS_WITH_180[mRotation] : THRESHOLDS[mRotation];
  10.             int row = -1;
  11.             for (int i = 0; i < thresholdRanges.length; i++) {
  12.                 if (orientation >= thresholdRanges[i][0] && orientation < thresholdRanges[i][1]) {
  13.                     row = i;
  14.                     break;
  15.                 }
  16.             }
  17.             if (row == -1) return; // no matching transition

  18.             int rotation = allow180Rotation
  19.                     ? ROTATE_TO_WITH_180[mRotation][row] : ROTATE_TO[mRotation][row];
  20.             if (tiltAngle > MAX_TRANSITION_TILT[rotation]) {
  21.                 // tilted too far flat to go to this rotation
  22.                 return;
  23.             }

  24.             if (localLOGV) Log.i(TAG, "orientation " + orientation + " gives new rotation = "
  25.                     + rotation);
  26.             mRotation = rotation;
  27. //这里通过WindowOrientationListener监听调用onOrientationChanged中的setRotation从而旋转界面
  28.             mOrientationListener.onOrientationChanged(INTERNAL_TO_SURFACE_ROTATION[mRotation]);
  29.         }
复制代码


onOrientationChanged()的实现在PhoneWindowManager.java 中,如下:


  1. class MyOrientationListener extends WindowOrientationListener {
  2.        MyOrientationListener(Context context) {
  3.            super(context);
  4.        }

  5.        @Override
  6.        public void onOrientationChanged(int rotation) {
  7.            // Send updates based on orientation value
  8.            if (localLOGV) Log.v(TAG, "onOrientationChanged, rotation changed to " +rotation);
  9.            try {
  10.                mWindowManager.setRotation(rotation, false,
  11.                        mFancyRotationAnimation);
  12.        SystemProperties.set("service.screen.rotation", ""+rotation);
  13.            } catch (RemoteException e) {
  14.                // Ignore

  15.            }
  16.        }
  17.    }
复制代码


基本上整个流程到此结束。

转载时请注明出处和作者
文章出处:http://www.code007.org/
作者:Code007

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值