diff options
-rwxr-xr-x | core/java/android/view/WindowOrientationListener.java | 101 | ||||
-rwxr-xr-x | policy/src/com/android/internal/policy/impl/PhoneWindowManager.java | 6 | ||||
-rw-r--r-- | tools/orientationplot/README.txt | 12 | ||||
-rwxr-xr-x | tools/orientationplot/orientationplot.py | 8 |
4 files changed, 75 insertions, 52 deletions
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.Sensor; 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 @@ import android.util.Slog; * "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 @@ public abstract class WindowOrientationListener { private int mRate; private Sensor mSensor; private SensorEventListenerImpl mSensorEventListener; - boolean mLogEnabled; int mCurrentRotation = -1; /** @@ -100,7 +95,9 @@ public abstract class WindowOrientationListener { 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 @@ public abstract class WindowOrientationListener { 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 class WindowOrientationListener { 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 @@ public abstract class WindowOrientationListener { // 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 @@ public abstract class WindowOrientationListener { // 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 @@ public abstract class WindowOrientationListener { // 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 @@ public abstract class WindowOrientationListener { @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 @@ public abstract class WindowOrientationListener { 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 @@ public abstract class WindowOrientationListener { 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 @@ public abstract class WindowOrientationListener { 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 @@ public abstract class WindowOrientationListener { // 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 @@ public abstract class WindowOrientationListener { 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 @@ public abstract class WindowOrientationListener { && isOrientationAngleAcceptable(nearestRotation, orientationAngle)) { updatePredictedRotation(now, nearestRotation); - if (log) { + if (LOG) { Slog.v(TAG, "Predicted: " + "tiltAngle=" + tiltAngle + ", orientationAngle=" + orientationAngle @@ -493,7 +499,7 @@ public abstract class WindowOrientationListener { * 0.000001f)); } } else { - if (log) { + if (LOG) { Slog.v(TAG, "Ignoring sensor data, no predicted rotation: " + "tiltAngle=" + tiltAngle + ", orientationAngle=" + orientationAngle); @@ -511,15 +517,18 @@ public abstract class WindowOrientationListener { } // 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 @@ public abstract class WindowOrientationListener { // 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 @@ public abstract class WindowOrientationListener { 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 @@ public abstract class WindowOrientationListener { mProposedRotation = -1; mFlatTimestampNanos = Long.MIN_VALUE; mSwingTimestampNanos = Long.MIN_VALUE; + mAccelerationTimestampNanos = Long.MIN_VALUE; clearPredictedRotation(); clearTiltHistory(); } @@ -643,6 +659,11 @@ public abstract class WindowOrientationListener { } } + 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ USAGE 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 @@ class Plotter: 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 @@ class Plotter: 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 @@ class Plotter: 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 @@ class Plotter: 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 @@ class Plotter: 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 @@ class Plotter: 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 @@ class Plotter: 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() |