天天看點

關于android2.3調試g-sensor

由于工作上的需要,特地寫了這麼一份關于調試g-sensor的内容.

1.首先确定你要調試的裝置的螢幕的橫豎屏如何設定。

在代碼中我們主要的流程如下:

os 啟動後 :

WindowManagerService.java中ENABLE_SCREEN

–>performEnableScreen()

–>mPolicy.enableScreenAfterBoot()/setRotation()

–>setRotationUnchecked()

–>PhoneWindowManager.java中的rotationForOrientationLw()

–>Surface.setOrientation()

基本上流程就是如上,隻要稍微跟蹤一下就可以了。

下面大概對上面主要code進行注釋說明:

?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55

//下面的方法主要用于判斷螢幕是否需要進行一個新的旋轉

public

boolean

setRotationUncheckedLocked(

int

rotation, 

int

animFlags) {

boolean

changed;

//rotation從外面傳入目前的rotation以及animFlags 最後的标簽

//如果rotation等于系統第一次啟動則rotation指派為mRequestedRotation此時為0

if

(rotation == WindowManagerPolicy.USE_LAST_ROTATION) {

rotation = mRequestedRotation;

}

else

{

mRequestedRotation = rotation;

mLastRotationFlags = animFlags;

}

if

(DEBUG_ORIENTATION) Slog.v(TAG, 

"Overwriting rotation value from "

+ rotation);

//此時的rotation為老的rotation,下面通過mPolicy.rotationForOrientationLw()進行擷取新的rotation

rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation,

mRotation, mDisplayEnabled);

if

(DEBUG_ORIENTATION) Slog.v(TAG, 

"new rotation is set to "

+ rotation);

changed = mDisplayEnabled && mRotation != rotation;

//如果擷取新的rotation與舊的rotation一樣則不做改變

//否則進入下面函數進行調整

if

(changed) {

if

(DEBUG_ORIENTATION) Slog.v(TAG,

"Rotation changed to "

+ rotation

+

" from "

+ mRotation

+

" (forceApp="

+ mForcedAppOrientation

+

", req="

+ mRequestedRotation +

")"

);

mRotation = rotation;

mWindowsFreezingScreen =

true

;

mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);

mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT),

2000

);

mWaitingForConfig =

true

;

mLayoutNeeded =

true

;

startFreezingDisplayLocked();

Slog.i(TAG,

"Setting rotation to "

+ rotation + 

", animFlags="

+ animFlags);

mInputManager.setDisplayOrientation(

, rotation);

if

(mDisplayEnabled) {

//Surface.setOrientation()這裡将進行調整Orientation

Surface.setOrientation(

, rotation, animFlags);

}

for

(

int

i=mWindows.size()-

1

; i>=

; i--) {

WindowState w = mWindows.get(i);

if

(w.mSurface != 

null

) {

w.mOrientationChanging =

true

;

}

}

for

(

int

i=mRotationWatchers.size()-

1

; i>=

; i--) {

try

{

mRotationWatchers.get(i).onRotationChanged(rotation);

}

catch

(RemoteException e) {

}

}

}

//end if changed

return

changed;

}

下面在對rotationForOrientationLw()進行解析一下:

在setRotationUncheckedLocked()中的 mPolicy.rotationForOrientationLw()如是:

?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

public

int

rotationForOrientationLw(

int

orientation, 

int

lastRotation,

boolean

displayEnabled) {

if

(mPortraitRotation < 

) {

// Initialize the rotation angles for each orientation once.

Display d = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))

.getDefaultDisplay();

//這裡的d.getWidth() 和 d.getHeight()得到的是實體螢幕的寬高。

//平闆跟手機不一樣。平闆的寬比高大

//(0度時位于//landscape模式,右轉90度進入porit模式),

//而手機是高比寬大(0度是位于porit模式,右轉90度進入landscape模式)。

//是以下面我做的是對平闆的修改

if

(d.getWidth() > d.getHeight()) {

//mPortraitRotation = Surface.ROTATION_90;

mPortraitRotation = Surface.ROTATION_270;

mLandscapeRotation = Surface.ROTATION_0;

//mUpsideDownRotation = Surface.ROTATION_270;

mUpsideDownRotation = Surface.ROTATION_90;

mSeascapeRotation = Surface.ROTATION_180;

}

else

{

mPortraitRotation = Surface.ROTATION_0;

//mLandscapeRotation = Surface.ROTATION_90;

mLandscapeRotation = Surface.ROTATION_270;

mUpsideDownRotation = Surface.ROTATION_180;

//mSeascapeRotation = Surface.ROTATION_270;

mSeascapeRotation = Surface.ROTATION_90;

}

}

......

}

2.如果g-sensor在旋轉上有不旋轉的方向或者方向不是很靈敏,則我們從下面進行分析:

主要流程如下:

–>WindowOrientationListener.java中的onSensorChanged()

–>computeNewOrientation()

–>filterOrientation()

–>calculateNewRotation()

calculateNewRotation()

–>mOrientationListener.onOrientationChanged()

