Small tweaks to orientation.
Improved threshold for detecting external acceleration.
Bug: 5976859
Change-Id: Iaf2298fba8eda72d1cacbb2f3aea72f460a9262f
diff --git a/core/java/android/view/WindowOrientationListener.java b/core/java/android/view/WindowOrientationListener.java
index c28b220..4c34dd4 100755
--- a/core/java/android/view/WindowOrientationListener.java
+++ b/core/java/android/view/WindowOrientationListener.java
@@ -21,6 +21,7 @@
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
+import android.os.SystemProperties;
import android.util.FloatMath;
import android.util.Log;
import android.util.Slog;
@@ -34,20 +35,15 @@
* "App/Activity/Screen Orientation" to ensure that all orientation
* modes still work correctly.
*
- * You can also visualize the behavior of the WindowOrientationListener by
- * enabling the window orientation listener log using the Development Settings
- * in the Dev Tools application (Development.apk)
- * and running frameworks/base/tools/orientationplot/orientationplot.py.
- *
- * More information about how to tune this algorithm in
- * frameworks/base/tools/orientationplot/README.txt.
+ * You can also visualize the behavior of the WindowOrientationListener.
+ * Refer to frameworks/base/tools/orientationplot/README.txt for details.
*
* @hide
*/
public abstract class WindowOrientationListener {
private static final String TAG = "WindowOrientationListener";
- private static final boolean DEBUG = false;
- private static final boolean localLOGV = DEBUG || false;
+ private static final boolean LOG = SystemProperties.getBoolean(
+ "debug.orientation.log", false);
private static final boolean USE_GRAVITY_SENSOR = false;
@@ -56,7 +52,6 @@
private int mRate;
private Sensor mSensor;
private SensorEventListenerImpl mSensorEventListener;
- boolean mLogEnabled;
int mCurrentRotation = -1;
/**
@@ -100,7 +95,9 @@
return;
}
if (mEnabled == false) {
- if (localLOGV) Log.d(TAG, "WindowOrientationListener enabled");
+ if (LOG) {
+ Log.d(TAG, "WindowOrientationListener enabled");
+ }
mSensorManager.registerListener(mSensorEventListener, mSensor, mRate);
mEnabled = true;
}
@@ -115,7 +112,9 @@
return;
}
if (mEnabled == true) {
- if (localLOGV) Log.d(TAG, "WindowOrientationListener disabled");
+ if (LOG) {
+ Log.d(TAG, "WindowOrientationListener disabled");
+ }
mSensorManager.unregisterListener(mSensorEventListener);
mEnabled = false;
}
@@ -165,16 +164,6 @@
public abstract void onProposedRotationChanged(int rotation);
/**
- * Enables or disables the window orientation listener logging for use with
- * the orientationplot.py tool.
- * Logging is usually enabled via Development Settings. (See class comments.)
- * @param enable True to enable logging.
- */
- public void setLogEnabled(boolean enable) {
- mLogEnabled = enable;
- }
-
- /**
* This class filters the raw accelerometer data and tries to detect actual changes in
* orientation. This is a very ill-defined problem so there are a lot of tweakable parameters,
* but here's the outline:
@@ -238,11 +227,16 @@
// can change.
private static final long PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS = 500 * NANOS_PER_MS;
- // The mininum amount of time that must have elapsed since the device stopped
+ // The minimum amount of time that must have elapsed since the device stopped
// swinging (time since device appeared to be in the process of being put down
// or put away into a pocket) before the proposed rotation can change.
private static final long PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS = 300 * NANOS_PER_MS;
+ // The minimum amount of time that must have elapsed since the device stopped
+ // undergoing external acceleration before the proposed rotation can change.
+ private static final long PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS =
+ 500 * NANOS_PER_MS;
+
// If the tilt angle remains greater than the specified angle for a minimum of
// the specified time, then the device is deemed to be lying flat
// (just chillin' on a table).
@@ -300,10 +294,15 @@
// singularities in the tilt and orientation calculations.
//
// In both cases, we postpone choosing an orientation.
+ //
+ // However, we need to tolerate some acceleration because the angular momentum
+ // of turning the device can skew the observed acceleration for a short period of time.
+ private static final float NEAR_ZERO_MAGNITUDE = 1; // m/s^2
+ private static final float ACCELERATION_TOLERANCE = 4; // m/s^2
private static final float MIN_ACCELERATION_MAGNITUDE =
- SensorManager.STANDARD_GRAVITY * 0.3f;
+ SensorManager.STANDARD_GRAVITY - ACCELERATION_TOLERANCE;
private static final float MAX_ACCELERATION_MAGNITUDE =
- SensorManager.STANDARD_GRAVITY * 1.25f;
+ SensorManager.STANDARD_GRAVITY + ACCELERATION_TOLERANCE;
// Maximum absolute tilt angle at which to consider orientation data. Beyond this (i.e.
// when screen is facing the sky or ground), we completely ignore orientation data.
@@ -353,6 +352,9 @@
// Timestamp when the device last appeared to be swinging.
private long mSwingTimestampNanos;
+ // Timestamp when the device last appeared to be undergoing external acceleration.
+ private long mAccelerationTimestampNanos;
+
// History of observed tilt angles.
private static final int TILT_HISTORY_SIZE = 40;
private float[] mTiltHistory = new float[TILT_HISTORY_SIZE];
@@ -374,15 +376,13 @@
@Override
public void onSensorChanged(SensorEvent event) {
- final boolean log = mOrientationListener.mLogEnabled;
-
// The vector given in the SensorEvent points straight up (towards the sky) under ideal
// conditions (the phone is not accelerating). I'll call this up vector elsewhere.
float x = event.values[ACCELEROMETER_DATA_X];
float y = event.values[ACCELEROMETER_DATA_Y];
float z = event.values[ACCELEROMETER_DATA_Z];
- if (log) {
+ if (LOG) {
Slog.v(TAG, "Raw acceleration vector: "
+ "x=" + x + ", y=" + y + ", z=" + z
+ ", magnitude=" + FloatMath.sqrt(x * x + y * y + z * z));
@@ -399,7 +399,7 @@
if (now < then
|| now > then + MAX_FILTER_DELTA_TIME_NANOS
|| (x == 0 && y == 0 && z == 0)) {
- if (log) {
+ if (LOG) {
Slog.v(TAG, "Resetting orientation listener.");
}
reset();
@@ -409,7 +409,7 @@
x = alpha * (x - mLastFilteredX) + mLastFilteredX;
y = alpha * (y - mLastFilteredY) + mLastFilteredY;
z = alpha * (z - mLastFilteredZ) + mLastFilteredZ;
- if (log) {
+ if (LOG) {
Slog.v(TAG, "Filtered acceleration vector: "
+ "x=" + x + ", y=" + y + ", z=" + z
+ ", magnitude=" + FloatMath.sqrt(x * x + y * y + z * z));
@@ -421,18 +421,24 @@
mLastFilteredY = y;
mLastFilteredZ = z;
+ boolean isAccelerating = false;
boolean isFlat = false;
boolean isSwinging = false;
if (!skipSample) {
// Calculate the magnitude of the acceleration vector.
final float magnitude = FloatMath.sqrt(x * x + y * y + z * z);
- if (magnitude < MIN_ACCELERATION_MAGNITUDE
- || magnitude > MAX_ACCELERATION_MAGNITUDE) {
- if (log) {
- Slog.v(TAG, "Ignoring sensor data, magnitude out of range.");
+ if (magnitude < NEAR_ZERO_MAGNITUDE) {
+ if (LOG) {
+ Slog.v(TAG, "Ignoring sensor data, magnitude too close to zero.");
}
clearPredictedRotation();
} else {
+ // Determine whether the device appears to be undergoing external acceleration.
+ if (isAccelerating(magnitude)) {
+ isAccelerating = true;
+ mAccelerationTimestampNanos = now;
+ }
+
// Calculate the tilt angle.
// This is the angle between the up vector and the x-y plane (the plane of
// the screen) in a range of [-90, 90] degrees.
@@ -441,6 +447,7 @@
// 90 degrees: screen horizontal and facing the sky (on table)
final int tiltAngle = (int) Math.round(
Math.asin(z / magnitude) * RADIANS_TO_DEGREES);
+ addTiltHistoryEntry(now, tiltAngle);
// Determine whether the device appears to be flat or swinging.
if (isFlat(now)) {
@@ -451,12 +458,11 @@
isSwinging = true;
mSwingTimestampNanos = now;
}
- addTiltHistoryEntry(now, tiltAngle);
// If the tilt angle is too close to horizontal then we cannot determine
// the orientation angle of the screen.
if (Math.abs(tiltAngle) > MAX_TILT) {
- if (log) {
+ if (LOG) {
Slog.v(TAG, "Ignoring sensor data, tilt angle too high: "
+ "tiltAngle=" + tiltAngle);
}
@@ -483,7 +489,7 @@
&& isOrientationAngleAcceptable(nearestRotation,
orientationAngle)) {
updatePredictedRotation(now, nearestRotation);
- if (log) {
+ if (LOG) {
Slog.v(TAG, "Predicted: "
+ "tiltAngle=" + tiltAngle
+ ", orientationAngle=" + orientationAngle
@@ -493,7 +499,7 @@
* 0.000001f));
}
} else {
- if (log) {
+ if (LOG) {
Slog.v(TAG, "Ignoring sensor data, no predicted rotation: "
+ "tiltAngle=" + tiltAngle
+ ", orientationAngle=" + orientationAngle);
@@ -511,15 +517,18 @@
}
// Write final statistics about where we are in the orientation detection process.
- if (log) {
+ 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,
@@ -528,7 +537,7 @@
// Tell the listener.
if (mProposedRotation != oldProposedRotation && mProposedRotation >= 0) {
- if (log) {
+ if (LOG) {
Slog.v(TAG, "Proposed rotation changed! proposedRotation=" + mProposedRotation
+ ", oldProposedRotation=" + oldProposedRotation);
}
@@ -618,6 +627,12 @@
return false;
}
+ // The last acceleration state must have been sufficiently long ago.
+ if (now < mAccelerationTimestampNanos
+ + PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS) {
+ return false;
+ }
+
// Looks good!
return true;
}
@@ -627,6 +642,7 @@
mProposedRotation = -1;
mFlatTimestampNanos = Long.MIN_VALUE;
mSwingTimestampNanos = Long.MIN_VALUE;
+ mAccelerationTimestampNanos = Long.MIN_VALUE;
clearPredictedRotation();
clearTiltHistory();
}
@@ -643,6 +659,11 @@
}
}
+ private boolean isAccelerating(float magnitude) {
+ return magnitude < MIN_ACCELERATION_MAGNITUDE
+ || magnitude > MAX_ACCELERATION_MAGNITUDE;
+ }
+
private void clearTiltHistory() {
mTiltHistoryTimestampNanos[0] = Long.MIN_VALUE;
mTiltHistoryIndex = 1;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index b3ca171..6348d37 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -553,8 +553,6 @@
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.SCREEN_OFF_TIMEOUT), false, this);
resolver.registerContentObserver(Settings.System.getUriFor(
- Settings.System.WINDOW_ORIENTATION_LISTENER_LOG), false, this);
- resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.POINTER_LOCATION), false, this);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.DEFAULT_INPUT_METHOD), false, this);
@@ -1098,10 +1096,6 @@
updateOrientationListenerLp();
}
- mOrientationListener.setLogEnabled(
- Settings.System.getInt(resolver,
- Settings.System.WINDOW_ORIENTATION_LISTENER_LOG, 0) != 0);
-
if (mSystemReady) {
int pointerLocation = Settings.System.getInt(resolver,
Settings.System.POINTER_LOCATION, 0);
diff --git a/tools/orientationplot/README.txt b/tools/orientationplot/README.txt
index 0143510..d53f65e 100644
--- a/tools/orientationplot/README.txt
+++ b/tools/orientationplot/README.txt
@@ -16,15 +16,15 @@
The tool works by scaping the debug log output from WindowOrientationListener
for interesting data and then plotting it.
-1. Enable the Window Orientation Listener debugging data log using the
- Development Settings in the Dev Tools application (Development.apk).
-
-2. Plug in the device. Ensure that it is the only device plugged in
+1. Plug in the device. Ensure that it is the only device plugged in
since this script is of very little brain and will get confused otherwise.
-3. Run "orientationplot.py".
+2. Enable the Window Orientation Listener debugging data log.
+ adb shell setprop debug.orientation.log true
+ adb shell stop
+ adb shell start
-4. When finished, remember to disable the debug log output since it is quite verbose!
+3. Run "orientationplot.py".
WHAT IT ALL MEANS
diff --git a/tools/orientationplot/orientationplot.py b/tools/orientationplot/orientationplot.py
index f4e6b45..6fc3922 100755
--- a/tools/orientationplot/orientationplot.py
+++ b/tools/orientationplot/orientationplot.py
@@ -152,6 +152,7 @@
self.time_until_settled = self._make_timeseries()
self.time_until_flat_delay_expired = self._make_timeseries()
self.time_until_swing_delay_expired = self._make_timeseries()
+ self.time_until_acceleration_delay_expired = self._make_timeseries()
self.stability_axes = self._add_timeseries_axes(
6, 'Proposal Stability', 'ms', [-10, 600],
sharex=shared_axis,
@@ -162,6 +163,8 @@
self.stability_axes, 'time until flat delay expired', 'green')
self.time_until_swing_delay_expired_line = self._add_timeseries_line(
self.stability_axes, 'time until swing delay expired', 'blue')
+ self.time_until_acceleration_delay_expired_line = self._add_timeseries_line(
+ self.stability_axes, 'time until acceleration delay expired', 'red')
self._add_timeseries_legend(self.stability_axes)
self.sample_latency = self._make_timeseries()
@@ -253,6 +256,7 @@
self.parse_time_until_settled = None
self.parse_time_until_flat_delay_expired = None
self.parse_time_until_swing_delay_expired = None
+ self.parse_time_until_acceleration_delay_expired = None
self.parse_sample_latency = None
# Update samples.
@@ -303,6 +307,7 @@
self.parse_time_until_settled = self._get_following_number(line, 'timeUntilSettledMS=')
self.parse_time_until_flat_delay_expired = self._get_following_number(line, 'timeUntilFlatDelayExpiredMS=')
self.parse_time_until_swing_delay_expired = self._get_following_number(line, 'timeUntilSwingDelayExpiredMS=')
+ self.parse_time_until_acceleration_delay_expired = self._get_following_number(line, 'timeUntilAccelerationDelayExpiredMS=')
self._append(self.raw_acceleration_x, timeindex, self.parse_raw_acceleration_x)
self._append(self.raw_acceleration_y, timeindex, self.parse_raw_acceleration_y)
@@ -326,6 +331,7 @@
self._append(self.time_until_settled, timeindex, self.parse_time_until_settled)
self._append(self.time_until_flat_delay_expired, timeindex, self.parse_time_until_flat_delay_expired)
self._append(self.time_until_swing_delay_expired, timeindex, self.parse_time_until_swing_delay_expired)
+ self._append(self.time_until_acceleration_delay_expired, timeindex, self.parse_time_until_acceleration_delay_expired)
self._append(self.sample_latency, timeindex, self.parse_sample_latency)
self._reset_parse_state()
@@ -349,6 +355,7 @@
self._scroll(self.time_until_settled, bottom)
self._scroll(self.time_until_flat_delay_expired, bottom)
self._scroll(self.time_until_swing_delay_expired, bottom)
+ self._scroll(self.time_until_acceleration_delay_expired, bottom)
self._scroll(self.sample_latency, bottom)
# Redraw the plots.
@@ -368,6 +375,7 @@
self.time_until_settled_line.set_data(self.time_until_settled)
self.time_until_flat_delay_expired_line.set_data(self.time_until_flat_delay_expired)
self.time_until_swing_delay_expired_line.set_data(self.time_until_swing_delay_expired)
+ self.time_until_acceleration_delay_expired_line.set_data(self.time_until_acceleration_delay_expired)
self.sample_latency_line.set_data(self.sample_latency)
self.fig.canvas.draw_idle()