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

Commit eee29c44 authored by Craig Mautner's avatar Craig Mautner
Browse files

Reset SensorEventListener when listener reenabled.

- Following disable and reenable of the WindowOrientationListener
the state was the same as before. State should be reset to default.

- Provide a Handler to the sensor task to deliver events on the
same Thread that WindowManagerPolicy operates on.

- Expand lock protection to all of WindowOrientationListener.

- Move WindowOrientationListener to policy package.

- Make SensorEventListenerImpl non-static.

Fixes bug 7964531.

Change-Id: I17cecf3d0b6d125cb3e4d7350c3adb3f62b684bd
parent 2ceb0815
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -50,7 +50,6 @@ import android.speech.tts.TextToSpeech;
import android.text.TextUtils;
import android.util.AndroidException;
import android.util.Log;
import android.view.WindowOrientationListener;

import com.android.internal.widget.ILockSettings;

+7 −5
Original line number Diff line number Diff line
@@ -84,7 +84,6 @@ import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.WindowManagerPolicy;
import android.view.WindowOrientationListener;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
@@ -555,8 +554,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    }
    
    class MyOrientationListener extends WindowOrientationListener {
        MyOrientationListener(Context context) {
            super(context);
        MyOrientationListener(Context context, Handler handler) {
            super(context, handler);
        }
        
        @Override
@@ -854,7 +853,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            mKeyguardMediator = new KeyguardViewMediator(context, null);
        }
        mHandler = new PolicyHandler();
        mOrientationListener = new MyOrientationListener(mContext);
        mOrientationListener = new MyOrientationListener(mContext, mHandler);
        try {
            mOrientationListener.setCurrentRotation(windowManager.getRotation());
        } catch (RemoteException ex) { }
@@ -3760,14 +3759,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    }

    BroadcastReceiver mDockReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())) {
                mDockMode = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
            }
            updateRotation(true);
            synchronized (mLock) {
                updateOrientationListenerLp();
            }
        }
    };

    BroadcastReceiver mDreamReceiver = new BroadcastReceiver() {
+213 −195
Original line number Diff line number Diff line
@@ -14,13 +14,14 @@
 * limitations under the License.
 */

package android.view;
package com.android.internal.policy.impl;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Handler;
import android.os.SystemProperties;
import android.util.FloatMath;
import android.util.Log;
@@ -47,26 +48,31 @@ public abstract class WindowOrientationListener {

    private static final boolean USE_GRAVITY_SENSOR = false;

    private Handler mHandler;
    private SensorManager mSensorManager;
    private boolean mEnabled;
    private int mRate;
    private Sensor mSensor;
    private SensorEventListenerImpl mSensorEventListener;
    int mCurrentRotation = -1;
    private int mCurrentRotation = -1;

    private final Object mLock = new Object();

    /**
     * Creates a new WindowOrientationListener.
     * 
     * @param context for the WindowOrientationListener.
     * @param handler Provides the Looper for receiving sensor updates.
     */
    public WindowOrientationListener(Context context) {
        this(context, SensorManager.SENSOR_DELAY_UI);
    public WindowOrientationListener(Context context, Handler handler) {
        this(context, handler, SensorManager.SENSOR_DELAY_UI);
    }
    
    /**
     * Creates a new WindowOrientationListener.
     * 
     * @param context for the WindowOrientationListener.
     * @param handler Provides the Looper for receiving sensor updates.
     * @param rate at which sensor events are processed (see also
     * {@link android.hardware.SensorManager SensorManager}). Use the default
     * value of {@link android.hardware.SensorManager#SENSOR_DELAY_NORMAL 
@@ -74,22 +80,24 @@ public abstract class WindowOrientationListener {
     *
     * This constructor is private since no one uses it.
     */
    private WindowOrientationListener(Context context, int rate) {
    private WindowOrientationListener(Context context, Handler handler, int rate) {
        mHandler = handler;
        mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
        mRate = rate;
        mSensor = mSensorManager.getDefaultSensor(USE_GRAVITY_SENSOR
                ? Sensor.TYPE_GRAVITY : Sensor.TYPE_ACCELEROMETER);
        if (mSensor != null) {
            // Create listener only if sensors do exist
            mSensorEventListener = new SensorEventListenerImpl(this);
            mSensorEventListener = new SensorEventListenerImpl();
        }
    }

    /**
     * Enables the WindowOrientationListener so it will monitor the sensor and call
     * {@link #onOrientationChanged} when the device orientation changes.
     * {@link #onProposedRotationChanged(int)} when the device orientation changes.
     */
    public void enable() {
        synchronized (mLock) {
            if (mSensor == null) {
                Log.w(TAG, "Cannot detect sensors. Not enabled");
                return;
@@ -98,16 +106,18 @@ public abstract class WindowOrientationListener {
                if (LOG) {
                    Log.d(TAG, "WindowOrientationListener enabled");
                }
            mSensorEventListener.reset();
            mSensorManager.registerListener(mSensorEventListener, mSensor, mRate);
                mSensorEventListener.resetLocked();
                mSensorManager.registerListener(mSensorEventListener, mSensor, mRate, mHandler);
                mEnabled = true;
            }
        }
    }

    /**
     * Disables the WindowOrientationListener.
     */
    public void disable() {
        synchronized (mLock) {
            if (mSensor == null) {
                Log.w(TAG, "Cannot detect sensors. Invalid disable");
                return;
@@ -120,6 +130,7 @@ public abstract class WindowOrientationListener {
                mEnabled = false;
            }
        }
    }

    /**
     * Sets the current rotation.
@@ -127,8 +138,10 @@ public abstract class WindowOrientationListener {
     * @param rotation The current rotation.
     */
    public void setCurrentRotation(int rotation) {
        synchronized (mLock) {
            mCurrentRotation = rotation;
        }
    }

    /**
     * Gets the proposed rotation.
@@ -139,18 +152,22 @@ public abstract class WindowOrientationListener {
     * @return The proposed rotation, or -1 if unknown.
     */
    public int getProposedRotation() {
        synchronized (mLock) {
            if (mEnabled) {
            return mSensorEventListener.getProposedRotation();
                return mSensorEventListener.getProposedRotationLocked();
            }
            return -1;
        }
    }

    /**
     * Returns true if sensor is enabled and false otherwise
     */
    public boolean canDetectOrientation() {
        synchronized (mLock) {
            return mSensor != null;
        }
    }

    /**
     * Called when the rotation view of the device has changed.
@@ -160,7 +177,7 @@ public abstract class WindowOrientationListener {
     * uncertain to being certain again, even if it is the same orientation as before.
     *
     * @param rotation The new orientation of the device, one of the Surface.ROTATION_* constants.
     * @see Surface
     * @see android.view.Surface
     */
    public abstract void onProposedRotationChanged(int rotation);

@@ -202,7 +219,7 @@ public abstract class WindowOrientationListener {
     * See http://en.wikipedia.org/wiki/Low-pass_filter#Discrete-time_realization for
     * signal processing background.
     */
    static final class SensorEventListenerImpl implements SensorEventListener {
    final class SensorEventListenerImpl implements SensorEventListener {
        // We work with all angles in degrees in this class.
        private static final float RADIANS_TO_DEGREES = (float) (180 / Math.PI);

@@ -214,8 +231,6 @@ public abstract class WindowOrientationListener {
        private static final int ACCELEROMETER_DATA_Y = 1;
        private static final int ACCELEROMETER_DATA_Z = 2;

        private final WindowOrientationListener mOrientationListener;

        // The minimum amount of time that a predicted rotation must be stable before it
        // is accepted as a valid rotation proposal.  This value can be quite small because
        // the low-pass filter already suppresses most of the noise so we're really just
@@ -320,7 +335,7 @@ public abstract class WindowOrientationListener {
        // facing up (resting on a table).
        // The ideal tilt angle is 0 (when the device is vertical) so the limits establish
        // how close to vertical the device must be in order to change orientation.
        private static final int[][] TILT_TOLERANCE = new int[][] {
        private final int[][] TILT_TOLERANCE = new int[][] {
            /* ROTATION_0   */ { -25, 70 },
            /* ROTATION_90  */ { -25, 65 },
            /* ROTATION_180 */ { -25, 60 },
@@ -362,12 +377,7 @@ public abstract class WindowOrientationListener {
        private long[] mTiltHistoryTimestampNanos = new long[TILT_HISTORY_SIZE];
        private int mTiltHistoryIndex;

        public SensorEventListenerImpl(WindowOrientationListener orientationListener) {
            mOrientationListener = orientationListener;
            reset();
        }

        public int getProposedRotation() {
        public int getProposedRotationLocked() {
            return mProposedRotation;
        }

@@ -377,8 +387,13 @@ public abstract class WindowOrientationListener {

        @Override
        public void onSensorChanged(SensorEvent event) {
            // 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.
            int proposedRotation;
            int oldProposedRotation;

            synchronized (mLock) {
                // 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];
@@ -403,7 +418,7 @@ public abstract class WindowOrientationListener {
                    if (LOG) {
                        Slog.v(TAG, "Resetting orientation listener.");
                    }
                reset();
                    resetLocked();
                    skipSample = true;
                } else {
                    final float alpha = timeDeltaMS / (FILTER_TIME_CONSTANT_MS + timeDeltaMS);
@@ -432,10 +447,11 @@ public abstract class WindowOrientationListener {
                        if (LOG) {
                            Slog.v(TAG, "Ignoring sensor data, magnitude too close to zero.");
                        }
                    clearPredictedRotation();
                        clearPredictedRotationLocked();
                    } else {
                    // Determine whether the device appears to be undergoing external acceleration.
                    if (isAccelerating(magnitude)) {
                        // Determine whether the device appears to be undergoing external
                        // acceleration.
                        if (isAcceleratingLocked(magnitude)) {
                            isAccelerating = true;
                            mAccelerationTimestampNanos = now;
                        }
@@ -448,14 +464,14 @@ 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);
                        addTiltHistoryEntryLocked(now, tiltAngle);

                        // Determine whether the device appears to be flat or swinging.
                    if (isFlat(now)) {
                        if (isFlatLocked(now)) {
                            isFlat = true;
                            mFlatTimestampNanos = now;
                        }
                    if (isSwinging(now, tiltAngle)) {
                        if (isSwingingLocked(now, tiltAngle)) {
                            isSwinging = true;
                            mSwingTimestampNanos = now;
                        }
@@ -467,7 +483,7 @@ public abstract class WindowOrientationListener {
                                Slog.v(TAG, "Ignoring sensor data, tilt angle too high: "
                                        + "tiltAngle=" + tiltAngle);
                            }
                        clearPredictedRotation();
                            clearPredictedRotationLocked();
                        } else {
                            // Calculate the orientation angle.
                            // This is the angle between the x-y projection of the up vector onto
@@ -486,10 +502,10 @@ public abstract class WindowOrientationListener {
                            }

                            // Determine the predicted orientation.
                        if (isTiltAngleAcceptable(nearestRotation, tiltAngle)
                                && isOrientationAngleAcceptable(nearestRotation,
                            if (isTiltAngleAcceptableLocked(nearestRotation, tiltAngle)
                                    && isOrientationAngleAcceptableLocked(nearestRotation,
                                            orientationAngle)) {
                            updatePredictedRotation(now, nearestRotation);
                                updatePredictedRotationLocked(now, nearestRotation);
                                if (LOG) {
                                    Slog.v(TAG, "Predicted: "
                                            + "tiltAngle=" + tiltAngle
@@ -505,22 +521,23 @@ public abstract class WindowOrientationListener {
                                            + "tiltAngle=" + tiltAngle
                                            + ", orientationAngle=" + orientationAngle);
                                }
                            clearPredictedRotation();
                                clearPredictedRotationLocked();
                            }
                        }
                    }
                }

                // Determine new proposed rotation.
            final int oldProposedRotation = mProposedRotation;
            if (mPredictedRotation < 0 || isPredictedRotationAcceptable(now)) {
                oldProposedRotation = mProposedRotation;
                if (mPredictedRotation < 0 || isPredictedRotationAcceptableLocked(now)) {
                    mProposedRotation = mPredictedRotation;
                }
                proposedRotation = mProposedRotation;

                // Write final statistics about where we are in the orientation detection process.
                if (LOG) {
                Slog.v(TAG, "Result: currentRotation=" + mOrientationListener.mCurrentRotation
                        + ", proposedRotation=" + mProposedRotation
                    Slog.v(TAG, "Result: currentRotation=" + mCurrentRotation
                            + ", proposedRotation=" + proposedRotation
                            + ", predictedRotation=" + mPredictedRotation
                            + ", timeDeltaMS=" + timeDeltaMS
                            + ", isAccelerating=" + isAccelerating
@@ -535,21 +552,22 @@ public abstract class WindowOrientationListener {
                            + ", timeUntilSwingDelayExpiredMS=" + remainingMS(now,
                                    mSwingTimestampNanos + PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS));
                }
            }

            // Tell the listener.
            if (mProposedRotation != oldProposedRotation && mProposedRotation >= 0) {
            if (proposedRotation != oldProposedRotation && proposedRotation >= 0) {
                if (LOG) {
                    Slog.v(TAG, "Proposed rotation changed!  proposedRotation=" + mProposedRotation
                    Slog.v(TAG, "Proposed rotation changed!  proposedRotation=" + proposedRotation
                            + ", oldProposedRotation=" + oldProposedRotation);
                }
                mOrientationListener.onProposedRotationChanged(mProposedRotation);
                onProposedRotationChanged(proposedRotation);
            }
        }

        /**
         * Returns true if the tilt angle is acceptable for a given predicted rotation.
         */
        private boolean isTiltAngleAcceptable(int rotation, int tiltAngle) {
        private boolean isTiltAngleAcceptableLocked(int rotation, int tiltAngle) {
            return tiltAngle >= TILT_TOLERANCE[rotation][0]
                    && tiltAngle <= TILT_TOLERANCE[rotation][1];
        }
@@ -560,11 +578,11 @@ public abstract class WindowOrientationListener {
         * This function takes into account the gap between adjacent orientations
         * for hysteresis.
         */
        private boolean isOrientationAngleAcceptable(int rotation, int orientationAngle) {
        private boolean isOrientationAngleAcceptableLocked(int rotation, int orientationAngle) {
            // If there is no current rotation, then there is no gap.
            // The gap is used only to introduce hysteresis among advertised orientation
            // changes to avoid flapping.
            final int currentRotation = mOrientationListener.mCurrentRotation;
            final int currentRotation = mCurrentRotation;
            if (currentRotation >= 0) {
                // If the specified rotation is the same or is counter-clockwise adjacent
                // to the current rotation, then we set a lower bound on the orientation angle.
@@ -611,7 +629,7 @@ public abstract class WindowOrientationListener {
         * Returns true if the predicted rotation is ready to be advertised as a
         * proposed rotation.
         */
        private boolean isPredictedRotationAcceptable(long now) {
        private boolean isPredictedRotationAcceptableLocked(long now) {
            // The predicted rotation must have settled long enough.
            if (now < mPredictedRotationTimestampNanos + PROPOSAL_SETTLE_TIME_NANOS) {
                return false;
@@ -638,47 +656,47 @@ public abstract class WindowOrientationListener {
            return true;
        }

        private void reset() {
        private void resetLocked() {
            mLastFilteredTimestampNanos = Long.MIN_VALUE;
            mProposedRotation = -1;
            mFlatTimestampNanos = Long.MIN_VALUE;
            mSwingTimestampNanos = Long.MIN_VALUE;
            mAccelerationTimestampNanos = Long.MIN_VALUE;
            clearPredictedRotation();
            clearTiltHistory();
            clearPredictedRotationLocked();
            clearTiltHistoryLocked();
        }

        private void clearPredictedRotation() {
        private void clearPredictedRotationLocked() {
            mPredictedRotation = -1;
            mPredictedRotationTimestampNanos = Long.MIN_VALUE;
        }

        private void updatePredictedRotation(long now, int rotation) {
        private void updatePredictedRotationLocked(long now, int rotation) {
            if (mPredictedRotation != rotation) {
                mPredictedRotation = rotation;
                mPredictedRotationTimestampNanos = now;
            }
        }

        private boolean isAccelerating(float magnitude) {
        private boolean isAcceleratingLocked(float magnitude) {
            return magnitude < MIN_ACCELERATION_MAGNITUDE
                    || magnitude > MAX_ACCELERATION_MAGNITUDE;
        }

        private void clearTiltHistory() {
        private void clearTiltHistoryLocked() {
            mTiltHistoryTimestampNanos[0] = Long.MIN_VALUE;
            mTiltHistoryIndex = 1;
        }

        private void addTiltHistoryEntry(long now, float tilt) {
        private void addTiltHistoryEntryLocked(long now, float tilt) {
            mTiltHistory[mTiltHistoryIndex] = tilt;
            mTiltHistoryTimestampNanos[mTiltHistoryIndex] = now;
            mTiltHistoryIndex = (mTiltHistoryIndex + 1) % TILT_HISTORY_SIZE;
            mTiltHistoryTimestampNanos[mTiltHistoryIndex] = Long.MIN_VALUE;
        }

        private boolean isFlat(long now) {
            for (int i = mTiltHistoryIndex; (i = nextTiltHistoryIndex(i)) >= 0; ) {
        private boolean isFlatLocked(long now) {
            for (int i = mTiltHistoryIndex; (i = nextTiltHistoryIndexLocked(i)) >= 0; ) {
                if (mTiltHistory[i] < FLAT_ANGLE) {
                    break;
                }
@@ -690,8 +708,8 @@ public abstract class WindowOrientationListener {
            return false;
        }

        private boolean isSwinging(long now, float tilt) {
            for (int i = mTiltHistoryIndex; (i = nextTiltHistoryIndex(i)) >= 0; ) {
        private boolean isSwingingLocked(long now, float tilt) {
            for (int i = mTiltHistoryIndex; (i = nextTiltHistoryIndexLocked(i)) >= 0; ) {
                if (mTiltHistoryTimestampNanos[i] + SWING_TIME_NANOS < now) {
                    break;
                }
@@ -703,12 +721,12 @@ public abstract class WindowOrientationListener {
            return false;
        }

        private int nextTiltHistoryIndex(int index) {
        private int nextTiltHistoryIndexLocked(int index) {
            index = (index == 0 ? TILT_HISTORY_SIZE : index) - 1;
            return mTiltHistoryTimestampNanos[index] != Long.MIN_VALUE ? index : -1;
        }

        private static float remainingMS(long now, long until) {
        private float remainingMS(long now, long until) {
            return now >= until ? 0 : (until - now) * 0.000001f;
        }
    }