作者:声网Agora 工程师 黄龙飞
在日常生活中使用手机,通常都会遇到下面这两种场景。 场景一: 当使用手机观看视频,设备打开屏幕自动旋转时,手机水平和垂直,效果会有所不同。垂直屏幕状态下的显示如下图所示(图1),水平屏幕状态下的显示如图2所示。
图1.垂直屏幕播放视频
图2.横屏播放视频
场景二: 在使用的手机应用程序中,一些应用程序的某些界面将根据当前手机水平和垂直屏幕的状态显示不同的界面效果,以方便每个人使用。AgoraVideoCall会议界面如图3所示 & 图4所示:
图3.AgoraVideoCall垂直显示会议界面
图4.AgoraVideoCall横屏显示会议界面
以上两个场景都是根据用户手持手机的方式和旋转动作自动识别用户是想要横屏还是竖屏。这个问题将在下面详细说明。
该功能的核心部件是加速度传感器,在介绍加速度传感器之前,先了解传感器坐标系。
- 传感器坐标系
通常,传感器框架使用标准 3 表示数据值的轴坐标系。对于大多数传感器,当设备处于默认屏幕方向时,坐标系将与设备屏幕相比定义(见图 5)。当设备处于默认屏幕方向时,X 轴向向右水平延伸,Y 轴垂直向上延伸,Z 轴向垂直于屏幕向外延伸。在这个坐标系中,屏幕后面的坐标将是负的 Z 值。关于这个坐标系,需要特别注意的是,传感器的坐标系不会随着设备的移动而改变。
图5.传感器坐标系(相对于设备)
- 加速传感器
加速度传感器由弹性敏感元件制成悬臂位移器,由弹性敏感元件制成的储能弹簧驱动电触点,完成从重力到电信号的转换。例如,当我们向上移动外壳时,金属球会因为惯性而向下拉伸弹簧。此时,我们只需要测量弹簧的拉伸量,我们就可以计算重力。由此易得,X,Y,Z加速度计可以测量物体在三维空间中的运动方向。详见[重力感应原理]
加速度传感器广泛应用于移动设备中。本文主要介绍加速度传感器Android水平和垂直屏切换在系统中的应用主要是通过监控加速传感器实时获得X、Y、Z三个方向的加速度值;当4(XX YY)>=Z*Z在X和Y平面上的旋转角度;最后,根据旋转角度计算设备的水平和垂直屏幕状态。主代码贴在下面。
/** * 在onResume中,向SensorManager注册监控加速传感器 */ @Override protected void onResume() { super.onResume(); orientationListener = new OrientationListener(this); orientationListener.enable(); } public void enable() { if (mSensor == null) { Log.w(TAG, "Cannot detect sensors. Not enabled"); return; } if (mEnabled == false) { if (localLOGV) Log.d(TAG, "OrientationEventListener enabled"); mSensorManager.registerListener(mSensorEventListener, mSensor, mRate); mEnabled = true; } }
class SensorEventListenerImpl implements SensorEventListener { private static final int _DATA_X = 0; private static final int _DATA_Y = 1; private static final int _DATA_Z = 2; /** ** 通过X、Y、Z三个方向加速度值的变化,计算出设备旋转的角度。 **/ public void onSensorChanged(SensorEvent event) { float[] values = event.values; int orientation = ORIENTATION_UNKNOWN; float X = -values[_DATA_X]; float Y = -values[_DATA_Y]; float Z = -values[_DATA_Z]; float magnitude = X*X Y*Y; // Don't trust the angle if the magnitude is small compared to the y value if (magnitude * 4 >= Z*Z) { float OneEightyOverPi = 57.29577957855f; float angle = (float)Math.atan2(-Y, X) * OneEightyOverPi; orientation = 90 - (int)Math.round(angle); // normalize to 0 - 359 range while (orientation >= 360) { orientation -= 360; } while (orientation < 0) { orientation = 360; } } if (mOldListener != null) { mOldListener.onSensorChanged(Sensor.TYPE_ACCELEROMETER, event.values); } if (orientation != mOrientation) { mOrientation = orientation; onOrientationChanged(orientation); } } }
public class OrientationListener extends OrientationEventListener { private int degree = 0;//旋转角度 private int mOrientation = 0;//2-横屏 1-竖屏,0-未知 public OrientationListener(Context context) { super(context); } /** * 根据旋转角度,设备水平和垂直屏幕状态 **/ @Override public void onOrientationChanged(int orientation) { degree = orientation; if (degree > 0 && degree < 45) { mOrientation = 1; } else if (degree > 45 && degree < 135) { mOrientation = 2; } else if (degree > 135 && degree < 225) { mOrientation = 1; } else if (degree > 225 && degree < 315) { mOrientation = 2; } else if (degree > 315 && degree < 360) { mOrientation = 1; } if (mOrientation == 2) { Log.i("OrientationListener ", "横屏"); } else if (mOrientation == 1) { Log.i("OrientationListener ", "竖屏"); } } }
特别说明:Math.atan2(-Y, X) 是计算原点(0,0)到(x,y)点的线段与x轴正方向之间的平面角度(弧度值), float angle = (float)Math.atan2(-Y, X) * OneEightyOverPi得到的是原点(0,0)到(x,y)点的线段与x轴正方向之间的角度,90 - (int)Math.round(angle)为设备旋转的角度。
本节实现一个简易的打高尔夫球游戏,练习一下加速度传感器的运用。该游戏为多人游戏,游戏规则为:参与者通过摇晃手机控制高尔夫球的移动,当高尔夫球落到洞中则计1分,否则不计分,每人操作3次,得分最高者获胜。游戏实现原理是根据加速度传感器获得设备旋转角度,实时计算并更新高尔夫球的位置,根据高尔夫球的位置与洞的重合度,判断高尔夫球是否落入洞中。落入洞中则得分,否则,不计分。游戏具体实现见附件,演示如下。
链接: https://pan.baidu.com/s/1Kas3kL0fdaXbygGA--l7JQ 2 提取码: 87nh 链接: https://pan.baidu.com/s/1yXNbbI3QhYG3BMZsyG2PSw 1 提取码: 8uaz
大多数移动设备,除了上面介绍的加速度传感器外,还有很多内置传感器,比如:重力传感器、旋转矢量传感器、屏幕方向传感器、温度传感器、光传感器、压力传感器等(如需了解详细信息,请参阅传感器)。开发者可以根据这些传感器,实现许多非常智能的功能。比如:
- 通过光线传感器,自动调节屏幕的亮度,保护用户的眼睛
- 通过加速度传感器,实现计步器和运动检测功能
- 通过湿度传感器和温度传感器,计算露点和绝对湿度
- 通过GPS,实现导航功能
- https://developer.android.com/guide/topics/sensors/sensors_motion?hl=zh-cn 1
- https://developer.android.com/guide/topics/sensors/sensors_overview?hl=zh-cn
- https://github.com/googlearchive/android-AccelerometerPlay
- https://v.qq.com/x/page/t050708r6ea.html
- https://baike.baidu.com/item/重力感应器?fromtitle=重力传感器&fromid=3623984
AccelerometerPlay.zip (5.0 KB)