利用GSensor让屏幕实现360度旋转

在 Android的 Settings->Sound and Display中有 Orientation这一设置项。当选中时,反转手机,手机屏幕会随之旋转,一般只可以旋转90度。

这一 settings设置是在文件 SoundAndDisplaySettings.java中,该项对应的键字符串为:

  1. private   static   final  String KEY_ACCELEROMETER =  "accelerometer" ;  
复制代码
Java代码
  1. private static final String KEY_ACCELEROMETER = "accelerometer";
复制代码

其默认值保存在 xml文件中,默认是 Enable。 UI程序初始化时会根据其值是否在复选框中打勾(代码在 onCreate函数中):

  1.    protected   void  onCreate(Bundle savedInstanceState) {  
  2. …  
  3.         mAccelerometer = (CheckBoxPreference) findPreference(KEY_ACCELEROMETER);  
  4.         mAccelerometer.setPersistent(false );  
  5. …  
  6. }  
复制代码
Java代码
  1.   protected void onCreate(Bundle savedInstanceState) {  
  2. …  
  3.         mAccelerometer = (CheckBoxPreference) findPreference(KEY_ACCELEROMETER);  
  4.         mAccelerometer.setPersistent(false);  
  5. …  
  6. }  
复制代码



当用户改变了该值时,会保存起来:



Java代码

  1. public   boolean  onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {  
  2. …  
  3.     } else   if  (preference == mAccelerometer) {  
  4.             Settings.System.putInt(getContentResolver(),  
  5.                     Settings.System.ACCELEROMETER_ROTATION,  
  6.                     mAccelerometer.isChecked() ? 1  :  0 );  
  7. …  
  8.         }  
复制代码
  1. public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {  
  2. …  
  3.     } else if (preference == mAccelerometer) {  
  4.             Settings.System.putInt(getContentResolver(),  
  5.                     Settings.System.ACCELEROMETER_ROTATION,  
  6.                     mAccelerometer.isChecked() ? 1 : 0);  
  7. …  
  8.         }  
复制代码

文件 frameworks/policies/base/phone/com/android/internal/policy/impl/PhoneWindowManager.java中的 SettingsServer会随时监控其值,对用户设置做出反应:



  1. public void update() {  
  2.             ContentResolver resolver = mContext.getContentResolver();  
  3.             boolean updateRotation = false ;  
  4.             synchronized (mLock) {  
  5.                 …  
  6.                 int accelerometerDefault = Settings.System.getInt(resolver,  
  7.                         Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION);  
  8.                 if (mAccelerometerDefault != accelerometerDefault) {  
  9.                     mAccelerometerDefault = accelerometerDefault;  
  10.                     updateOrientationListenerLp();  
  11.                 }  
  12. …  
  13. }  
复制代码

Java代码

  1. publicvoid update() {  
  2.             ContentResolver resolver = mContext.getContentResolver();  
  3.             boolean updateRotation = false;  
  4.             synchronized (mLock) {  
  5.                 …  
  6.                 int accelerometerDefault = Settings.System.getInt(resolver,  
  7.                         Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION);  
  8.                 if (mAccelerometerDefault != accelerometerDefault) {  
  9.                     mAccelerometerDefault = accelerometerDefault;  
  10.                     updateOrientationListenerLp();  
  11.                 }  
  12. …  
  13. }  
复制代码

上述是设置生效流程。当 Orientation设置 Enable时,会发生什么呢?

在 PhoneWindowManager.java有个 Listener,它会根据 Sensor判别出的旋转方向,调用 WindowManager.setRotation让屏幕进行旋转。另外,当应用程序显示禁止屏幕旋转时则不会旋转,见函数 needSensorRunningLp()。


  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 ( true ) Log.i(TAG, "onOrientationChanged, rotation changed to " +rotation);  
  9.           try {  
  10.               mWindowManager.setRotation(rotation, false ,  
  11.                       mFancyRotationAnimation);  
  12.           } catch (RemoteException e) {  
  13.               // Ignore
  14.           }  
  15.       }                                       
  16.   }  
  17.   MyOrientationListener mOrientationListener;  
  18.   boolean useSensorForOrientationLp( int appOrientation) {  
  19.       if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) {  
  20.           return true ;  
  21.       }  
  22.       if (mAccelerometerDefault != 0 && (  
  23.               appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER ||  
  24.               appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) {  
  25.           return true ;  
  26.       }  
  27.       return false ;  
  28.   }  

  29.   /*  
  30.    * We always let the sensor be switched on by default except when  
  31.    * the user has explicitly disabled sensor based rotation or when the  
  32.    * screen is switched off.  
  33.    */
  34.   boolean needSensorRunningLp() {  
  35.       if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) {  
  36.           // If the application has explicitly requested to follow the
  37.           // orientation, then we need to turn the sensor or.
  38.           return true ;  
  39.       }  
  40.       if (mAccelerometerDefault == 0 ) {  
  41.           // If the setting for using the sensor by default is enabled, then
  42.           // we will always leave it on.  Note that the user could go to
  43.           // a window that forces an orientation that does not use the
  44.           // sensor and in theory we could turn it off... however, when next
  45.           // turning it on we won't have a good value for the current
  46.           // orientation for a little bit, which can cause orientation
  47.           // changes to lag, so we'd like to keep it always on.  (It will
  48.           // still be turned off when the screen is off.)
  49.           return false ;  
  50.       }  
  51.       return true ;  
  52.   }