PhoneWindowManager.java 中的onOrientationChanged()

–>mWindowManager.setRotation()

首先在android中的x,y,z定義如下摘自http://developer.android.com/reference/android/hardware/SensorEvent.html :

Class Overview

This class represents a Sensor event and holds informations such as the sensor’s type, the time-stamp, accuracy and of course the sensor’s data.

Definition of the coordinate system used by the SensorEvent API.

The coordinate-system is defined relative to the screen of the phone in its default orientation. The axes are not swapped when the device’s screen orientation changes.

The X axis is horizontal and points to the right, the Y axis is vertical and points up and the Z axis points towards the outside of the front face of the screen. In this system, coordinates behind the screen have negative Z values.

Sensors coordinate-system diagram.

關于android2.3調試g-sensor

Note: This coordinate system is different from the one used in the Android 2D APIs where the origin is in the top-left corner.

frameworks/base/core/java/android/view/WindowOrientationListener.java

WindowOrientationListener.java 是一個abstract class,它主要是把從gsensor擷取到的資料轉化為orientation.

每次sensor有進行改變時都會調用到以下函數進行計算Orientation。

?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38

public

void

onSensorChanged(SensorEvent event) {

// the vector given in the SensorEvent points straight up (towards the sky) under ideal

// conditions (the phone is not accelerating).  i'll call this upVector elsewhere.

float

x = event.values[_DATA_X];

float

y = event.values[_DATA_Y];

float

z = event.values[_DATA_Z];

float

magnitude = vectorMagnitude(x, y, z);

float

deviation = Math.abs(magnitude - SensorManager.STANDARD_GRAVITY);

handleAccelerationDistrust(deviation);

// only filter tilt when we're accelerating

float

alpha = 

1

;

if

(mAccelerationDistrust > 

) {

alpha = ACCELERATING_LOWPASS_ALPHA;

}

float

newTiltAngle = tiltAngle(z, magnitude);

mTiltAngle = lowpassFilter(newTiltAngle, mTiltAngle, alpha);

float

absoluteTilt = Math.abs(mTiltAngle);

checkFullyTilted(absoluteTilt);

if

(mTiltDistrust > 

) {

return

;

// when fully tilted, ignore orientation entirely

}

//下面通過x,y計算得到新的OrientationAngle,計算方法如下

//        private float computeNewOrientation(float x, float y) {

//           float orientationAngle = (float) -Math.atan2(-x, y) * RADIANS_TO_DEGREES;

// atan2 returns [-180, 180]; normalize to [0, 360]

//            if (orientationAngle < 0) {

//               orientationAngle += 360;

//            }

//            return orientationAngle;

//        }

float

newOrientationAngle = computeNewOrientation(x, y);

//通過下面函數計算出Orientation的值。

filterOrientation(absoluteTilt, newOrientationAngle);

calculateNewRotation(mOrientationAngle, absoluteTilt);

}

這裡對calculateNewRotation進行分析前必須先對SensorEventListenerImpl類中的一些變量先進行解釋:

?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60

private

static

final

int

[][][] THRESHOLDS = 

new

int

[][][] {

{{

60

,

180

}, {

180

,

300

}},

{{

,

30

}, {

195

,

315

}, {

315

,

360

}},

{{

,

45

}, {

45

,

165

}, {

330

,

360

}},

// Handle situation where we are currently doing 180 rotation

// but that is no longer allowed.

{{

,

45

}, {

45

,

135

}, {

135

,

225

}, {

225

,

315

}, {

315

,

360

}},

};

// See THRESHOLDS

private

static

final

int

[][] ROTATE_TO = 

new

int

[][] {

{ROTATION_90, ROTATION_270},

{ROTATION_0, ROTATION_270, ROTATION_0},

{ROTATION_0, ROTATION_90, ROTATION_0},

{ROTATION_0, ROTATION_90, ROTATION_0, ROTATION_270, ROTATION_0},

};

private

static

final

int

[][][] THRESHOLDS_WITH_180 = 

new

int

[][][] {

{{

60

,

165

}, {

165

,

195

}, {

195

,

300

}},

{{

,

30

}, {

165

,

195

}, {

195

,

315

}, {

315

,

360

}},

{{

,

45

}, {

45

,

165

}, {

165

,

195

}, {

330

,

360

}},

{{

,

45

}, {

45

,

135

}, {

225

,

315

}, {

315

,

360

}},

};

private

static

final

int

[][] ROTATE_TO_WITH_180 = 

new

int

[][] {

{ROTATION_90, ROTATION_180, ROTATION_270},

{ROTATION_0, ROTATION_180, ROTATION_90, ROTATION_0},

{ROTATION_0, ROTATION_270, ROTATION_180, ROTATION_0},

{ROTATION_0, ROTATION_90, ROTATION_270, ROTATION_0},

};

//當裝置平放,螢幕朝正上方。以下四個常量分别代表:

private

static

final

int

ROTATION_0 = 

;

//初始情況。橫/豎屏與一開始設定有關

private

static

final

int

