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

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

 

 

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

 

 

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

 

  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.         }  

 

public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { … } else if (preference == mAccelerometer) { Settings.System.putInt(getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, mAccelerometer.isChecked() ? 1 : 0); … }  

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

 

 

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

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

 

 

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

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

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

 

 

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

 

 

修改下面函数 void android.view.WindowOrientationListener .SensorEventListenerImpl .onSensorChanged(android.hardware.SensorEvent event)


            float[] values = event.values;
             
            float X = values[_DATA_X];
            float Y = values[_DATA_Y];
            float Z = values[_DATA_Z];
            //For fixing the problem of Sensor change the window orientation error but the sensor game is no problem.
            float OneEightyOverPi = 57.29577957855f;
            float gravity = (float) Math.sqrt(X*X+Y*Y+Z*Z);
            float zyangle = (float)Math.asin(Z/gravity)*OneEightyOverPi;
            int rotation = -1;
            if ((zyangle <= PIVOT_UPPER) && (zyangle >= PIVOT_LOWER)) {
                // Check orientation only if the phone is flat enough
                // Don't trust the angle if the magnitude is small compared to the y value
                float angle = (float)Math.atan2(Y, -X) * OneEightyOverPi;
                int orientation = 90 - (int)Math.round(angle);
                // normalize to 0 - 359 range
                while (orientation >= 360) {
                    orientation -= 360;
                }
                while (orientation < 0) {
                    orientation += 360;
                }
                Log.i("Tiger","orientation="+orientation);
                 //确定由角度与屏幕方向的对应范围
                if(orientation > 325 || orientation <= 45){
                rotation = Surface.ROTATION_0;
                }else if(orientation > 45 && orientation <= 135){
                rotation = Surface.ROTATION_270;
                }else if(orientation > 135 && orientation < 225){
                rotation = Surface.ROTATION_180;
                }else {
                rotation = Surface.ROTATION_90;
                }
               
                Log.i("Tiger","mSensorRotation="+mSensorRotation+"    , rotation="+rotation);
                if ((rotation != -1) && (rotation != mSensorRotation)) {
                    mSensorRotation = rotation;
                    onOrientationChanged(mSensorRotation);
                }
            }

 

  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. }  