复制代码

Java代码


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

  5.       @Override
  6.       publicvoid onOrientationChanged(int rotation) {  
  7.           // Send updates based on orientation value
  8.           if (true) Log.i(TAG, "onOrientationChanged, rotation changed to " +rotation);  
  9.           try {  
  10.               mWindowManager.setRotation(rotation, false,  
  11.                       mFancyRotationAnimation);  
  12.           } catch (RemoteException e) {  
  13.               // Ignore
  14.           }  
  15.       }                                       
  16.   }  
  17.   MyOrientationListener mOrientationListener;  
  18.   boolean useSensorForOrientationLp(int appOrientation) {  
  19.       if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) {  
  20.           returntrue;  
  21.       }  
  22.       if (mAccelerometerDefault != 0 && (  
  23.               appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER ||  
  24.               appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) {  
  25.           returntrue;  
  26.       }  
  27.       returnfalse;  
  28.   }  

  29.   /*
  30.    * We always let the sensor be switched on by default except when
  31.    * the user has explicitly disabled sensor based rotation or when the
  32.    * screen is switched off.
  33.    */
  34.   boolean needSensorRunningLp() {  
  35.       if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) {  
  36.           // If the application has explicitly requested to follow the
  37.           // orientation, then we need to turn the sensor or.
  38.           returntrue;  
  39.       }  
  40.       if (mAccelerometerDefault == 0) {  
  41.           // If the setting for using the sensor by default is enabled, then
  42.           // we will always leave it on.  Note that the user could go to
  43.           // a window that forces an orientation that does not use the
  44.           // sensor and in theory we could turn it off... however, when next
  45.           // turning it on we won't have a good value for the current
  46.           // orientation for a little bit, which can cause orientation
  47.           // changes to lag, so we'd like to keep it always on.  (It will
  48.           // still be turned off when the screen is off.)
  49.           returnfalse;  
  50.       }  
  51.       returntrue;  
  52.   }  
复制代码

在 WindowOrientationListener(见文件 javaframeworks/base/core/java/android/view/WindowOrientationListener.java)中会监听Sensor的值,对旋转方向进行判断,然后调用抽象方法 onOrientationChanged,因此,只要在子类 Listener中重新实现这个函数即可对四个不同方向做出响应(见上面让屏幕旋转即是一例)。

遗憾的是在 Donut和 Éclair中,对旋转方向的识别只给出了 90度旋转,在 Froyo中增加了一个 270度旋转,不支持 180度即倒立的操作。

