天天看点

关于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

继续阅读