1.问题背景
从google原生算法,可以知道其有2个比较大的缺陷:
1) 通过重力传感器传来的x,y,z轴的加速度合成之后只有一个垂直往下的加速度,如果此时用户在别的方向上有加速度,那么通过反余弦、反正切等计算的角度就会不准确,原始的角度计算有问题,就谈不上识别正确的方向了。而google在旋转角度上,并未用代码进行修正。
2) google拿到方向信息之后,去干扰采取的措施是延迟300-500ms,等彻底没有干扰的时候再进行方向改变,这个方案很保守。由于普通用户正常转屏都会触发抖动和加速(70%左右都会触发),这样就会导致,就算是旋转角度计算没有任何问题,也会由于算法导致300-500ms的延迟。
2.优化措施
1.1采集数据时,提高采样灵敏度
private final float FILTER_TIME_CONSTANT_MS = tcl.Features.has("PERF_ROTATION") ? 70.0f : 200.0f;
//两次事件间隔,单位是ms,一般默认SENSOR_DELAY_NORMAL时,gsensor上报数据是66.666ms左右
final float timeDeltaMS = (now - then) * 0.000001f;
final float alpha = timeDeltaMS / (FILTER_TIME_CONSTANT_MS + timeDeltaMS);
x = alpha * (x - mLastFilteredX) + mLastFilteredX;
y = alpha * (y - mLastFilteredY) + mLastFilteredY;
z = alpha * (z - mLastFilteredZ) + mLastFilteredZ;
原生FILTER_TIME_CONSTANT_MS为200ms,alpha约为0.25,即xyz的渐变速率是0.25。TCL的渐变速率约为0.49。即TCL计算得到的角度更大,猜测会会导致方向预测更加灵敏。
1.2获取预测角度时,提高更新频率
tclWindowOrientation.updateTimestamp(orientationAngle, tiltAngle, nearestRotation, mCurrentRotation,
PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS, PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS,
now, mSwingTimestampNanos, mAccelerationTimestampNanos, mPredictedRotation,
mPredictedRotationTimestampNanos);
mSwingTimestampNanos = tclWindowOrientation.getSwingTimestampNanos();
mAccelerationTimestampNanos = tclWindowOrientation.getAccelerationTimestampNanos();
原生:摆动的更新频率是300ms,加速度的更新频率是500ms
private static final long PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS = 300 * NANOS_PER_MS;
if (now < mSwingTimestampNanos + PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS) {
return false;
}
private static final long PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS = 500 * NANOS_PER_MS;
if (now < mAccelerationTimestampNanos + PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS) {
return false;
}
TCL:摆动的更新频率是200ms,加速度的更新频率是400ms,减少了100ms的延迟
long PROPOSAL_MIN_TIME_ENDED_NANOS = 100 * NANOS_PER_MS;
//简化后
if (now < mSwingTimestampNanos + PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS-PROPOSAL_MIN_TIME_ENDED_NANOS) {
swingNanos = now - minTimeSinceSwing + PROPOSAL_MIN_TIME_ENDED_NANOS;
accelerationNanos = now - minTimeSinceAcceleration + PROPOSAL_MIN_TIME_ENDED_NANOS;
isSwingTimeChange = false;
isAccelerationTimeChange = false;
1.3预测角度归一时,提高采样范围
private final int ADJACENT_ORIENTATION_ANGLE_GAP = tcl.Features.has("PERF_ROTATION") ? 30 : 45;
以逆时针相邻为例
//0-360度减去22.5度,即(0,1,2,3)-->(-22.5,67.5,157.5,247.5)
int lowerBound = rotation * 90 - 45 + ADJACENT_ORIENTATION_ANGLE_GAP / 2;
//0(竖直向上):(315,360)缩短(337.5,360)
if (rotation == 0) { if (orientationAngle >= 315 && orientationAngle < lowerBound + 360) { return false; } }
//其他范围边际缩小22.5度 ,
else { if (orientationAngle < lowerBound) { return false; } }
原生:
//0-360度减去22.5度,即(0,1,2,3)-->(-22.5,67.5,157.5,247.5)
0-->(0,45)&(337.5,360),1-->(67.5,135),2-->(157.5,225),3→(247.5,315)
TCL:多减去7.5度,扩大了采样范围
//0-360度减去30度,即(0,1,2,3)-->(30,60,150,250)
0→(0,45)&(330,360),1→(60,135),2→(150,225),3→(240,315)
1.4通知监听更新时,增加加速度判断
原生:通过重力传感器传来的x,y,z轴的加速度合成之后只有一个垂直往下的加速度,如果此时用户在别的方向上有加速度,那么通过反余弦、反正切等计算的角度就会不准确,导致最终计算的方向不准。
TCL:
final float magnitudeData = (float) Math.sqrt(x * x + y * y + z * z);
if (isTiltAngleAcceptableLocked(nearestRotation, tiltAngle)
&& (isOrientationAngleAcceptableLocked(nearestRotation, orientationAngle) || (tclWindowOrientation != null && tclWindowOrientation.isRotating()))
&& (tclWindowOrientation == null || magnitudeData < MAX_ACCELERATION_MAGNITUDE) //判断计算的加速度小于可容忍的最大加速度
)
3.方案介绍
3.1流程图
参考原生屏幕旋转算法(AccelSensor) - 终端OS部 - Confluence (tclking.com) 中的流程图
3.2代码提交
topic:JIRA-SOC15MT6835-19536 | sz.gerrit Code Review (tclcom.com)
4.调试自测
1)查看sensor类型
Goldfinch_TMO:/ # dumpsys window|grep Sensor
AccelSensorJudge
2)自测用例