概述
在 Android的 Settings->Sound and Display中有 Orientation这一设置项。当选中时,反转手机,手机屏幕会随之旋转,一般只可以旋转90度。
这一 settings设置是在文件 SoundAndDisplaySettings.java中,该项对应的键字符串为:
- private static final String KEY_ACCELEROMETER = "accelerometer" ;
- private static final String KEY_ACCELEROMETER = "accelerometer";
其默认值保存在 xml文件中,默认是 Enable。 UI程序初始化时会根据其值是否在复选框中打勾(代码在 onCreate函数中):
- protected void onCreate(Bundle savedInstanceState) {
- …
- mAccelerometer = (CheckBoxPreference) findPreference(KEY_ACCELEROMETER);
- mAccelerometer.setPersistent(false );
- …
- }
- protected void onCreate(Bundle savedInstanceState) {
- …
- mAccelerometer = (CheckBoxPreference) findPreference(KEY_ACCELEROMETER);
- mAccelerometer.setPersistent(false);
- …
- }
当用户改变了该值时,会保存起来:
Java代码
- public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
- …
- } else if (preference == mAccelerometer) {
- Settings.System.putInt(getContentResolver(),
- Settings.System.ACCELEROMETER_ROTATION,
- mAccelerometer.isChecked() ? 1 : 0 );
- …
- }
- 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会随时监控其值,对用户设置做出反应:
- 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代码
- publicvoid 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()。
- 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
- publicvoid 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) {
- returntrue;
- }
- if (mAccelerometerDefault != 0 && (
- appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER ||
- appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) {
- returntrue;
- }
- returnfalse;
- }
- /*
- * 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.
- returntrue;
- }
- 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.)
- returnfalse;
- }
- returntrue;
- }
在 WindowOrientationListener(见文件 javaframeworks/base/core/java/android/view/WindowOrientationListener.java)中会监听Sensor的值,对旋转方向进行判断,然后调用抽象方法 onOrientationChanged,因此,只要在子类 Listener中重新实现这个函数即可对四个不同方向做出响应(见上面让屏幕旋转即是一例)。
遗憾的是在 Donut和 Éclair中,对旋转方向的识别只给出了 90度旋转,在 Froyo中增加了一个 270度旋转,不支持 180度即倒立的操作。
可以在修改下面代码,判断来自于 Gsensor的值,识别出旋转方向:
- 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代码
- publicvoid 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;
- }
- } elseif ((orientation >= LANDSCAPE_LOWER) && (orientation < LP_LOWER)) {
- rotation = Surface.ROTATION_90;
- } elseif ((orientation >= PL_UPPER) || (orientation <= PORTRAIT_LOWER)) {
- rotation = Surface.ROTATION_0;
- }
- if ((rotation != -1) && (rotation != mSensorRotation)) {
- mSensorRotation = rotation;
- onOrientationChanged(mSensorRotation);
- }
- }
- }
在Froyo中,对上述算法进行了修改,让其报出270度的旋转方向。
Android Sensor 屏幕360度旋转实现
修改下面函数
- void android.view.WindowOrientationListener SensorEventListenerImp.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);
- }
- }
最后
以上就是愤怒学姐为你收集整理的利用GSensor让屏幕实现360度旋转的全部内容,希望文章能够帮你解决利用GSensor让屏幕实现360度旋转所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复