可以在修改下面代码,判断来自于 Gsensor的值,识别出旋转方向:


  1. public void onSensorChanged(SensorEvent event) {  
  2.     float [] values = event.values;  
  3.     float X = values[_DATA_X];  
  4.     float Y = values[_DATA_Y];  
  5.     float Z = values[_DATA_Z];  
  6.     float OneEightyOverPi = 57 .29577957855f;  
  7.     float gravity = ( float ) Math.sqrt(X*X+Y*Y+Z*Z);  
  8.     float zyangle = ( float )Math.asin(Z/gravity)*OneEightyOverPi;  
  9.     int rotation = - 1 ;  
  10.     if ((zyangle <= PIVOT_UPPER) && (zyangle >= PIVOT_LOWER)) {  
  11.         // Check orientation only if the phone is flat enough
  12.         // Don't trust the angle if the magnitude is small compared to the y value
  13.         float angle = ( float )Math.atan2(Y, -X) * OneEightyOverPi;  
  14.         int orientation = 90 - ( int )Math.round(angle);  
  15.         // normalize to 0 - 359 range
  16.         while (orientation >= 360 ) {  
  17.             orientation -= 360 ;  
  18.         }   
  19.         while (orientation < 0 ) {  
  20.             orientation += 360 ;  
  21.         }  
  22.         // Orientation values between  LANDSCAPE_LOWER and PL_LOWER
  23.         // are considered landscape.
  24.         // Ignore orientation values between 0 and LANDSCAPE_LOWER
  25.         // For orientation values between LP_UPPER and PL_LOWER,
  26.         // the threshold gets set linearly around PIVOT.
  27.         if ((orientation >= PL_LOWER) && (orientation <= LP_UPPER)) {  
  28.             float threshold;  
  29.             float delta = zyangle - PIVOT;  
  30.             if (mSensorRotation == Surface.ROTATION_90) {  
  31.                 if (delta < 0 ) {  
  32.                     // Delta is negative
  33.                     threshold = LP_LOWER - (LP_LF_LOWER * delta);  
  34.                 } else {  
  35.                     threshold = LP_LOWER + (LP_LF_UPPER * delta);  
  36.                 }  
  37.                 rotation = (orientation >= threshold) ? Surface.ROTATION_0 : Surface.ROTATION_90;  
  38.             } else {  
  39.                 if (delta < 0 ) {  
  40.                     // Delta is negative
  41.                     threshold = PL_UPPER+(PL_LF_LOWER * delta);  
  42.                 } else {  
  43.                     threshold = PL_UPPER-(PL_LF_UPPER * delta);  
  44.                 }  
  45.                 rotation = (orientation <= threshold) ? Surface.ROTATION_90: Surface.ROTATION_0;  
  46.             }  
  47.         } else if ((orientation >= LANDSCAPE_LOWER) && (orientation < LP_LOWER)) {  
  48.             rotation = Surface.ROTATION_90;  
  49.         } else if ((orientation >= PL_UPPER) || (orientation <= PORTRAIT_LOWER)) {  
  50.             rotation = Surface.ROTATION_0;  
  51.         }  
  52.         if ((rotation != - 1 ) && (rotation != mSensorRotation)) {  
  53.             mSensorRotation = rotation;  
  54.             onOrientationChanged(mSensorRotation);  
  55.         }  
  56.     }  
  57. }  
复制代码