ROTATION_90 = 

1

;

//右側翻起側立時,螢幕會旋轉到這個方向。

private

static

final

int

ROTATION_270 = 

2

;

//左側翻起度側立時,螢幕會旋轉到這個方向。

private

static

final

int

ROTATION_180 = 

3

;

//螢幕底部側立時,螢幕會旋轉到這個方向

//如上則

// {ROTATION_90, ROTATION_180, ROTATION_270}

//對應落在的範圍為 {{60, 165}, {165, 195}, {195, 300}}

//{ROTATION_0, ROTATION_180, ROTATION_90, ROTATION_0}

//對應落在的範圍為 {{0, 30}, {165, 195}, {195, 315}, {315, 360}}

//{ROTATION_0, ROTATION_270, ROTATION_180, ROTATION_0}

//對應落在的範圍為 {{0, 45}, {45, 165}, {165, 195}, {330, 360}}

//{ROTATION_0, ROTATION_90, ROTATION_270, ROTATION_0}

//對應落在的範圍為{{0, 45}, {45, 135}, {225, 315}, {315, 360}}

//是以如果需要微調的話隻要修改對應的範圍既可

//目前螢幕旋轉方向為ROTATION_0時,取int[][] threshold=THRESHOLDS_WITH_180[0];

//此時的範圍為:{{60, 165}, {165, 195}, {195, 300}}

//目前螢幕旋轉方向為ROTATION_90時,取int[][] threshold=THRESHOLDS_WITH_180[1];

//此時的範圍為:{{0, 30}, {165, 195}, {195, 315}, {315, 360}}

//目前螢幕旋轉方向為ROTATION_270時,取int[][] threshold=THRESHOLDS_WITH_180[2];

//此時的範圍為:{{0, 45}, {45, 165}, {165, 195}, {330, 360}}

//目前螢幕旋轉方向為ROTATION_180時,取int[][] threshold=THRESHOLDS_WITH_180[3];

//此時的範圍為:{{0, 45}, {45, 135}, {225, 315}, {315, 360}}

//例如目前我們的位置為ROTATION_90那麼此時我們的THRESHOLDS_WITH_180就

//為{{0, 30}, {165, 195}, {195, 315}, {315, 360}}

//,然後通過filterOrientation計算出的orientation值落在了第2個元素圍内,則到ROTATE_TO_WITH_180找到對應的值,

//這裡為ROTATION_180,則此時把方向選裝到ROTATION_180

對上面的變量稍微了解後對下面的分析就很簡單了。

?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

private

void

calculateNewRotation(

float

orientation, 

float

tiltAngle) {

//這裡的orientation,tiltAngle,mRotation為gsensor擷取到的最新的資料

if

(localLOGV) Log.i(TAG, orientation + 

", "

+ tiltAngle + 

", "

+ mRotation);

//是否允許180度旋轉,這裡定義的其實就是變成了360度旋轉了,

//如果mAllow180Rotation為false時,上面的變量中使用的為THRESHOLDS以及ROTATE_TO

//如果為ture則為THRESHOLDS_WITH_180與ROTATE_TO_WITH_180

final

boolean

allow180Rotation = mAllow180Rotation;

int

thresholdRanges[][] = allow180Rotation

? THRESHOLDS_WITH_180[mRotation] : THRESHOLDS[mRotation];

int

row = -

1

;

for

(

int

i = 

; i < thresholdRanges.length; i++) {

if

(orientation >= thresholdRanges[i][

] && orientation < thresholdRanges[i][

1

]) {

row = i;

break

;

}

}

if

(row == -

1

)

return

// no matching transition

int

rotation = allow180Rotation

? ROTATE_TO_WITH_180[mRotation][row] : ROTATE_TO[mRotation][row];

if

(tiltAngle > MAX_TRANSITION_TILT[rotation]) {

// tilted too far flat to go to this rotation

return

;

}

if

(localLOGV) Log.i(TAG, 

"orientation "

+ orientation + 

" gives new rotation = "

+ rotation);

mRotation = rotation;

//這裡通過WindowOrientationListener監聽調用onOrientationChanged中的setRotation進而旋轉界面

mOrientationListener.onOrientationChanged(INTERNAL_TO_SURFACE_ROTATION[mRotation]);

}

onOrientationChanged()的實作在PhoneWindowManager.java 中,如下:

?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

class

MyOrientationListener 

extends

WindowOrientationListener {

MyOrientationListener(Context context) {

super

(context);

}

@Override

public

void

onOrientationChanged(

int

rotation) {

// Send updates based on orientation value

if

(localLOGV) Log.v(TAG, 

"onOrientationChanged, rotation changed to "

+rotation);

try

{

mWindowManager.setRotation(rotation,

false

,

mFancyRotationAnimation);

SystemProperties.set(

"service.screen.rotation"

,

""

+rotation);

}

catch

(RemoteException e) {

// Ignore

}

}

}

基本上整個流程到此結束。

轉載時請注明出處和作者

文章出處:http://www.code007.org/

作者:Code007

繼續閱讀