生活随笔
收集整理的這篇文章主要介紹了
利用GSensor让屏幕实现360度旋转
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
在 Android的 Settings->Sound and Display中有 Orientation這一設(shè)置項(xiàng)。當(dāng)選中時(shí),反轉(zhuǎn)手機(jī),手機(jī)屏幕會(huì)隨之旋轉(zhuǎn),一般只可以旋轉(zhuǎn)90度。
這一 settings設(shè)置是在文件 SoundAndDisplaySettings.java中,該項(xiàng)對(duì)應(yīng)的鍵字符串為:
private? ?static? ?final??String KEY_ACCELEROMETER =??"accelerometer" ;?? 復(fù)制代碼
Java代碼
private static final String KEY_ACCELEROMETER = "accelerometer"; 復(fù)制代碼
其默認(rèn)值保存在 xml文件中,默認(rèn)是 Enable。 UI程序初始化時(shí)會(huì)根據(jù)其值是否在復(fù)選框中打勾(代碼在 onCreate函數(shù)中):
? ?protected? ?void??onCreate(Bundle savedInstanceState) {??
…??
? ?? ???mAccelerometer = (CheckBoxPreference) findPreference(KEY_ACCELEROMETER);??
? ?? ???mAccelerometer.setPersistent(false );??
…??
}?? 復(fù)制代碼
Java代碼
??protected void onCreate(Bundle savedInstanceState) {??
…??
? ?? ???mAccelerometer = (CheckBoxPreference) findPreference(KEY_ACCELEROMETER);??
? ?? ???mAccelerometer.setPersistent(false);??
…??
}?? 復(fù)制代碼
當(dāng)用戶改變了該值時(shí),會(huì)保存起來(lái):
Java代碼
public? ?boolean??onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {??
…??
? ? } else? ?if??(preference == mAccelerometer) {??
? ?? ?? ?? ?Settings.System.putInt(getContentResolver(),??
? ?? ?? ?? ?? ?? ???Settings.System.ACCELEROMETER_ROTATION,??
? ?? ?? ?? ?? ?? ???mAccelerometer.isChecked() ? 1??:??0 );??
…??
? ?? ???}?? 復(fù)制代碼
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {??
…??
? ? } else if (preference == mAccelerometer) {??
? ?? ?? ?? ?Settings.System.putInt(getContentResolver(),??
? ?? ?? ?? ?? ?? ???Settings.System.ACCELEROMETER_ROTATION,??
? ?? ?? ?? ?? ?? ???mAccelerometer.isChecked() ? 1 : 0);??
…??
? ?? ???}?? 復(fù)制代碼
文件 frameworks/policies/base/phone/com/android/internal/policy/impl/PhoneWindowManager.java中的 SettingsServer會(huì)隨時(shí)監(jiān)控其值,對(duì)用戶設(shè)置做出反應(yīng):
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();??
? ?? ?? ?? ?? ? }??
…??
}?? 復(fù)制代碼
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();??
? ?? ?? ?? ?? ? }??
…??
}?? 復(fù)制代碼
上述是設(shè)置生效流程。當(dāng) Orientation設(shè)置 Enable時(shí),會(huì)發(fā)生什么呢?
在 PhoneWindowManager.java有個(gè) Listener,它會(huì)根據(jù) Sensor判別出的旋轉(zhuǎn)方向,調(diào)用 WindowManager.setRotation讓屏幕進(jìn)行旋轉(zhuǎn)。另外,當(dāng)應(yīng)用程序顯示禁止屏幕旋轉(zhuǎn)時(shí)則不會(huì)旋轉(zhuǎn),見函數(shù) 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 ;??
??} 復(fù)制代碼
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;??
??}?? 復(fù)制代碼
在 WindowOrientationListener(見文件 javaframeworks/base/core/java/android/view/WindowOrientationListener.java)中會(huì)監(jiān)聽Sensor的值,對(duì)旋轉(zhuǎn)方向進(jìn)行判斷,然后調(diào)用抽象方法 onOrientationChanged,因此,只要在子類 Listener中重新實(shí)現(xiàn)這個(gè)函數(shù)即可對(duì)四個(gè)不同方向做出響應(yīng)(見上面讓屏幕旋轉(zhuǎn)即是一例)。
遺憾的是在 Donut和 éclair中,對(duì)旋轉(zhuǎn)方向的識(shí)別只給出了 90度旋轉(zhuǎn),在 Froyo中增加了一個(gè) 270度旋轉(zhuǎn),不支持 180度即倒立的操作。
可以在修改下面代碼,判斷來(lái)自于 Gsensor的值,識(shí)別出旋轉(zhuǎn)方向:
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);??
? ?? ???}??
? ? }??
}?? 復(fù)制代碼
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);??
? ?? ???}??
? ? }??
}?? 復(fù)制代碼
在Froyo中,對(duì)上述算法進(jìn)行了修改,讓其報(bào)出270度的旋轉(zhuǎn)方向。
Android Sensor 屏幕360度旋轉(zhuǎn)實(shí)現(xiàn)
修改下面函數(shù)
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);
? ?? ?? ?? ?? ???//確定由角度與屏幕方向的對(duì)應(yīng)范圍
? ?? ?? ?? ?? ? 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);
? ?? ?? ?? ?? ? }
? ?? ?? ?? ?} 復(fù)制代碼
總結(jié)
以上是生活随笔為你收集整理的利用GSensor让屏幕实现360度旋转的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。