如何判断手机的横竖屏
这个问题依赖与手机上的传感器 一般获取手机倾斜角度,用加速度计和磁力计去判断 如果只是判断横竖屏 可以只用加速度计 加速度计普及度高
使用加速度计实现
参考了AOSP的通用实现
public class AccelerometerListener {
public static final int ORIENTATION_UNKNOWN = 0;
public static final int ORIENTATION_VERTICAL = 1;
public static final int ORIENTATION_HORIZONTAL = 2;
private static final String TAG = "AccelerometerListener";
private static final boolean DEBUG = true;
private static final boolean VDEBUG = false;
private static final int ORIENTATION_CHANGED = 1234;
private static final int VERTICAL_DEBOUNCE = 100;
private static final int HORIZONTAL_DEBOUNCE = 500;
private static final double VERTICAL_ANGLE = 50.0;
private SensorManager sensorManager;
private Sensor sensor;
private int orientation;
private int pendingOrientation;
private OrientationListener listener;
Handler handler =
new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case ORIENTATION_CHANGED:
synchronized (this) {
orientation = pendingOrientation;
if (DEBUG) {
LogUtil.d(
TAG,
"orientation: "
+ (orientation == ORIENTATION_HORIZONTAL
? "horizontal"
: (orientation == ORIENTATION_VERTICAL ? "vertical" : "unknown")));
}
if (listener != null) {
listener.orientationChanged(orientation);
}
}
break;
}
}
};
SensorEventListener sensorListener =
new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
onSensorEvent(event.values[0], event.values[1], event.values[2]);
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
public AccelerometerListener(Context context) {
sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
}
public void setListener(OrientationListener listener) {
this.listener = listener;
}
public void enable(boolean enable) {
if (DEBUG) {
LogUtil.d(TAG, "enable(" + enable + ")");
}
synchronized (this) {
if (enable) {
orientation = ORIENTATION_UNKNOWN;
pendingOrientation = ORIENTATION_UNKNOWN;
sensorManager.registerListener(sensorListener, sensor, SensorManager.SENSOR_DELAY_NORMAL);
} else {
sensorManager.unregisterListener(sensorListener);
handler.removeMessages(ORIENTATION_CHANGED);
}
}
}
private void setOrientation(int orientation) {
synchronized (this) {
if (pendingOrientation == orientation) {
return;
}
handler.removeMessages(ORIENTATION_CHANGED);
if (this.orientation != orientation) {
pendingOrientation = orientation;
final Message m = handler.obtainMessage(ORIENTATION_CHANGED);
int delay = (orientation == ORIENTATION_VERTICAL ? VERTICAL_DEBOUNCE : HORIZONTAL_DEBOUNCE);
handler.sendMessageDelayed(m, delay);
} else {
pendingOrientation = ORIENTATION_UNKNOWN;
}
}
}
private void onSensorEvent(double x, double y, double z) {
if (VDEBUG) {
LogUtil.d(TAG, "onSensorEvent(" + x + ", " + y + ", " + z + ")");
}
if (x == 0.0 || y == 0.0 || z == 0.0) {
return;
}
final double xy = Math.hypot(x, y);
double angle = Math.atan2(xy, z);
angle = angle * 180.0 / Math.PI;
final int orientation =
(angle > VERTICAL_ANGLE ? ORIENTATION_VERTICAL : ORIENTATION_HORIZONTAL);
if (VDEBUG) {
LogUtil.d(TAG, "angle: " + angle + " orientation: " + orientation);
}
setOrientation(orientation);
}
public interface OrientationListener {
void orientationChanged(int orientation);
}
}
接口使用
public class ProximitySensor
implements AccelerometerListener.OrientationListener, InCallStateListener, AudioModeListener {
private static final String TAG = ProximitySensor.class.getSimpleName();
private final PowerManager powerManager;
private final PowerManager.WakeLock proximityWakeLock;
private final AudioModeProvider audioModeProvider;
private final AccelerometerListener accelerometerListener;
private final ProximityDisplayListener displayListener;
private int orientation = AccelerometerListener.ORIENTATION_UNKNOWN;
private boolean uiShowing = false;
private boolean isPhoneOffhook = false;
private boolean dialpadVisible;
private boolean isAttemptingVideoCall;
private boolean isVideoCall;
private boolean isRttCall;
public ProximitySensor(
@NonNull Context context,
@NonNull AudioModeProvider audioModeProvider,
@NonNull AccelerometerListener accelerometerListener) {
Trace.beginSection("ProximitySensor.Constructor");
powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if (powerManager.isWakeLockLevelSupported(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)) {
proximityWakeLock =
powerManager.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, TAG);
} else {
LogUtil.i("ProximitySensor.constructor", "Device does not support proximity wake lock.");
proximityWakeLock = null;
}
this.accelerometerListener = accelerometerListener;
this.accelerometerListener.setListener(this);
displayListener =
new ProximityDisplayListener(
(DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE));
displayListener.register();
this.audioModeProvider = audioModeProvider;
this.audioModeProvider.addListener(this);
Trace.endSection();
}
public void tearDown() {
audioModeProvider.removeListener(this);
accelerometerListener.enable(false);
displayListener.unregister();
turnOffProximitySensor(true);
}
@Override
public void orientationChanged(int orientation) {
this.orientation = orientation;
updateProximitySensorMode();
}
@Override
public void onStateChange(InCallState oldState, InCallState newState, CallList callList) {
boolean hasOngoingCall = InCallState.INCALL == newState && callList.hasLiveCall();
boolean isOffhook =
InCallState.PENDING_OUTGOING == newState
|| InCallState.OUTGOING == newState
|| hasOngoingCall;
DialerCall activeCall = callList.getActiveCall();
boolean isVideoCall = activeCall != null && activeCall.isVideoCall();
boolean isRttCall = activeCall != null && activeCall.isActiveRttCall();
if (isOffhook != isPhoneOffhook
|| this.isVideoCall != isVideoCall
|| this.isRttCall != isRttCall) {
isPhoneOffhook = isOffhook;
this.isVideoCall = isVideoCall;
this.isRttCall = isRttCall;
orientation = AccelerometerListener.ORIENTATION_UNKNOWN;
accelerometerListener.enable(isPhoneOffhook);
updateProximitySensorMode();
}
}
@Override
public void onAudioStateChanged(CallAudioState audioState) {
updateProximitySensorMode();
}
public void onDialpadVisible(boolean visible) {
dialpadVisible = visible;
updateProximitySensorMode();
}
public void setIsAttemptingVideoCall(boolean isAttemptingVideoCall) {
LogUtil.i(
"ProximitySensor.setIsAttemptingVideoCall",
"isAttemptingVideoCall: %b",
isAttemptingVideoCall);
this.isAttemptingVideoCall = isAttemptingVideoCall;
updateProximitySensorMode();
}
public void onInCallShowing(boolean showing) {
if (showing) {
uiShowing = true;
} else if (powerManager.isScreenOn()) {
uiShowing = false;
}
updateProximitySensorMode();
}
void onDisplayStateChanged(boolean isDisplayOn) {
LogUtil.i("ProximitySensor.onDisplayStateChanged", "isDisplayOn: %b", isDisplayOn);
accelerometerListener.enable(isDisplayOn);
}
public boolean isScreenReallyOff() {
return !powerManager.isScreenOn();
}
private void turnOnProximitySensor() {
if (proximityWakeLock != null) {
if (!proximityWakeLock.isHeld()) {
LogUtil.i("ProximitySensor.turnOnProximitySensor", "acquiring wake lock");
proximityWakeLock.acquire();
} else {
LogUtil.i("ProximitySensor.turnOnProximitySensor", "wake lock already acquired");
}
}
}
private void turnOffProximitySensor(boolean screenOnImmediately) {
if (proximityWakeLock != null) {
if (proximityWakeLock.isHeld()) {
LogUtil.i("ProximitySensor.turnOffProximitySensor", "releasing wake lock");
int flags = (screenOnImmediately ? 0 : PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY);
proximityWakeLock.release(flags);
} else {
LogUtil.i("ProximitySensor.turnOffProximitySensor", "wake lock already released");
}
}
}
private synchronized void updateProximitySensorMode() {
Trace.beginSection("ProximitySensor.updateProximitySensorMode");
final int audioRoute = audioModeProvider.getAudioState().getRoute();
boolean screenOnImmediately =
(CallAudioState.ROUTE_WIRED_HEADSET == audioRoute
|| CallAudioState.ROUTE_SPEAKER == audioRoute
|| CallAudioState.ROUTE_BLUETOOTH == audioRoute
|| isAttemptingVideoCall
|| isVideoCall
|| isRttCall);
final boolean horizontal = (orientation == AccelerometerListener.ORIENTATION_HORIZONTAL);
screenOnImmediately |= !uiShowing && horizontal;
screenOnImmediately |= dialpadVisible && horizontal;
LogUtil.i(
"ProximitySensor.updateProximitySensorMode",
"screenOnImmediately: %b, dialPadVisible: %b, "
+ "offHook: %b, horizontal: %b, uiShowing: %b, audioRoute: %s",
screenOnImmediately,
dialpadVisible,
isPhoneOffhook,
orientation == AccelerometerListener.ORIENTATION_HORIZONTAL,
uiShowing,
CallAudioState.audioRouteToString(audioRoute));
if (isPhoneOffhook && !screenOnImmediately) {
LogUtil.v("ProximitySensor.updateProximitySensorMode", "turning on proximity sensor");
turnOnProximitySensor();
} else {
LogUtil.v("ProximitySensor.updateProximitySensorMode", "turning off proximity sensor");
turnOffProximitySensor(screenOnImmediately);
}
Trace.endSection();
}
public class ProximityDisplayListener implements DisplayListener {
private DisplayManager displayManager;
private boolean isDisplayOn = true;
ProximityDisplayListener(DisplayManager displayManager) {
this.displayManager = displayManager;
}
void register() {
displayManager.registerDisplayListener(this, null);
}
void unregister() {
displayManager.unregisterDisplayListener(this);
}
@Override
public void onDisplayRemoved(int displayId) {}
@Override
public void onDisplayChanged(int displayId) {
if (displayId == Display.DEFAULT_DISPLAY) {
final Display display = displayManager.getDisplay(displayId);
final boolean isDisplayOn = display.getState() != Display.STATE_OFF;
if (isDisplayOn != this.isDisplayOn) {
this.isDisplayOn = isDisplayOn;
onDisplayStateChanged(this.isDisplayOn);
}
}
}
@Override
public void onDisplayAdded(int displayId) {}
}
}
使用加速度计和磁力计获取手机倾斜角度
public class MainActivity extends Activity {
private SensorManager mSensorManager;
private Sensor accelerometer;
private Sensor magnetic;
private TextView azimuthAngle;
private float[] accelerometerValues = new float[3];
private float[] magneticFieldValues = new float[3];
private static final String TAG = "---MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
accelerometer = mSensorManager
.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
magnetic = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
azimuthAngle = (TextView) findViewById(R.id.azimuth_angle_value);
calculateOrientation();
}
@Override
protected void onResume() {
mSensorManager.registerListener(new MySensorEventListener(),
accelerometer, Sensor.TYPE_ACCELEROMETER);
mSensorManager.registerListener(new MySensorEventListener(), magnetic,
Sensor.TYPE_MAGNETIC_FIELD);
super.onResume();
}
@Override
protected void onPause() {
mSensorManager.unregisterListener(new MySensorEventListener());
super.onPause();
}
private void calculateOrientation() {
float[] values = new float[3];
float[] R = new float[9];
SensorManager.getRotationMatrix(R, null, accelerometerValues,
magneticFieldValues);
SensorManager.getOrientation(R, values);
values[0] = (float) Math.toDegrees(values[0]);
Log.i(TAG, values[0] + "");
if (values[0] >= -5 && values[0] < 5) {
azimuthAngle.setText("正北");
} else if (values[0] >= 5 && values[0] < 85) {
azimuthAngle.setText("东北");
} else if (values[0] >= 85 && values[0] <= 95) {
azimuthAngle.setText("正东");
} else if (values[0] >= 95 && values[0] < 175) {
azimuthAngle.setText("东南");
} else if ((values[0] >= 175 && values[0] <= 180)
|| (values[0]) >= -180 && values[0] < -175) {
azimuthAngle.setText("正南");
} else if (values[0] >= -175 && values[0] < -95) {
azimuthAngle.setText("西南");
} else if (values[0] >= -95 && values[0] < -85) {
azimuthAngle.setText("正西");
} else if (values[0] >= -85 && values[0] < -5) {
azimuthAngle.setText("西北");
}
}
class MySensorEventListener implements SensorEventListener {
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
accelerometerValues = event.values;
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
magneticFieldValues = event.values;
}
calculateOrientation();
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
}
加速度传感器在Android横竖屏切换中的应用
- 通过监听加速度传感器,实时获得X、Y、Z三个方向的加速度值;当4(XX + YY)>=Z*Z时,开始计算设备在X与Y平面上的旋转角度;最后根据旋转角度计算出设备的横竖屏状态。
@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;
}
}
``
```java
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;
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;
if (magnitude * 4 >= Z*Z) {
float OneEightyOverPi = 57.29577957855f;
float angle = (float)Math.atan2(-Y, X) * OneEightyOverPi;
orientation = 90 - (int)Math.round(angle);
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;
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)为设备旋转的角度。
|