zoukankan      html  css  js  c++  java
  • 利用GSensor让屏幕实现360度旋 ...

    http://www.iteye.com/wiki/blog/812749
    
    在Android的Settings->Sound andDisplay中有Orientation这一设置项。当选中时,反转手机,手机屏幕会随之旋转,一般只可以旋转90度。
    
    这一settings设置是在文件SoundAndDisplaySettings.java中,该项对应的键字符串为:
    view plaincopy to clipboardprint?
    
        private static final String KEY_ACCELEROMETER = "accelerometer";  
    
    Java代码
    
        private static final String KEY_ACCELEROMETER = "accelerometer";  
    
     
    
    其默认值保存在xml文件中,默认是Enable。UI程序初始化时会根据其值是否在复选框中打勾(代码在onCreate函数中):
    view plaincopy to clipboardprint?
    
            protected void onCreate(Bundle savedInstanceState) {  
        …  
                mAccelerometer = (CheckBoxPreference) findPreference(KEY_ACCELEROMETER);  
                mAccelerometer.setPersistent(false);  
        …  
        }  
    
    Java代码
    
            protected void onCreate(Bundle savedInstanceState) {  
        …  
                mAccelerometer = (CheckBoxPreference) findPreference(KEY_ACCELEROMETER);  
                mAccelerometer.setPersistent(false);  
        …  
        }  
    
     
    
    当用户改变了该值时,会保存起来:
    
     
    view plaincopy to clipboardprint?
    
        public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {  
        …  
            } else if (preference == mAccelerometer) {  
                    Settings.System.putInt(getContentResolver(),  
                            Settings.System.ACCELEROMETER_ROTATION,  
                            mAccelerometer.isChecked() ? 1 : 0);  
        …  
                }  
    
    Java代码
    
        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会随时监控其值,对用户设置做出反应:
    view plaincopy to clipboardprint?
    
        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();  
                        }  
        …  
        }  
    
    Java代码
    
        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();  
                        }  
        …  
        }  
    
     
    
    上述是设置生效流程。当Orientation设置Enable时,会发生什么呢?
    
    在PhoneWindowManager.java有个Listener,它会根据Sensor判别出的旋转方向,调用WindowManager.setRotation让屏幕进行旋转。另外,当应用程序显示禁止屏幕旋转时则不会旋转,见函数needSensorRunningLp()。
    view plaincopy to clipboardprint?
    
        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;  
          }  
    
    Java代码
    
        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;  
          }  
    
     
    
    在WindowOrientationListener(见文件javaframeworks/base/core/java/android/view/WindowOrientationListener.java)中会监听Sensor的值,对旋转方向进行判断,然后调用抽象方法onOrientationChanged,因此,只要在子类Listener中重新实现这个函数即可对四个不同方向做出响应(见上面让屏幕旋转即是一例)。
    
    遗憾的是在Donut和Éclair中,对旋转方向的识别只给出了90度旋转,在Froyo中增加了一个270度旋转,不支持180度即倒立的操作。
    
    可以在修改下面代码,判断来自于Gsensor的值,识别出旋转方向:
    view plaincopy to clipboardprint?
    
        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);  
                }  
            }  
        }  
    
    Java代码
    
        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);  
                }  
            }  
        }  
    
     
    
    在Froyo中,对上述算法进行了修改,让其报出270度的旋转方向。
    
     
    
     
    Android Sensor 屏幕360度旋转实现
    2010-09-17 10:51
    
    修改下面函数 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);
                    }
                }
    分享到: 


  • 相关阅读:
    Java第三季
    LeetCode(10)Regular Expression Matching
    LeetCode(9)Palindrome Number
    shell基础编程
    LeetCode(8)String to Integer (atoi)
    使用python绘制词云
    我的书单
    LeetCode(7)Reverse Integer
    获取新浪微博的Access_token
    c语言中,常见数据类型的字节数
  • 原文地址:https://www.cnblogs.com/yuzaipiaofei/p/4124316.html
Copyright © 2011-2022 走看看