关于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(
0
, rotation);
if
(mDisplayEnabled) {
//Surface.setOrientation()这里将进行调整Orientation
Surface.setOrientation(
0
, rotation, animFlags);
}
for
(
int
i=mWindows.size()-
1
; i>=
0
; i--) {
WindowState w = mWindows.get(i);
if
(w.mSurface !=
null
) {
w.mOrientationChanging =
true
;
}
}
for
(
int
i=mRotationWatchers.size()-
1
; i>=
0
; 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 <
0
) {
// 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.
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 >
0
) {
alpha = ACCELERATING_LOWPASS_ALPHA;
}
float
newTiltAngle = tiltAngle(z, magnitude);
mTiltAngle = lowpassFilter(newTiltAngle, mTiltAngle, alpha);
float
absoluteTilt = Math.abs(mTiltAngle);
checkFullyTilted(absoluteTilt);
if
(mTiltDistrust >
0
) {
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
|
private
static
final
int
[][][] THRESHOLDS =
new
int
[][][] {
{{
60
,
180
}, {
180
,
300
}},
{{
0
,
30
}, {
195
,
315
}, {
315
,
360
}},
{{
0
,
45
}, {
45
,
165
}, {
330
,
360
}},
// Handle situation where we are currently doing 180 rotation
// but that is no longer allowed.
{{
0
,
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
}},
{{
0
,
30
}, {
165
,
195
}, {
195
,
315
}, {
315
,
360
}},
{{
0
,
45
}, {
45
,
165
}, {
165
,
195
}, {
330
,
360
}},
{{
0
,
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 =
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 =
0
; i < thresholdRanges.length; i++) {
if
(orientation >= thresholdRanges[i][
0
] && 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
---------------------------------------------------------------------------