一
概述
frameworks\base\core\java\android\view\WindowOrientationListener.java |
监听sensor是否有数据变化 |
首先看看芯片方向(x,y,z):
补充流程:
PhoneWindowManager调用updateOrientationListenerLp去SensorManager里面去注册一个Listener,
当Sensor发生变化的时候,PhoneWindowManager就可以监听到并且调用回调onProposeRotationChanged。
Callback
如下:
1
MyOrientationListener.onProposeRotationChange
PhoneWindowManager.java
-------------》
class MyOrientationListener extends
WindowOrientationListener {
@Override
public void
onProposedRotationChanged(introtation) {
if (localLOGV) Log.v(TAG,"onProposedRotationChanged, rotation=" + rotation);
updateRotation(false);
}
}
--------》
2. PhoneWindowManager.updateRotation(booleanalwaysSendConfiguration)
void
updateRotation(booleanalwaysSendConfiguration) {
try {
//set orientation on WindowManager
mWindowManager.updateRotation(alwaysSendConfiguration, false);、、WindowManagerService的对象
} catch (RemoteException e) {
// Ignore
}
}
3. WindowManagerService.updateRotation(booleanalwaysSendConfiguration, boolean forceRelayout)
二代码分析
public void
onSensorChanged(SensorEvent event) {
// The vector given in theSensorEvent points straight up (towards the sky) under ideal
// conditions (the phone is notaccelerating). I‘ll call this up vectorelsewhere.
float x =event.values[ACCELEROMETER_DATA_X];
float y =event.values[ACCELEROMETER_DATA_Y];
float z =event.values[ACCELEROMETER_DATA_Z];
if (LOG) {
Slog.v(TAG, "Rawacceleration vector: "
+ "x=" + x +", y=" + y + ", z=" + z
+ ",magnitude=" + FloatMath.sqrt(x * x + y * y + z * z));
}
// Apply a low-pass filter to theacceleration up vector in cartesian space.
// Reset the orientation listenerstate if the samples are too far apart in time
// or when we see values of (0, 0,0) which indicates that we polled the
// accelerometer too soon afterturning it on and we don‘t have any data yet.
final long now = event.timestamp;
final long then =mLastFilteredTimestampNanos;
final float timeDeltaMS = (now -then) * 0.000001f;
final boolean skipSample;
if (now < then
|| now > then +MAX_FILTER_DELTA_TIME_NANOS
|| (x == 0 && y ==0 && z == 0)) {
if (LOG) {
Slog.v(TAG, "Resettingorientation listener.");
}
reset();
skipSample = true;
} else {
final float alpha = timeDeltaMS/ (FILTER_TIME_CONSTANT_MS + timeDeltaMS);
x = alpha * (x -mLastFilteredX) + mLastFilteredX;
y = alpha * (y -mLastFilteredY) + mLastFilteredY;
z = alpha * (z -mLastFilteredZ) + mLastFilteredZ;
if (LOG) {
Slog.v(TAG, "Filteredacceleration vector: "
+ "x=" +x + ", y=" + y + ", z=" + z
+ ",magnitude=" + FloatMath.sqrt(x * x + y * y + z * z));
}
skipSample = false;
}
mLastFilteredTimestampNanos = now;
mLastFilteredX = x;
mLastFilteredY = y;
mLastFilteredZ = z;
boolean isAccelerating = false;
boolean isFlat = false;
boolean isSwinging = false;
if (!skipSample) {
// Calculate the magnitude ofthe acceleration vector.
final float magnitude =FloatMath.sqrt(x * x + y * y + z * z);
if (magnitude <NEAR_ZERO_MAGNITUDE) {
if (LOG) {
Slog.v(TAG,"Ignoring sensor data, magnitude too close to zero.");
}
clearPredictedRotation();
} else {
// Determine whether thedevice appears to be undergoing external acceleration.
if(isAccelerating(magnitude)) {
isAccelerating = true;
mAccelerationTimestampNanos = now;
}
// Calculate the tiltangle.
// This is the anglebetween the up vector and the x-y plane (the plane of
// the screen) in a rangeof [-90, 90] degrees.
// -90 degrees: screen horizontal and facingthe ground (overhead)
// 0 degrees: screen vertical
// 90 degrees: screen horizontal and facingthe sky (on table)
final int
tiltAngle = (int) Math.round(//关键数据1:tiltAngle
计算出传感器的倾斜角
Math.asin(z /magnitude) * RADIANS_TO_DEGREES);
addTiltHistoryEntry(now,
tiltAngle);
// Determine whether thedevice appears to be flat or swinging.
if (isFlat(now)) {
isFlat = true;
mFlatTimestampNanos =now;
}
if (isSwinging(now,tiltAngle)) {
isSwinging = true;
mSwingTimestampNanos =now;
}
// If the tilt angle is tooclose to horizontal then we cannot determine
// the orientation angle ofthe screen.
if (Math.abs(tiltAngle)> MAX_TILT) {
if (LOG) {
Slog.v(TAG,"Ignoring sensor data, tilt angle too high: "
+"tiltAngle=" + tiltAngle);
}
clearPredictedRotation();
} else {
// Calculate theorientation angle.
// This is the anglebetween the x-y projection of the up vector onto
// the +y-axis,increasing clockwise in a range of [0, 360] degrees.
int
orientationAngle = (int) Math.round(//关键数据2:计算出方向
角度
-Math.atan2(-x,y) * RADIANS_TO_DEGREES);
if (orientationAngle < 0) {
// atan2 returns[-180, 180]; normalize to [0, 360]
orientationAngle +=360;
}
// Find the nearestrotation.
int
nearestRotation = (orientationAngle+ 45) / 90;
//关键数据3:计算出要旋转的方向;也就是说orientationAngle
需要大于45,
才会找到一个方向(共四个方向:0,1,2,3)
if (nearestRotation ==4) {
nearestRotation =0;
}
// Determine the predicted orientation.
判断预报的方向:mPredictedRotation是否合理
if (isTiltAngleAcceptable(nearestRotation,tiltAngle)
&&
isOrientationAngleAcceptable(nearestRotation,
orientationAngle)) {
updatePredictedRotation(now, nearestRotation);
if (LOG) {
Slog.v(TAG,"Predicted: "
+"tiltAngle=" + tiltAngle
+", orientationAngle=" + orientationAngle
+", predictedRotation=" + mPredictedRotation
+", predictedRotationAgeMS="
+ ((now - mPredictedRotationTimestampNanos)
* 0.000001f));
}
} else{////所以做好不要进入
无效数据范围
if (LOG) {
Slog.v(TAG,"Ignoring sensor data, no predicted rotation: "
+"tiltAngle=" + tiltAngle
+", orientationAngle=" + orientationAngle);
}
clearPredictedRotation();
}
}
}
}
// Determine new proposedrotation.判断新的建议的方向:mProposedRotation
是否合理
final int oldProposedRotation =
mProposedRotation;
if (mPredictedRotation < 0 ||
isPredictedRotationAcceptable(now)) {
mProposedRotation = mPredictedRotation;//关键数:4:新的建议方向等于预报方向。
}
// Write final statistics aboutwhere we are in the orientation detection process.
if (LOG) {
Slog.v(TAG, "Result: currentRotation=" +mOrientationListener.mCurrentRotation
+ ",proposedRotation=" + mProposedRotation
+ ",predictedRotation=" + mPredictedRotation
+ ",timeDeltaMS=" + timeDeltaMS
+ ",isAccelerating=" + isAccelerating
+ ", isFlat="+ isFlat
+ ",isSwinging=" + isSwinging
+ ",timeUntilSettledMS=" + remainingMS(now,
mPredictedRotationTimestampNanos + PROPOSAL_SETTLE_TIME_NANOS)
+ ",timeUntilAccelerationDelayExpiredMS=" + remainingMS(now,
mAccelerationTimestampNanos +PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS)
+ ",timeUntilFlatDelayExpiredMS=" + remainingMS(now,
mFlatTimestampNanos + PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS)
+ ",timeUntilSwingDelayExpiredMS=" + remainingMS(now,
mSwingTimestampNanos + PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS));
}
// Tell the listener.
if (mProposedRotation!= oldProposedRotation &&
mProposedRotation>= 0) {
if (LOG) {
Slog.v(TAG, "Proposedrotation changed! proposedRotation=" + mProposedRotation
+ ",oldProposedRotation=" + oldProposedRotation);
}
mOrientationListener.onProposedRotationChanged(mProposedRotation);
/*通知windoweservice去更新rotation*/
}
}
2.1
mOrientationListener.onProposedRotationChanged(mProposedRotation);
MyOrientationListener.onProposeRotationChange
----------在
PhoneWindowManager.java
class MyOrientationListener extendsWindowOrientationListener {
@Override
public void
onProposedRotationChanged(introtation) {
if (localLOGV) Log.v(TAG,"onProposedRotationChanged, rotation=" + rotation);
updateRotation(false);
}
}
三
关键结构:
1. private static finalint[][]TILT_TOLERANCE
= new int[][]{
参数含义:{旋转方向(0,90,180,270), 倾斜角}
/* ROTATION_0 */ { -25, 70 },
/* ROTATION_90 */ { -25, 65 },
/* ROTATION_180 */ { -25, 60 },
/* ROTATION_270 */ { -25, 65 }
};
也就是tiltAngle在各个倾斜角的范围;
2.这里有两个关键的方向:
原来方向oldProposedRotation
等于
mProposedRotation
预报方向mPredictedRotation
等于
nearestRotation
建议方向
mProposedRotation
如果条件满足等于
mPredictedRotation
3.总的来说是否更新rotation到listenser
需要如下的条件(从Tell the listener往前推理)优化如下几个条件:
条件1):(mProposedRotation
!= oldProposedRotation &&
mProposedRotation >= 0)
条件2):新的预报方向
是否可以作为
建议方向的条件是:if (mPredictedRotation < 0
|| isPredictedRotationAcceptable(now))
其中两个
isPredictedRotationAcceptable():是判断预报方向的在某时间内是否稳定;//可以缩短其时间
提高灵敏度
mPredictedRotation
<0 : 说明tiltAngle和orientationAngle
都不在合理的范围内
条件3):所以tiltAngle和orientationAngle
不要进入
无效数据范围。可以调整TILT_TOLERANCE和ADJACENT_ORIENTATION_ANGLE_GAP
齿槽角(目前是45度)
isOrientationAngleAcceptable()//该函数会判断相邻方向之间的齿槽角差距
Case 1:
// For example, if currentRotation is ROTATION_0(则rotation=0) and
proposed is ROTATION_90(则rotation=1),
// then we want tocheck
orientationAngle > 45 + GAP / 2.也就是最低的方向角下限
if (currentRotation>= 0) {
// If the specified rotation isthe same or is counter-clockwise adjacent
// to the current rotation,then we set a lower bound on the orientation angle.
// For example, ifcurrentRotation is ROTATION_0 and proposed is ROTATION_90,
// then we want to checkorientationAngle > 45 + GAP / 2.
if (rotation == currentRotation
|| rotation ==(currentRotation + 1) % 4) {
int lowerBound = rotation * 90 - 45+ADJACENT_ORIENTATION_ANGLE_GAP / 2; //lowerBound
:最低下限
if (rotation == 0) {
if (orientationAngle>= 315 && orientationAngle < lowerBound + 360) {
return false;
}
} else {
if (orientationAngle< lowerBound) {
return false;
}
}
}
所以说ADJACENT_ORIENTATION_ANGLE_GAP
越大,lowerBound 就越大,orientationAngle
就会越容易满足条件,
Case 2:
//If the specified rotation is the same or is clockwise adjacent,
// then we set an upper boundon the orientation angle.
// For example, ifcurrentRotation is ROTATION_0 and rotation is ROTATION_270(则rotation=3)
,
// then we want to checkorientationAngle < 315 - GAP / 2.
if (rotation == currentRotation
|| rotation ==(currentRotation + 3) % 4) {
int
upperBound = rotation * 90 + 45-
ADJACENT_ORIENTATION_ANGLE_GAP/ 2;
if (rotation == 0) {
if (orientationAngle<= 45 && orientationAngle > upperBound) {
return false;
}
} else {
if (orientationAngle> upperBound) {
return false;
}
}
}
所以说ADJACENT_ORIENTATION_ANGLE_GAP
越小,upperBound
就越大,orientationAngle就会越容易满足条件,
条件4):nearestRotation
要发生变化
条件5):以调整转屏角度及转屏加速度delay方面的设置来达到些许优化转屏速度的目的
在函数:private boolean isPredictedRotationAcceptable(long now){}里面的时间
四 FAQ
1.客户有如下需求:
需校正重力感应角度,將機器放於桌面,用手托住機器一側,慢慢向上抬起,當機器後殼與桌面夾角角度達到45度時,畫面應能出現旋轉(四個方向都必須是到達45度角後才能旋轉)
--------》
改变屏幕旋转的角度,可以修改frameworks/base/core/java/android/view/WindowOrientationListener.java中的MAX_TILT或者TILT_TOLERANCE
但是这样修改之后的影响不确定。