生活随笔
收集整理的這篇文章主要介紹了
利用GSensor让屏幕实现360度旋转
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
在 Android的 Settings->Sound and Display中有 Orientation這一設置項。當選中時,反轉手機,手機屏幕會隨之旋轉,一般只可以旋轉90度。
這一 settings設置是在文件 SoundAndDisplaySettings.java中,該項對應的鍵字符串為:
private? ?static? ?final??String KEY_ACCELEROMETER =??"accelerometer" ;?? 復制代碼
Java代碼
private static final String KEY_ACCELEROMETER = "accelerometer"; 復制代碼
其默認值保存在 xml文件中,默認是 Enable。 UI程序初始化時會根據其值是否在復選框中打勾(代碼在 onCreate函數中):
? ?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);??
…??
}?? 復制代碼
當用戶改變了該值時,會保存起來:
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度旋转的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。