public void onSensorChanged(SensorEvent event) { float[] values = event.values; float X = values[_DATA_X]; float Y = values[_DATA_Y]; float Z = values[_DATA_Z]; float OneEightyOverPi = 57.29577957855f; float gravity = (float) Math.sqrt(X*X+Y*Y+Z*Z); float zyangle = (float)Math.asin(Z/gravity)*OneEightyOverPi; int rotation = -1; if ((zyangle <= PIVOT_UPPER) && (zyangle >= PIVOT_LOWER)) { // Check orientation only if the phone is flat enough // Don't trust the angle if the magnitude is small compared to the y value float angle = (float)Math.atan2(Y, -X) * OneEightyOverPi; int orientation = 90 - (int)Math.round(angle); // normalize to 0 - 359 range while (orientation >= 360) { orientation -= 360; } while (orientation < 0) { orientation += 360; } // Orientation values between LANDSCAPE_LOWER and PL_LOWER // are considered landscape. // Ignore orientation values between 0 and LANDSCAPE_LOWER // For orientation values between LP_UPPER and PL_LOWER, // the threshold gets set linearly around PIVOT. if ((orientation >= PL_LOWER) && (orientation <= LP_UPPER)) { float threshold; float delta = zyangle - PIVOT; if (mSensorRotation == Surface.ROTATION_90) { if (delta < 0) { // Delta is negative threshold = LP_LOWER - (LP_LF_LOWER * delta); } else { threshold = LP_LOWER + (LP_LF_UPPER * delta); } rotation = (orientation >= threshold) ? Surface.ROTATION_0 : Surface.ROTATION_90; } else { if (delta < 0) { // Delta is negative threshold = PL_UPPER+(PL_LF_LOWER * delta); } else { threshold = PL_UPPER-(PL_LF_UPPER * delta); } rotation = (orientation <= threshold) ? Surface.ROTATION_90: Surface.ROTATION_0; } } else if ((orientation >= LANDSCAPE_LOWER) && (orientation < LP_LOWER)) { rotation = Surface.ROTATION_90; } else if ((orientation >= PL_UPPER) || (orientation <= PORTRAIT_LOWER)) { rotation = Surface.ROTATION_0; } if ((rotation != -1) && (rotation != mSensorRotation)) { mSensorRotation = rotation; onOrientationChanged(mSensorRotation); } } }  

 

  1. class  MyOrientationListener  extends  WindowOrientationListener {  
  2.       MyOrientationListener(Context context) {  
  3.           super (context);  
  4.       }  
  5.         
  6.       @Override   
  7.       public   void  onOrientationChanged( int  rotation) {  
  8.           // Send updates based on orientation value   
  9.           if  ( true ) Log.i(TAG,  "onOrientationChanged, rotation changed to "  +rotation);  
  10.           try  {  
  11.               mWindowManager.setRotation(rotation, false ,  
  12.                       mFancyRotationAnimation);  
  13.           } catch  (RemoteException e) {  
  14.               // Ignore   
  15.           }  
  16.       }                                        
  17.   }  
  18.   MyOrientationListener mOrientationListener;  
  19.   boolean  useSensorForOrientationLp( int  appOrientation) {  
  20.       if  (appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) {  
  21.           return   true ;  
  22.       }  
  23.       if  (mAccelerometerDefault !=  0  && (  
  24.               appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER ||  
  25.               appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) {  
  26.           return   true ;  
  27.       }  
  28.       return   false ;  
  29.   }  
  30.     
  31.   /*  
  32.    * We always let the sensor be switched on by default except when  
  33.    * the user has explicitly disabled sensor based rotation or when the  
  34.    * screen is switched off.  
  35.    */   
  36.   boolean  needSensorRunningLp() {  
  37.       if  (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) {  
  38.           // If the application has explicitly requested to follow the   
  39.           // orientation, then we need to turn the sensor or.   
  40.           return   true ;  
  41.       }  
  42.       if  (mAccelerometerDefault ==  0 ) {  
  43.           // If the setting for using the sensor by default is enabled, then   
  44.           // we will always leave it on.  Note that the user could go to   
  45.           // a window that forces an orientation that does not use the   
  46.           // sensor and in theory we could turn it off... however, when next   
  47.           // turning it on we won't have a good value for the current   
  48.           // orientation for a little bit, which can cause orientation   
  49.           // changes to lag, so we'd like to keep it always on.  (It will   
  50.           // still be turned off when the screen is off.)   
  51.           return   false ;  
  52.       }  
  53.       return   true ;  
  54.   }  
class MyOrientationListener extends WindowOrientationListener { MyOrientationListener(Context context) { super(context); } @Override public void onOrientationChanged(int rotation) { // Send updates based on orientation value if (true) Log.i(TAG, "onOrientationChanged, rotation changed to " +rotation); try { mWindowManager.setRotation(rotation, false, mFancyRotationAnimation); } catch (RemoteException e) { // Ignore } } } MyOrientationListener mOrientationListener; boolean useSensorForOrientationLp(int appOrientation) { if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { return true; } if (mAccelerometerDefault != 0 && ( appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) { return true; } return false; } /* * We always let the sensor be switched on by default except when * the user has explicitly disabled sensor based rotation or when the * screen is switched off. */ boolean needSensorRunningLp() { if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { // If the application has explicitly requested to follow the // orientation, then we need to turn the sensor or. return true; } if (mAccelerometerDefault == 0) { // If the setting for using the sensor by default is enabled, then // we will always leave it on. Note that the user could go to // a window that forces an orientation that does not use the // sensor and in theory we could turn it off... however, when next // turning it on we won't have a good value for the current // orientation for a little bit, which can cause orientation // changes to lag, so we'd like to keep it always on. (It will // still be turned off when the screen is off.) return false; } return true; }  

 

  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. }  

 

public void update() { ContentResolver resolver = mContext.getContentResolver(); boolean updateRotation = false; synchronized (mLock) { … int accelerometerDefault = Settings.System.getInt(resolver, Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION); if (mAccelerometerDefault != accelerometerDefault) { mAccelerometerDefault = accelerometerDefault; updateOrientationListenerLp(); } … }  

 

 

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

 

  1. private static final String KEY_ACCELEROMETER = "accelerometer";  
private static final String KEY_ACCELEROMETER = "accelerometer";  
創作者介紹
創作者 shadow 的頭像
shadow

資訊園

shadow 發表在 痞客邦 留言(0) 人氣()