Loading core/res/res/values/config.xml +11 −0 Original line number Diff line number Diff line Loading @@ -619,6 +619,17 @@ <!-- rotation: 270 (rotate CW) --> <item>-25</item> <item>65</item> </integer-array> <!-- Indicate the name of the window orientation sensor type if present. A window orientation sensor produces values to be used in lieu of the typical, accelerometer based sensor. It must only produce integral values between 0 and 3, inclusive, with each one corresponding to a given rotation: 0: 0 degrees of rotation (natural) 1: 90 degrees of rotation (rotate CCW) 2: 180 degrees of rotation (reverse) 3: 270 degrees of rotation (rotate CW) --> <string name="config_orientationSensorType" translatable="false">@null</string> <!-- Lid switch behavior --> <!-- The number of degrees to rotate the display when the keyboard is open. Loading core/res/res/values/symbols.xml +1 −0 Original line number Diff line number Diff line Loading @@ -1547,6 +1547,7 @@ <java-symbol type="string" name="bugreport_title" /> <java-symbol type="string" name="bugreport_message" /> <java-symbol type="string" name="bugreport_status" /> <java-symbol type="string" name="config_orientationSensorType" /> <java-symbol type="string" name="faceunlock_multiple_failures" /> <java-symbol type="string" name="global_action_power_off" /> <java-symbol type="string" name="global_actions_airplane_mode_off_status" /> Loading services/core/java/com/android/server/policy/WindowOrientationListener.java +263 −45 Original line number Diff line number Diff line Loading @@ -24,10 +24,12 @@ import android.hardware.SensorManager; import android.os.Handler; import android.os.SystemClock; import android.os.SystemProperties; import android.text.TextUtils; import android.util.Slog; import java.io.PrintWriter; import java.util.Arrays; import java.util.List; /** * A special helper class used by the WindowManager Loading @@ -52,8 +54,9 @@ public abstract class WindowOrientationListener { private SensorManager mSensorManager; private boolean mEnabled; private int mRate; private String mSensorType; private Sensor mSensor; private SensorEventListenerImpl mSensorEventListener; private OrientationJudge mOrientationJudge; private int mCurrentRotation = -1; private final Object mLock = new Object(); Loading Loading @@ -84,11 +87,31 @@ public abstract class WindowOrientationListener { mHandler = handler; mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE); mRate = rate; mSensorType = context.getResources().getString( com.android.internal.R.string.config_orientationSensorType); if (!TextUtils.isEmpty(mSensorType)) { List<Sensor> sensors = mSensorManager.getSensorList(Sensor.TYPE_ALL); final int N = sensors.size(); for (int i = 0; i < N; i++) { Sensor sensor = sensors.get(i); if (mSensorType.equals(sensor.getStringType())) { mSensor = sensor; break; } } if (mSensor != null) { mOrientationJudge = new OrientationSensorJudge(); } } if (mOrientationJudge == null) { 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(context); mOrientationJudge = new AccelSensorJudge(context); } } } Loading @@ -106,8 +129,8 @@ public abstract class WindowOrientationListener { if (LOG) { Slog.d(TAG, "WindowOrientationListener enabled"); } mSensorEventListener.resetLocked(); mSensorManager.registerListener(mSensorEventListener, mSensor, mRate, mHandler); mOrientationJudge.resetLocked(); mSensorManager.registerListener(mOrientationJudge, mSensor, mRate, mHandler); mEnabled = true; } } Loading @@ -126,7 +149,7 @@ public abstract class WindowOrientationListener { if (LOG) { Slog.d(TAG, "WindowOrientationListener disabled"); } mSensorManager.unregisterListener(mSensorEventListener); mSensorManager.unregisterListener(mOrientationJudge); mEnabled = false; } } Loading @@ -134,8 +157,8 @@ public abstract class WindowOrientationListener { public void onTouchStart() { synchronized (mLock) { if (mSensorEventListener != null) { mSensorEventListener.onTouchStartLocked(); if (mOrientationJudge != null) { mOrientationJudge.onTouchStartLocked(); } } } Loading @@ -144,8 +167,8 @@ public abstract class WindowOrientationListener { long whenElapsedNanos = SystemClock.elapsedRealtimeNanos(); synchronized (mLock) { if (mSensorEventListener != null) { mSensorEventListener.onTouchEndLocked(whenElapsedNanos); if (mOrientationJudge != null) { mOrientationJudge.onTouchEndLocked(whenElapsedNanos); } } } Loading @@ -172,7 +195,7 @@ public abstract class WindowOrientationListener { public int getProposedRotation() { synchronized (mLock) { if (mEnabled) { return mSensorEventListener.getProposedRotationLocked(); return mOrientationJudge.getProposedRotationLocked(); } return -1; } Loading Loading @@ -205,15 +228,77 @@ public abstract class WindowOrientationListener { prefix += " "; pw.println(prefix + "mEnabled=" + mEnabled); pw.println(prefix + "mCurrentRotation=" + mCurrentRotation); pw.println(prefix + "mSensorType=" + mSensorType); pw.println(prefix + "mSensor=" + mSensor); pw.println(prefix + "mRate=" + mRate); if (mSensorEventListener != null) { mSensorEventListener.dumpLocked(pw, prefix); if (mOrientationJudge != null) { mOrientationJudge.dumpLocked(pw, prefix); } } } abstract class OrientationJudge implements SensorEventListener { // Number of nanoseconds per millisecond. protected static final long NANOS_PER_MS = 1000000; // Number of milliseconds per nano second. protected static final float MILLIS_PER_NANO = 0.000001f; // The minimum amount of time that must have elapsed since the screen was last touched // before the proposed rotation can change. protected static final long PROPOSAL_MIN_TIME_SINCE_TOUCH_END_NANOS = 500 * NANOS_PER_MS; /** * Gets the proposed rotation. * * This method only returns a rotation if the orientation listener is certain * of its proposal. If the rotation is indeterminate, returns -1. * * Should only be called when holding WindowOrientationListener lock. * * @return The proposed rotation, or -1 if unknown. */ public abstract int getProposedRotationLocked(); /** * Notifies the orientation judge that the screen is being touched. * * Should only be called when holding WindowOrientationListener lock. */ public abstract void onTouchStartLocked(); /** * Notifies the orientation judge that the screen is no longer being touched. * * Should only be called when holding WindowOrientationListener lock. * * @param whenElapsedNanos Given in the elapsed realtime nanos time base. */ public abstract void onTouchEndLocked(long whenElapsedNanos); /** * Resets the state of the judge. * * Should only be called when holding WindowOrientationListener lock. */ public abstract void resetLocked(); /** * Dumps internal state of the orientation judge. * * Should only be called when holding WindowOrientationListener lock. */ public abstract void dumpLocked(PrintWriter pw, String prefix); @Override public abstract void onAccuracyChanged(Sensor sensor, int accuracy); @Override public abstract void onSensorChanged(SensorEvent event); } /** * 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, Loading Loading @@ -252,13 +337,10 @@ public abstract class WindowOrientationListener { * See http://en.wikipedia.org/wiki/Low-pass_filter#Discrete-time_realization for * signal processing background. */ final class SensorEventListenerImpl implements SensorEventListener { final class AccelSensorJudge extends OrientationJudge { // We work with all angles in degrees in this class. private static final float RADIANS_TO_DEGREES = (float) (180 / Math.PI); // Number of nanoseconds per millisecond. private static final long NANOS_PER_MS = 1000000; // Indices into SensorEvent.values for the accelerometer sensor. private static final int ACCELEROMETER_DATA_X = 0; private static final int ACCELEROMETER_DATA_Y = 1; Loading Loading @@ -286,11 +368,6 @@ public abstract class WindowOrientationListener { private static final long PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS = 500 * NANOS_PER_MS; // The minimum amount of time that must have elapsed since the screen was last touched // before the proposed rotation can change. private static final long PROPOSAL_MIN_TIME_SINCE_TOUCH_END_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). Loading Loading @@ -434,7 +511,7 @@ public abstract class WindowOrientationListener { private long[] mTiltHistoryTimestampNanos = new long[TILT_HISTORY_SIZE]; private int mTiltHistoryIndex; public SensorEventListenerImpl(Context context) { public AccelSensorJudge(Context context) { // Load tilt tolerance configuration. int[] tiltTolerance = context.getResources().getIntArray( com.android.internal.R.array.config_autoRotationTiltTolerance); Loading @@ -455,11 +532,15 @@ public abstract class WindowOrientationListener { } } @Override public int getProposedRotationLocked() { return mProposedRotation; } @Override public void dumpLocked(PrintWriter pw, String prefix) { pw.println(prefix + "AccelSensorJudge"); prefix += " "; pw.println(prefix + "mProposedRotation=" + mProposedRotation); pw.println(prefix + "mPredictedRotation=" + mPredictedRotation); pw.println(prefix + "mLastFilteredX=" + mLastFilteredX); Loading Loading @@ -689,6 +770,33 @@ public abstract class WindowOrientationListener { } } @Override public void onTouchStartLocked() { mTouched = true; } @Override public void onTouchEndLocked(long whenElapsedNanos) { mTouched = false; mTouchEndedTimestampNanos = whenElapsedNanos; } @Override public void resetLocked() { mLastFilteredTimestampNanos = Long.MIN_VALUE; mProposedRotation = -1; mFlatTimestampNanos = Long.MIN_VALUE; mFlat = false; mSwingTimestampNanos = Long.MIN_VALUE; mSwinging = false; mAccelerationTimestampNanos = Long.MIN_VALUE; mAccelerating = false; mOverhead = false; clearPredictedRotationLocked(); clearTiltHistoryLocked(); } /** * Returns true if the tilt angle is acceptable for a given predicted rotation. */ Loading Loading @@ -787,20 +895,6 @@ public abstract class WindowOrientationListener { return true; } private void resetLocked() { mLastFilteredTimestampNanos = Long.MIN_VALUE; mProposedRotation = -1; mFlatTimestampNanos = Long.MIN_VALUE; mFlat = false; mSwingTimestampNanos = Long.MIN_VALUE; mSwinging = false; mAccelerationTimestampNanos = Long.MIN_VALUE; mAccelerating = false; mOverhead = false; clearPredictedRotationLocked(); clearTiltHistoryLocked(); } private void clearPredictedRotationLocked() { mPredictedRotation = -1; mPredictedRotationTimestampNanos = Long.MIN_VALUE; Loading Loading @@ -869,14 +963,138 @@ public abstract class WindowOrientationListener { private float remainingMS(long now, long until) { return now >= until ? 0 : (until - now) * 0.000001f; } } private void onTouchStartLocked() { mTouched = true; final class OrientationSensorJudge extends OrientationJudge { private boolean mTouching; private long mTouchEndedTimestampNanos = Long.MIN_VALUE; private int mProposedRotation = -1; private int mDesiredRotation = -1; private boolean mRotationEvaluationScheduled; @Override public int getProposedRotationLocked() { return mProposedRotation; } private void onTouchEndLocked(long whenElapsedNanos) { mTouched = false; @Override public void onTouchStartLocked() { mTouching = true; } @Override public void onTouchEndLocked(long whenElapsedNanos) { mTouching = false; mTouchEndedTimestampNanos = whenElapsedNanos; if (mDesiredRotation != mProposedRotation) { final long now = SystemClock.elapsedRealtimeNanos(); scheduleRotationEvaluationIfNecessaryLocked(now); } } @Override public void onSensorChanged(SensorEvent event) { synchronized (mLock) { mDesiredRotation = (int) event.values[0]; evaluateRotationChangeLocked(); } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } @Override public void dumpLocked(PrintWriter pw, String prefix) { pw.println(prefix + "OrientationSensorJudge"); prefix += " "; pw.println(prefix + "mDesiredRotation=" + mDesiredRotation); pw.println(prefix + "mProposedRotation=" + mProposedRotation); pw.println(prefix + "mTouching=" + mTouching); pw.println(prefix + "mTouchEndedTimestampNanos=" + mTouchEndedTimestampNanos); } @Override public void resetLocked() { mProposedRotation = -1; mDesiredRotation = -1; mTouching = false; mTouchEndedTimestampNanos = Long.MIN_VALUE; unscheduleRotationEvaluationLocked(); } public void evaluateRotationChangeLocked() { unscheduleRotationEvaluationLocked(); if (mDesiredRotation == mProposedRotation) { return; } final long now = SystemClock.elapsedRealtimeNanos(); if (isDesiredRotationAcceptableLocked(now)) { mProposedRotation = mDesiredRotation; onProposedRotationChanged(mProposedRotation); } else { scheduleRotationEvaluationIfNecessaryLocked(now); } } private boolean isDesiredRotationAcceptableLocked(long now) { if (mTouching) { return false; } if (now < mTouchEndedTimestampNanos + PROPOSAL_MIN_TIME_SINCE_TOUCH_END_NANOS) { return false; } return true; } private void scheduleRotationEvaluationIfNecessaryLocked(long now) { if (mRotationEvaluationScheduled || mDesiredRotation == mProposedRotation) { if (LOG) { Slog.d(TAG, "scheduleRotationEvaluationLocked: " + "ignoring, an evaluation is already scheduled or is unnecessary."); } return; } if (mTouching) { if (LOG) { Slog.d(TAG, "scheduleRotationEvaluationLocked: " + "ignoring, user is still touching the screen."); } return; } long timeOfNextPossibleRotationNanos = mTouchEndedTimestampNanos + PROPOSAL_MIN_TIME_SINCE_TOUCH_END_NANOS; if (now >= timeOfNextPossibleRotationNanos) { if (LOG) { Slog.d(TAG, "scheduleRotationEvaluationLocked: " + "ignoring, already past the next possible time of rotation."); } return; } // Use a delay instead of an absolute time since handlers are in uptime millis and we // use elapsed realtime. final long delayMs = (long) Math.ceil((timeOfNextPossibleRotationNanos - now) * MILLIS_PER_NANO); mHandler.postDelayed(mRotationEvaluator, delayMs); mRotationEvaluationScheduled = true; } private void unscheduleRotationEvaluationLocked() { if (!mRotationEvaluationScheduled) { return; } mHandler.removeCallbacks(mRotationEvaluator); mRotationEvaluationScheduled = false; } private Runnable mRotationEvaluator = new Runnable() { @Override public void run() { synchronized (mLock) { mRotationEvaluationScheduled = false; evaluateRotationChangeLocked(); } } }; } } Loading
core/res/res/values/config.xml +11 −0 Original line number Diff line number Diff line Loading @@ -619,6 +619,17 @@ <!-- rotation: 270 (rotate CW) --> <item>-25</item> <item>65</item> </integer-array> <!-- Indicate the name of the window orientation sensor type if present. A window orientation sensor produces values to be used in lieu of the typical, accelerometer based sensor. It must only produce integral values between 0 and 3, inclusive, with each one corresponding to a given rotation: 0: 0 degrees of rotation (natural) 1: 90 degrees of rotation (rotate CCW) 2: 180 degrees of rotation (reverse) 3: 270 degrees of rotation (rotate CW) --> <string name="config_orientationSensorType" translatable="false">@null</string> <!-- Lid switch behavior --> <!-- The number of degrees to rotate the display when the keyboard is open. Loading
core/res/res/values/symbols.xml +1 −0 Original line number Diff line number Diff line Loading @@ -1547,6 +1547,7 @@ <java-symbol type="string" name="bugreport_title" /> <java-symbol type="string" name="bugreport_message" /> <java-symbol type="string" name="bugreport_status" /> <java-symbol type="string" name="config_orientationSensorType" /> <java-symbol type="string" name="faceunlock_multiple_failures" /> <java-symbol type="string" name="global_action_power_off" /> <java-symbol type="string" name="global_actions_airplane_mode_off_status" /> Loading
services/core/java/com/android/server/policy/WindowOrientationListener.java +263 −45 Original line number Diff line number Diff line Loading @@ -24,10 +24,12 @@ import android.hardware.SensorManager; import android.os.Handler; import android.os.SystemClock; import android.os.SystemProperties; import android.text.TextUtils; import android.util.Slog; import java.io.PrintWriter; import java.util.Arrays; import java.util.List; /** * A special helper class used by the WindowManager Loading @@ -52,8 +54,9 @@ public abstract class WindowOrientationListener { private SensorManager mSensorManager; private boolean mEnabled; private int mRate; private String mSensorType; private Sensor mSensor; private SensorEventListenerImpl mSensorEventListener; private OrientationJudge mOrientationJudge; private int mCurrentRotation = -1; private final Object mLock = new Object(); Loading Loading @@ -84,11 +87,31 @@ public abstract class WindowOrientationListener { mHandler = handler; mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE); mRate = rate; mSensorType = context.getResources().getString( com.android.internal.R.string.config_orientationSensorType); if (!TextUtils.isEmpty(mSensorType)) { List<Sensor> sensors = mSensorManager.getSensorList(Sensor.TYPE_ALL); final int N = sensors.size(); for (int i = 0; i < N; i++) { Sensor sensor = sensors.get(i); if (mSensorType.equals(sensor.getStringType())) { mSensor = sensor; break; } } if (mSensor != null) { mOrientationJudge = new OrientationSensorJudge(); } } if (mOrientationJudge == null) { 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(context); mOrientationJudge = new AccelSensorJudge(context); } } } Loading @@ -106,8 +129,8 @@ public abstract class WindowOrientationListener { if (LOG) { Slog.d(TAG, "WindowOrientationListener enabled"); } mSensorEventListener.resetLocked(); mSensorManager.registerListener(mSensorEventListener, mSensor, mRate, mHandler); mOrientationJudge.resetLocked(); mSensorManager.registerListener(mOrientationJudge, mSensor, mRate, mHandler); mEnabled = true; } } Loading @@ -126,7 +149,7 @@ public abstract class WindowOrientationListener { if (LOG) { Slog.d(TAG, "WindowOrientationListener disabled"); } mSensorManager.unregisterListener(mSensorEventListener); mSensorManager.unregisterListener(mOrientationJudge); mEnabled = false; } } Loading @@ -134,8 +157,8 @@ public abstract class WindowOrientationListener { public void onTouchStart() { synchronized (mLock) { if (mSensorEventListener != null) { mSensorEventListener.onTouchStartLocked(); if (mOrientationJudge != null) { mOrientationJudge.onTouchStartLocked(); } } } Loading @@ -144,8 +167,8 @@ public abstract class WindowOrientationListener { long whenElapsedNanos = SystemClock.elapsedRealtimeNanos(); synchronized (mLock) { if (mSensorEventListener != null) { mSensorEventListener.onTouchEndLocked(whenElapsedNanos); if (mOrientationJudge != null) { mOrientationJudge.onTouchEndLocked(whenElapsedNanos); } } } Loading @@ -172,7 +195,7 @@ public abstract class WindowOrientationListener { public int getProposedRotation() { synchronized (mLock) { if (mEnabled) { return mSensorEventListener.getProposedRotationLocked(); return mOrientationJudge.getProposedRotationLocked(); } return -1; } Loading Loading @@ -205,15 +228,77 @@ public abstract class WindowOrientationListener { prefix += " "; pw.println(prefix + "mEnabled=" + mEnabled); pw.println(prefix + "mCurrentRotation=" + mCurrentRotation); pw.println(prefix + "mSensorType=" + mSensorType); pw.println(prefix + "mSensor=" + mSensor); pw.println(prefix + "mRate=" + mRate); if (mSensorEventListener != null) { mSensorEventListener.dumpLocked(pw, prefix); if (mOrientationJudge != null) { mOrientationJudge.dumpLocked(pw, prefix); } } } abstract class OrientationJudge implements SensorEventListener { // Number of nanoseconds per millisecond. protected static final long NANOS_PER_MS = 1000000; // Number of milliseconds per nano second. protected static final float MILLIS_PER_NANO = 0.000001f; // The minimum amount of time that must have elapsed since the screen was last touched // before the proposed rotation can change. protected static final long PROPOSAL_MIN_TIME_SINCE_TOUCH_END_NANOS = 500 * NANOS_PER_MS; /** * Gets the proposed rotation. * * This method only returns a rotation if the orientation listener is certain * of its proposal. If the rotation is indeterminate, returns -1. * * Should only be called when holding WindowOrientationListener lock. * * @return The proposed rotation, or -1 if unknown. */ public abstract int getProposedRotationLocked(); /** * Notifies the orientation judge that the screen is being touched. * * Should only be called when holding WindowOrientationListener lock. */ public abstract void onTouchStartLocked(); /** * Notifies the orientation judge that the screen is no longer being touched. * * Should only be called when holding WindowOrientationListener lock. * * @param whenElapsedNanos Given in the elapsed realtime nanos time base. */ public abstract void onTouchEndLocked(long whenElapsedNanos); /** * Resets the state of the judge. * * Should only be called when holding WindowOrientationListener lock. */ public abstract void resetLocked(); /** * Dumps internal state of the orientation judge. * * Should only be called when holding WindowOrientationListener lock. */ public abstract void dumpLocked(PrintWriter pw, String prefix); @Override public abstract void onAccuracyChanged(Sensor sensor, int accuracy); @Override public abstract void onSensorChanged(SensorEvent event); } /** * 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, Loading Loading @@ -252,13 +337,10 @@ public abstract class WindowOrientationListener { * See http://en.wikipedia.org/wiki/Low-pass_filter#Discrete-time_realization for * signal processing background. */ final class SensorEventListenerImpl implements SensorEventListener { final class AccelSensorJudge extends OrientationJudge { // We work with all angles in degrees in this class. private static final float RADIANS_TO_DEGREES = (float) (180 / Math.PI); // Number of nanoseconds per millisecond. private static final long NANOS_PER_MS = 1000000; // Indices into SensorEvent.values for the accelerometer sensor. private static final int ACCELEROMETER_DATA_X = 0; private static final int ACCELEROMETER_DATA_Y = 1; Loading Loading @@ -286,11 +368,6 @@ public abstract class WindowOrientationListener { private static final long PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS = 500 * NANOS_PER_MS; // The minimum amount of time that must have elapsed since the screen was last touched // before the proposed rotation can change. private static final long PROPOSAL_MIN_TIME_SINCE_TOUCH_END_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). Loading Loading @@ -434,7 +511,7 @@ public abstract class WindowOrientationListener { private long[] mTiltHistoryTimestampNanos = new long[TILT_HISTORY_SIZE]; private int mTiltHistoryIndex; public SensorEventListenerImpl(Context context) { public AccelSensorJudge(Context context) { // Load tilt tolerance configuration. int[] tiltTolerance = context.getResources().getIntArray( com.android.internal.R.array.config_autoRotationTiltTolerance); Loading @@ -455,11 +532,15 @@ public abstract class WindowOrientationListener { } } @Override public int getProposedRotationLocked() { return mProposedRotation; } @Override public void dumpLocked(PrintWriter pw, String prefix) { pw.println(prefix + "AccelSensorJudge"); prefix += " "; pw.println(prefix + "mProposedRotation=" + mProposedRotation); pw.println(prefix + "mPredictedRotation=" + mPredictedRotation); pw.println(prefix + "mLastFilteredX=" + mLastFilteredX); Loading Loading @@ -689,6 +770,33 @@ public abstract class WindowOrientationListener { } } @Override public void onTouchStartLocked() { mTouched = true; } @Override public void onTouchEndLocked(long whenElapsedNanos) { mTouched = false; mTouchEndedTimestampNanos = whenElapsedNanos; } @Override public void resetLocked() { mLastFilteredTimestampNanos = Long.MIN_VALUE; mProposedRotation = -1; mFlatTimestampNanos = Long.MIN_VALUE; mFlat = false; mSwingTimestampNanos = Long.MIN_VALUE; mSwinging = false; mAccelerationTimestampNanos = Long.MIN_VALUE; mAccelerating = false; mOverhead = false; clearPredictedRotationLocked(); clearTiltHistoryLocked(); } /** * Returns true if the tilt angle is acceptable for a given predicted rotation. */ Loading Loading @@ -787,20 +895,6 @@ public abstract class WindowOrientationListener { return true; } private void resetLocked() { mLastFilteredTimestampNanos = Long.MIN_VALUE; mProposedRotation = -1; mFlatTimestampNanos = Long.MIN_VALUE; mFlat = false; mSwingTimestampNanos = Long.MIN_VALUE; mSwinging = false; mAccelerationTimestampNanos = Long.MIN_VALUE; mAccelerating = false; mOverhead = false; clearPredictedRotationLocked(); clearTiltHistoryLocked(); } private void clearPredictedRotationLocked() { mPredictedRotation = -1; mPredictedRotationTimestampNanos = Long.MIN_VALUE; Loading Loading @@ -869,14 +963,138 @@ public abstract class WindowOrientationListener { private float remainingMS(long now, long until) { return now >= until ? 0 : (until - now) * 0.000001f; } } private void onTouchStartLocked() { mTouched = true; final class OrientationSensorJudge extends OrientationJudge { private boolean mTouching; private long mTouchEndedTimestampNanos = Long.MIN_VALUE; private int mProposedRotation = -1; private int mDesiredRotation = -1; private boolean mRotationEvaluationScheduled; @Override public int getProposedRotationLocked() { return mProposedRotation; } private void onTouchEndLocked(long whenElapsedNanos) { mTouched = false; @Override public void onTouchStartLocked() { mTouching = true; } @Override public void onTouchEndLocked(long whenElapsedNanos) { mTouching = false; mTouchEndedTimestampNanos = whenElapsedNanos; if (mDesiredRotation != mProposedRotation) { final long now = SystemClock.elapsedRealtimeNanos(); scheduleRotationEvaluationIfNecessaryLocked(now); } } @Override public void onSensorChanged(SensorEvent event) { synchronized (mLock) { mDesiredRotation = (int) event.values[0]; evaluateRotationChangeLocked(); } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } @Override public void dumpLocked(PrintWriter pw, String prefix) { pw.println(prefix + "OrientationSensorJudge"); prefix += " "; pw.println(prefix + "mDesiredRotation=" + mDesiredRotation); pw.println(prefix + "mProposedRotation=" + mProposedRotation); pw.println(prefix + "mTouching=" + mTouching); pw.println(prefix + "mTouchEndedTimestampNanos=" + mTouchEndedTimestampNanos); } @Override public void resetLocked() { mProposedRotation = -1; mDesiredRotation = -1; mTouching = false; mTouchEndedTimestampNanos = Long.MIN_VALUE; unscheduleRotationEvaluationLocked(); } public void evaluateRotationChangeLocked() { unscheduleRotationEvaluationLocked(); if (mDesiredRotation == mProposedRotation) { return; } final long now = SystemClock.elapsedRealtimeNanos(); if (isDesiredRotationAcceptableLocked(now)) { mProposedRotation = mDesiredRotation; onProposedRotationChanged(mProposedRotation); } else { scheduleRotationEvaluationIfNecessaryLocked(now); } } private boolean isDesiredRotationAcceptableLocked(long now) { if (mTouching) { return false; } if (now < mTouchEndedTimestampNanos + PROPOSAL_MIN_TIME_SINCE_TOUCH_END_NANOS) { return false; } return true; } private void scheduleRotationEvaluationIfNecessaryLocked(long now) { if (mRotationEvaluationScheduled || mDesiredRotation == mProposedRotation) { if (LOG) { Slog.d(TAG, "scheduleRotationEvaluationLocked: " + "ignoring, an evaluation is already scheduled or is unnecessary."); } return; } if (mTouching) { if (LOG) { Slog.d(TAG, "scheduleRotationEvaluationLocked: " + "ignoring, user is still touching the screen."); } return; } long timeOfNextPossibleRotationNanos = mTouchEndedTimestampNanos + PROPOSAL_MIN_TIME_SINCE_TOUCH_END_NANOS; if (now >= timeOfNextPossibleRotationNanos) { if (LOG) { Slog.d(TAG, "scheduleRotationEvaluationLocked: " + "ignoring, already past the next possible time of rotation."); } return; } // Use a delay instead of an absolute time since handlers are in uptime millis and we // use elapsed realtime. final long delayMs = (long) Math.ceil((timeOfNextPossibleRotationNanos - now) * MILLIS_PER_NANO); mHandler.postDelayed(mRotationEvaluator, delayMs); mRotationEvaluationScheduled = true; } private void unscheduleRotationEvaluationLocked() { if (!mRotationEvaluationScheduled) { return; } mHandler.removeCallbacks(mRotationEvaluator); mRotationEvaluationScheduled = false; } private Runnable mRotationEvaluator = new Runnable() { @Override public void run() { synchronized (mLock) { mRotationEvaluationScheduled = false; evaluateRotationChangeLocked(); } } }; } }