Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit daf5d894 authored by Jeff Brown's avatar Jeff Brown
Browse files

Small tweaks to orientation.

Improved threshold for detecting external acceleration.

Bug: 5976859
Change-Id: Iaf2298fba8eda72d1cacbb2f3aea72f460a9262f
parent 59bbef0c
Loading
Loading
Loading
Loading
+61 −40
Original line number Diff line number Diff line
@@ -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;
        }
@@ -164,16 +163,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,
@@ -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;
+0 −6
Original line number Diff line number Diff line
@@ -552,8 +552,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                    Settings.System.USER_ROTATION), false, this);
            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(
@@ -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);
+6 −6
Original line number Diff line number Diff line
@@ -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
+8 −0
Original line number Diff line number Diff line
@@ -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()