Java代码


  1. publicvoid onSensorChanged(SensorEvent event) {  
  2.     float[] values = event.values;  
  3.     float X = values[_DATA_X];  
  4.     float Y = values[_DATA_Y];  
  5.     float Z = values[_DATA_Z];  
  6.     float OneEightyOverPi = 57.29577957855f;  
  7.     float gravity = (float) Math.sqrt(X*X+Y*Y+Z*Z);  
  8.     float zyangle = (float)Math.asin(Z/gravity)*OneEightyOverPi;  
  9.     int rotation = -1;  
  10.     if ((zyangle <= PIVOT_UPPER) && (zyangle >= PIVOT_LOWER)) {  
  11.         // Check orientation only if the phone is flat enough
  12.         // Don't trust the angle if the magnitude is small compared to the y value
  13.         float angle = (float)Math.atan2(Y, -X) * OneEightyOverPi;  
  14.         int orientation = 90 - (int)Math.round(angle);  
  15.         // normalize to 0 - 359 range
  16.         while (orientation >= 360) {  
  17.             orientation -= 360;  
  18.         }   
  19.         while (orientation < 0) {  
  20.             orientation += 360;  
  21.         }  
  22.         // Orientation values between  LANDSCAPE_LOWER and PL_LOWER
  23.         // are considered landscape.
  24.         // Ignore orientation values between 0 and LANDSCAPE_LOWER
  25.         // For orientation values between LP_UPPER and PL_LOWER,
  26.         // the threshold gets set linearly around PIVOT.
  27.         if ((orientation >= PL_LOWER) && (orientation <= LP_UPPER)) {  
  28.             float threshold;  
  29.             float delta = zyangle - PIVOT;  
  30.             if (mSensorRotation == Surface.ROTATION_90) {  
  31.                 if (delta < 0) {  
  32.                     // Delta is negative
  33.                     threshold = LP_LOWER - (LP_LF_LOWER * delta);  
  34.                 } else {  
  35.                     threshold = LP_LOWER + (LP_LF_UPPER * delta);  
  36.                 }  
  37.                 rotation = (orientation >= threshold) ? Surface.ROTATION_0 : Surface.ROTATION_90;  
  38.             } else {  
  39.                 if (delta < 0) {  
  40.                     // Delta is negative
  41.                     threshold = PL_UPPER+(PL_LF_LOWER * delta);  
  42.                 } else {  
  43.                     threshold = PL_UPPER-(PL_LF_UPPER * delta);  
  44.                 }  
  45.                 rotation = (orientation <= threshold) ? Surface.ROTATION_90: Surface.ROTATION_0;  
  46.             }  
  47.         } elseif ((orientation >= LANDSCAPE_LOWER) && (orientation < LP_LOWER)) {  
  48.             rotation = Surface.ROTATION_90;  
  49.         } elseif ((orientation >= PL_UPPER) || (orientation <= PORTRAIT_LOWER)) {  
  50.             rotation = Surface.ROTATION_0;  
  51.         }  
  52.         if ((rotation != -1) && (rotation != mSensorRotation)) {  
  53.             mSensorRotation = rotation;  
  54.             onOrientationChanged(mSensorRotation);  
  55.         }  
  56.     }  
  57. }  
复制代码

在Froyo中,对上述算法进行了修改,让其报出270度的旋转方向。


Android Sensor 屏幕360度旋转实现

修改下面函数


  1. void android.view.WindowOrientationListener SensorEventListenerImp.onSensorChanged(android.hardware.SensorEvent event)
  2.             float[] values = event.values;
  3.             
  4.             float X = values[_DATA_X];
  5.             float Y = values[_DATA_Y];
  6.             float Z = values[_DATA_Z];
  7.             //For fixing the problem of Sensor change the window orientation error but the sensor game is no problem.
  8.             float OneEightyOverPi = 57.29577957855f;
  9.             float gravity = (float) Math.sqrt(X*X+Y*Y+Z*Z);
  10.             float zyangle = (float)Math.asin(Z/gravity)*OneEightyOverPi;
  11.             int rotation = -1;
  12.             if ((zyangle <= PIVOT_UPPER) && (zyangle >= PIVOT_LOWER)) {
  13.                 // Check orientation only if the phone is flat enough
  14.                 // Don't trust the angle if the magnitude is small compared to the y value
  15.                 float angle = (float)Math.atan2(Y, -X) * OneEightyOverPi;
  16.                 int orientation = 90 - (int)Math.round(angle);
  17.                 // normalize to 0 - 359 range
  18.                 while (orientation >= 360) {
  19.                     orientation -= 360;
  20.                 }
  21.                 while (orientation < 0) {
  22.                     orientation += 360;
  23.                 }
  24.                 Log.i("Tiger","orientation="+orientation);
  25.                  //确定由角度与屏幕方向的对应范围
  26.                 if(orientation > 325 || orientation <= 45){
  27.                 rotation = Surface.ROTATION_0;
  28.                 }else if(orientation > 45 && orientation <= 135){
  29.                 rotation = Surface.ROTATION_270;
  30.                 }else if(orientation > 135 && orientation < 225){
  31.                 rotation = Surface.ROTATION_180;
  32.                 }else {
  33.                 rotation = Surface.ROTATION_90;
  34.                 }
  35.                
  36.                 Log.i("Tiger","mSensorRotation="+mSensorRotation+"    , rotation="+rotation);
  37.                 if ((rotation != -1) && (rotation != mSensorRotation)) {
  38.                     mSensorRotation = rotation;
  39.                     onOrientationChanged(mSensorRotation);
  40.                 }
  41.             }
复制代码

你可能感兴趣的:(java,user,application,360,float,PIVOT)