/policy/src/com/android/internal/policy/impl/WindowOrientationListener.java

https://github.com/aizuzi/platform_frameworks_base · Java · 733 lines · 392 code · 71 blank · 270 comment · 88 complexity · d97f103ad6632f114fa1dcabb8400de4 MD5 · raw file

  1. /*
  2. * Copyright (C) 2008 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.android.internal.policy.impl;
  17. import android.content.Context;
  18. import android.hardware.Sensor;
  19. import android.hardware.SensorEvent;
  20. import android.hardware.SensorEventListener;
  21. import android.hardware.SensorManager;
  22. import android.os.Handler;
  23. import android.os.SystemProperties;
  24. import android.util.FloatMath;
  25. import android.util.Log;
  26. import android.util.Slog;
  27. /**
  28. * A special helper class used by the WindowManager
  29. * for receiving notifications from the SensorManager when
  30. * the orientation of the device has changed.
  31. *
  32. * NOTE: If changing anything here, please run the API demo
  33. * "App/Activity/Screen Orientation" to ensure that all orientation
  34. * modes still work correctly.
  35. *
  36. * You can also visualize the behavior of the WindowOrientationListener.
  37. * Refer to frameworks/base/tools/orientationplot/README.txt for details.
  38. *
  39. * @hide
  40. */
  41. public abstract class WindowOrientationListener {
  42. private static final String TAG = "WindowOrientationListener";
  43. private static final boolean LOG = SystemProperties.getBoolean(
  44. "debug.orientation.log", false);
  45. private static final boolean USE_GRAVITY_SENSOR = false;
  46. private Handler mHandler;
  47. private SensorManager mSensorManager;
  48. private boolean mEnabled;
  49. private int mRate;
  50. private Sensor mSensor;
  51. private SensorEventListenerImpl mSensorEventListener;
  52. private int mCurrentRotation = -1;
  53. private final Object mLock = new Object();
  54. /**
  55. * Creates a new WindowOrientationListener.
  56. *
  57. * @param context for the WindowOrientationListener.
  58. * @param handler Provides the Looper for receiving sensor updates.
  59. */
  60. public WindowOrientationListener(Context context, Handler handler) {
  61. this(context, handler, SensorManager.SENSOR_DELAY_UI);
  62. }
  63. /**
  64. * Creates a new WindowOrientationListener.
  65. *
  66. * @param context for the WindowOrientationListener.
  67. * @param handler Provides the Looper for receiving sensor updates.
  68. * @param rate at which sensor events are processed (see also
  69. * {@link android.hardware.SensorManager SensorManager}). Use the default
  70. * value of {@link android.hardware.SensorManager#SENSOR_DELAY_NORMAL
  71. * SENSOR_DELAY_NORMAL} for simple screen orientation change detection.
  72. *
  73. * This constructor is private since no one uses it.
  74. */
  75. private WindowOrientationListener(Context context, Handler handler, int rate) {
  76. mHandler = handler;
  77. mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
  78. mRate = rate;
  79. mSensor = mSensorManager.getDefaultSensor(USE_GRAVITY_SENSOR
  80. ? Sensor.TYPE_GRAVITY : Sensor.TYPE_ACCELEROMETER);
  81. if (mSensor != null) {
  82. // Create listener only if sensors do exist
  83. mSensorEventListener = new SensorEventListenerImpl();
  84. }
  85. }
  86. /**
  87. * Enables the WindowOrientationListener so it will monitor the sensor and call
  88. * {@link #onProposedRotationChanged(int)} when the device orientation changes.
  89. */
  90. public void enable() {
  91. synchronized (mLock) {
  92. if (mSensor == null) {
  93. Log.w(TAG, "Cannot detect sensors. Not enabled");
  94. return;
  95. }
  96. if (mEnabled == false) {
  97. if (LOG) {
  98. Log.d(TAG, "WindowOrientationListener enabled");
  99. }
  100. mSensorEventListener.resetLocked();
  101. mSensorManager.registerListener(mSensorEventListener, mSensor, mRate, mHandler);
  102. mEnabled = true;
  103. }
  104. }
  105. }
  106. /**
  107. * Disables the WindowOrientationListener.
  108. */
  109. public void disable() {
  110. synchronized (mLock) {
  111. if (mSensor == null) {
  112. Log.w(TAG, "Cannot detect sensors. Invalid disable");
  113. return;
  114. }
  115. if (mEnabled == true) {
  116. if (LOG) {
  117. Log.d(TAG, "WindowOrientationListener disabled");
  118. }
  119. mSensorManager.unregisterListener(mSensorEventListener);
  120. mEnabled = false;
  121. }
  122. }
  123. }
  124. /**
  125. * Sets the current rotation.
  126. *
  127. * @param rotation The current rotation.
  128. */
  129. public void setCurrentRotation(int rotation) {
  130. synchronized (mLock) {
  131. mCurrentRotation = rotation;
  132. }
  133. }
  134. /**
  135. * Gets the proposed rotation.
  136. *
  137. * This method only returns a rotation if the orientation listener is certain
  138. * of its proposal. If the rotation is indeterminate, returns -1.
  139. *
  140. * @return The proposed rotation, or -1 if unknown.
  141. */
  142. public int getProposedRotation() {
  143. synchronized (mLock) {
  144. if (mEnabled) {
  145. return mSensorEventListener.getProposedRotationLocked();
  146. }
  147. return -1;
  148. }
  149. }
  150. /**
  151. * Returns true if sensor is enabled and false otherwise
  152. */
  153. public boolean canDetectOrientation() {
  154. synchronized (mLock) {
  155. return mSensor != null;
  156. }
  157. }
  158. /**
  159. * Called when the rotation view of the device has changed.
  160. *
  161. * This method is called whenever the orientation becomes certain of an orientation.
  162. * It is called each time the orientation determination transitions from being
  163. * uncertain to being certain again, even if it is the same orientation as before.
  164. *
  165. * @param rotation The new orientation of the device, one of the Surface.ROTATION_* constants.
  166. * @see android.view.Surface
  167. */
  168. public abstract void onProposedRotationChanged(int rotation);
  169. /**
  170. * This class filters the raw accelerometer data and tries to detect actual changes in
  171. * orientation. This is a very ill-defined problem so there are a lot of tweakable parameters,
  172. * but here's the outline:
  173. *
  174. * - Low-pass filter the accelerometer vector in cartesian coordinates. We do it in
  175. * cartesian space because the orientation calculations are sensitive to the
  176. * absolute magnitude of the acceleration. In particular, there are singularities
  177. * in the calculation as the magnitude approaches 0. By performing the low-pass
  178. * filtering early, we can eliminate most spurious high-frequency impulses due to noise.
  179. *
  180. * - Convert the acceleromter vector from cartesian to spherical coordinates.
  181. * Since we're dealing with rotation of the device, this is the sensible coordinate
  182. * system to work in. The zenith direction is the Z-axis, the direction the screen
  183. * is facing. The radial distance is referred to as the magnitude below.
  184. * The elevation angle is referred to as the "tilt" below.
  185. * The azimuth angle is referred to as the "orientation" below (and the azimuth axis is
  186. * the Y-axis).
  187. * See http://en.wikipedia.org/wiki/Spherical_coordinate_system for reference.
  188. *
  189. * - If the tilt angle is too close to horizontal (near 90 or -90 degrees), do nothing.
  190. * The orientation angle is not meaningful when the device is nearly horizontal.
  191. * The tilt angle thresholds are set differently for each orientation and different
  192. * limits are applied when the device is facing down as opposed to when it is facing
  193. * forward or facing up.
  194. *
  195. * - When the orientation angle reaches a certain threshold, consider transitioning
  196. * to the corresponding orientation. These thresholds have some hysteresis built-in
  197. * to avoid oscillations between adjacent orientations.
  198. *
  199. * - Wait for the device to settle for a little bit. Once that happens, issue the
  200. * new orientation proposal.
  201. *
  202. * Details are explained inline.
  203. *
  204. * See http://en.wikipedia.org/wiki/Low-pass_filter#Discrete-time_realization for
  205. * signal processing background.
  206. */
  207. final class SensorEventListenerImpl implements SensorEventListener {
  208. // We work with all angles in degrees in this class.
  209. private static final float RADIANS_TO_DEGREES = (float) (180 / Math.PI);
  210. // Number of nanoseconds per millisecond.
  211. private static final long NANOS_PER_MS = 1000000;
  212. // Indices into SensorEvent.values for the accelerometer sensor.
  213. private static final int ACCELEROMETER_DATA_X = 0;
  214. private static final int ACCELEROMETER_DATA_Y = 1;
  215. private static final int ACCELEROMETER_DATA_Z = 2;
  216. // The minimum amount of time that a predicted rotation must be stable before it
  217. // is accepted as a valid rotation proposal. This value can be quite small because
  218. // the low-pass filter already suppresses most of the noise so we're really just
  219. // looking for quick confirmation that the last few samples are in agreement as to
  220. // the desired orientation.
  221. private static final long PROPOSAL_SETTLE_TIME_NANOS = 40 * NANOS_PER_MS;
  222. // The minimum amount of time that must have elapsed since the device last exited
  223. // the flat state (time since it was picked up) before the proposed rotation
  224. // can change.
  225. private static final long PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS = 500 * NANOS_PER_MS;
  226. // The minimum amount of time that must have elapsed since the device stopped
  227. // swinging (time since device appeared to be in the process of being put down
  228. // or put away into a pocket) before the proposed rotation can change.
  229. private static final long PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS = 300 * NANOS_PER_MS;
  230. // The minimum amount of time that must have elapsed since the device stopped
  231. // undergoing external acceleration before the proposed rotation can change.
  232. private static final long PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS =
  233. 500 * NANOS_PER_MS;
  234. // If the tilt angle remains greater than the specified angle for a minimum of
  235. // the specified time, then the device is deemed to be lying flat
  236. // (just chillin' on a table).
  237. private static final float FLAT_ANGLE = 75;
  238. private static final long FLAT_TIME_NANOS = 1000 * NANOS_PER_MS;
  239. // If the tilt angle has increased by at least delta degrees within the specified amount
  240. // of time, then the device is deemed to be swinging away from the user
  241. // down towards flat (tilt = 90).
  242. private static final float SWING_AWAY_ANGLE_DELTA = 20;
  243. private static final long SWING_TIME_NANOS = 300 * NANOS_PER_MS;
  244. // The maximum sample inter-arrival time in milliseconds.
  245. // If the acceleration samples are further apart than this amount in time, we reset the
  246. // state of the low-pass filter and orientation properties. This helps to handle
  247. // boundary conditions when the device is turned on, wakes from suspend or there is
  248. // a significant gap in samples.
  249. private static final long MAX_FILTER_DELTA_TIME_NANOS = 1000 * NANOS_PER_MS;
  250. // The acceleration filter time constant.
  251. //
  252. // This time constant is used to tune the acceleration filter such that
  253. // impulses and vibrational noise (think car dock) is suppressed before we
  254. // try to calculate the tilt and orientation angles.
  255. //
  256. // The filter time constant is related to the filter cutoff frequency, which is the
  257. // frequency at which signals are attenuated by 3dB (half the passband power).
  258. // Each successive octave beyond this frequency is attenuated by an additional 6dB.
  259. //
  260. // Given a time constant t in seconds, the filter cutoff frequency Fc in Hertz
  261. // is given by Fc = 1 / (2pi * t).
  262. //
  263. // The higher the time constant, the lower the cutoff frequency, so more noise
  264. // will be suppressed.
  265. //
  266. // Filtering adds latency proportional the time constant (inversely proportional
  267. // to the cutoff frequency) so we don't want to make the time constant too
  268. // large or we can lose responsiveness. Likewise we don't want to make it too
  269. // small or we do a poor job suppressing acceleration spikes.
  270. // Empirically, 100ms seems to be too small and 500ms is too large.
  271. private static final float FILTER_TIME_CONSTANT_MS = 200.0f;
  272. /* State for orientation detection. */
  273. // Thresholds for minimum and maximum allowable deviation from gravity.
  274. //
  275. // If the device is undergoing external acceleration (being bumped, in a car
  276. // that is turning around a corner or a plane taking off) then the magnitude
  277. // may be substantially more or less than gravity. This can skew our orientation
  278. // detection by making us think that up is pointed in a different direction.
  279. //
  280. // Conversely, if the device is in freefall, then there will be no gravity to
  281. // measure at all. This is problematic because we cannot detect the orientation
  282. // without gravity to tell us which way is up. A magnitude near 0 produces
  283. // singularities in the tilt and orientation calculations.
  284. //
  285. // In both cases, we postpone choosing an orientation.
  286. //
  287. // However, we need to tolerate some acceleration because the angular momentum
  288. // of turning the device can skew the observed acceleration for a short period of time.
  289. private static final float NEAR_ZERO_MAGNITUDE = 1; // m/s^2
  290. private static final float ACCELERATION_TOLERANCE = 4; // m/s^2
  291. private static final float MIN_ACCELERATION_MAGNITUDE =
  292. SensorManager.STANDARD_GRAVITY - ACCELERATION_TOLERANCE;
  293. private static final float MAX_ACCELERATION_MAGNITUDE =
  294. SensorManager.STANDARD_GRAVITY + ACCELERATION_TOLERANCE;
  295. // Maximum absolute tilt angle at which to consider orientation data. Beyond this (i.e.
  296. // when screen is facing the sky or ground), we completely ignore orientation data.
  297. private static final int MAX_TILT = 75;
  298. // The tilt angle range in degrees for each orientation.
  299. // Beyond these tilt angles, we don't even consider transitioning into the
  300. // specified orientation. We place more stringent requirements on unnatural
  301. // orientations than natural ones to make it less likely to accidentally transition
  302. // into those states.
  303. // The first value of each pair is negative so it applies a limit when the device is
  304. // facing down (overhead reading in bed).
  305. // The second value of each pair is positive so it applies a limit when the device is
  306. // facing up (resting on a table).
  307. // The ideal tilt angle is 0 (when the device is vertical) so the limits establish
  308. // how close to vertical the device must be in order to change orientation.
  309. private final int[][] TILT_TOLERANCE = new int[][] {
  310. /* ROTATION_0 */ { -25, 70 },
  311. /* ROTATION_90 */ { -25, 65 },
  312. /* ROTATION_180 */ { -25, 60 },
  313. /* ROTATION_270 */ { -25, 65 }
  314. };
  315. // The gap angle in degrees between adjacent orientation angles for hysteresis.
  316. // This creates a "dead zone" between the current orientation and a proposed
  317. // adjacent orientation. No orientation proposal is made when the orientation
  318. // angle is within the gap between the current orientation and the adjacent
  319. // orientation.
  320. private static final int ADJACENT_ORIENTATION_ANGLE_GAP = 45;
  321. // Timestamp and value of the last accelerometer sample.
  322. private long mLastFilteredTimestampNanos;
  323. private float mLastFilteredX, mLastFilteredY, mLastFilteredZ;
  324. // The last proposed rotation, -1 if unknown.
  325. private int mProposedRotation;
  326. // Value of the current predicted rotation, -1 if unknown.
  327. private int mPredictedRotation;
  328. // Timestamp of when the predicted rotation most recently changed.
  329. private long mPredictedRotationTimestampNanos;
  330. // Timestamp when the device last appeared to be flat for sure (the flat delay elapsed).
  331. private long mFlatTimestampNanos;
  332. // Timestamp when the device last appeared to be swinging.
  333. private long mSwingTimestampNanos;
  334. // Timestamp when the device last appeared to be undergoing external acceleration.
  335. private long mAccelerationTimestampNanos;
  336. // History of observed tilt angles.
  337. private static final int TILT_HISTORY_SIZE = 40;
  338. private float[] mTiltHistory = new float[TILT_HISTORY_SIZE];
  339. private long[] mTiltHistoryTimestampNanos = new long[TILT_HISTORY_SIZE];
  340. private int mTiltHistoryIndex;
  341. public int getProposedRotationLocked() {
  342. return mProposedRotation;
  343. }
  344. @Override
  345. public void onAccuracyChanged(Sensor sensor, int accuracy) {
  346. }
  347. @Override
  348. public void onSensorChanged(SensorEvent event) {
  349. int proposedRotation;
  350. int oldProposedRotation;
  351. synchronized (mLock) {
  352. // The vector given in the SensorEvent points straight up (towards the sky) under
  353. // ideal conditions (the phone is not accelerating). I'll call this up vector
  354. // elsewhere.
  355. float x = event.values[ACCELEROMETER_DATA_X];
  356. float y = event.values[ACCELEROMETER_DATA_Y];
  357. float z = event.values[ACCELEROMETER_DATA_Z];
  358. if (LOG) {
  359. Slog.v(TAG, "Raw acceleration vector: "
  360. + "x=" + x + ", y=" + y + ", z=" + z
  361. + ", magnitude=" + FloatMath.sqrt(x * x + y * y + z * z));
  362. }
  363. // Apply a low-pass filter to the acceleration up vector in cartesian space.
  364. // Reset the orientation listener state if the samples are too far apart in time
  365. // or when we see values of (0, 0, 0) which indicates that we polled the
  366. // accelerometer too soon after turning it on and we don't have any data yet.
  367. final long now = event.timestamp;
  368. final long then = mLastFilteredTimestampNanos;
  369. final float timeDeltaMS = (now - then) * 0.000001f;
  370. final boolean skipSample;
  371. if (now < then
  372. || now > then + MAX_FILTER_DELTA_TIME_NANOS
  373. || (x == 0 && y == 0 && z == 0)) {
  374. if (LOG) {
  375. Slog.v(TAG, "Resetting orientation listener.");
  376. }
  377. resetLocked();
  378. skipSample = true;
  379. } else {
  380. final float alpha = timeDeltaMS / (FILTER_TIME_CONSTANT_MS + timeDeltaMS);
  381. x = alpha * (x - mLastFilteredX) + mLastFilteredX;
  382. y = alpha * (y - mLastFilteredY) + mLastFilteredY;
  383. z = alpha * (z - mLastFilteredZ) + mLastFilteredZ;
  384. if (LOG) {
  385. Slog.v(TAG, "Filtered acceleration vector: "
  386. + "x=" + x + ", y=" + y + ", z=" + z
  387. + ", magnitude=" + FloatMath.sqrt(x * x + y * y + z * z));
  388. }
  389. skipSample = false;
  390. }
  391. mLastFilteredTimestampNanos = now;
  392. mLastFilteredX = x;
  393. mLastFilteredY = y;
  394. mLastFilteredZ = z;
  395. boolean isAccelerating = false;
  396. boolean isFlat = false;
  397. boolean isSwinging = false;
  398. if (!skipSample) {
  399. // Calculate the magnitude of the acceleration vector.
  400. final float magnitude = FloatMath.sqrt(x * x + y * y + z * z);
  401. if (magnitude < NEAR_ZERO_MAGNITUDE) {
  402. if (LOG) {
  403. Slog.v(TAG, "Ignoring sensor data, magnitude too close to zero.");
  404. }
  405. clearPredictedRotationLocked();
  406. } else {
  407. // Determine whether the device appears to be undergoing external
  408. // acceleration.
  409. if (isAcceleratingLocked(magnitude)) {
  410. isAccelerating = true;
  411. mAccelerationTimestampNanos = now;
  412. }
  413. // Calculate the tilt angle.
  414. // This is the angle between the up vector and the x-y plane (the plane of
  415. // the screen) in a range of [-90, 90] degrees.
  416. // -90 degrees: screen horizontal and facing the ground (overhead)
  417. // 0 degrees: screen vertical
  418. // 90 degrees: screen horizontal and facing the sky (on table)
  419. final int tiltAngle = (int) Math.round(
  420. Math.asin(z / magnitude) * RADIANS_TO_DEGREES);
  421. addTiltHistoryEntryLocked(now, tiltAngle);
  422. // Determine whether the device appears to be flat or swinging.
  423. if (isFlatLocked(now)) {
  424. isFlat = true;
  425. mFlatTimestampNanos = now;
  426. }
  427. if (isSwingingLocked(now, tiltAngle)) {
  428. isSwinging = true;
  429. mSwingTimestampNanos = now;
  430. }
  431. // If the tilt angle is too close to horizontal then we cannot determine
  432. // the orientation angle of the screen.
  433. if (Math.abs(tiltAngle) > MAX_TILT) {
  434. if (LOG) {
  435. Slog.v(TAG, "Ignoring sensor data, tilt angle too high: "
  436. + "tiltAngle=" + tiltAngle);
  437. }
  438. clearPredictedRotationLocked();
  439. } else {
  440. // Calculate the orientation angle.
  441. // This is the angle between the x-y projection of the up vector onto
  442. // the +y-axis, increasing clockwise in a range of [0, 360] degrees.
  443. int orientationAngle = (int) Math.round(
  444. -Math.atan2(-x, y) * RADIANS_TO_DEGREES);
  445. if (orientationAngle < 0) {
  446. // atan2 returns [-180, 180]; normalize to [0, 360]
  447. orientationAngle += 360;
  448. }
  449. // Find the nearest rotation.
  450. int nearestRotation = (orientationAngle + 45) / 90;
  451. if (nearestRotation == 4) {
  452. nearestRotation = 0;
  453. }
  454. // Determine the predicted orientation.
  455. if (isTiltAngleAcceptableLocked(nearestRotation, tiltAngle)
  456. && isOrientationAngleAcceptableLocked(nearestRotation,
  457. orientationAngle)) {
  458. updatePredictedRotationLocked(now, nearestRotation);
  459. if (LOG) {
  460. Slog.v(TAG, "Predicted: "
  461. + "tiltAngle=" + tiltAngle
  462. + ", orientationAngle=" + orientationAngle
  463. + ", predictedRotation=" + mPredictedRotation
  464. + ", predictedRotationAgeMS="
  465. + ((now - mPredictedRotationTimestampNanos)
  466. * 0.000001f));
  467. }
  468. } else {
  469. if (LOG) {
  470. Slog.v(TAG, "Ignoring sensor data, no predicted rotation: "
  471. + "tiltAngle=" + tiltAngle
  472. + ", orientationAngle=" + orientationAngle);
  473. }
  474. clearPredictedRotationLocked();
  475. }
  476. }
  477. }
  478. }
  479. // Determine new proposed rotation.
  480. oldProposedRotation = mProposedRotation;
  481. if (mPredictedRotation < 0 || isPredictedRotationAcceptableLocked(now)) {
  482. mProposedRotation = mPredictedRotation;
  483. }
  484. proposedRotation = mProposedRotation;
  485. // Write final statistics about where we are in the orientation detection process.
  486. if (LOG) {
  487. Slog.v(TAG, "Result: currentRotation=" + mCurrentRotation
  488. + ", proposedRotation=" + proposedRotation
  489. + ", predictedRotation=" + mPredictedRotation
  490. + ", timeDeltaMS=" + timeDeltaMS
  491. + ", isAccelerating=" + isAccelerating
  492. + ", isFlat=" + isFlat
  493. + ", isSwinging=" + isSwinging
  494. + ", timeUntilSettledMS=" + remainingMS(now,
  495. mPredictedRotationTimestampNanos + PROPOSAL_SETTLE_TIME_NANOS)
  496. + ", timeUntilAccelerationDelayExpiredMS=" + remainingMS(now,
  497. mAccelerationTimestampNanos + PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS)
  498. + ", timeUntilFlatDelayExpiredMS=" + remainingMS(now,
  499. mFlatTimestampNanos + PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS)
  500. + ", timeUntilSwingDelayExpiredMS=" + remainingMS(now,
  501. mSwingTimestampNanos + PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS));
  502. }
  503. }
  504. // Tell the listener.
  505. if (proposedRotation != oldProposedRotation && proposedRotation >= 0) {
  506. if (LOG) {
  507. Slog.v(TAG, "Proposed rotation changed! proposedRotation=" + proposedRotation
  508. + ", oldProposedRotation=" + oldProposedRotation);
  509. }
  510. onProposedRotationChanged(proposedRotation);
  511. }
  512. }
  513. /**
  514. * Returns true if the tilt angle is acceptable for a given predicted rotation.
  515. */
  516. private boolean isTiltAngleAcceptableLocked(int rotation, int tiltAngle) {
  517. return tiltAngle >= TILT_TOLERANCE[rotation][0]
  518. && tiltAngle <= TILT_TOLERANCE[rotation][1];
  519. }
  520. /**
  521. * Returns true if the orientation angle is acceptable for a given predicted rotation.
  522. *
  523. * This function takes into account the gap between adjacent orientations
  524. * for hysteresis.
  525. */
  526. private boolean isOrientationAngleAcceptableLocked(int rotation, int orientationAngle) {
  527. // If there is no current rotation, then there is no gap.
  528. // The gap is used only to introduce hysteresis among advertised orientation
  529. // changes to avoid flapping.
  530. final int currentRotation = mCurrentRotation;
  531. if (currentRotation >= 0) {
  532. // If the specified rotation is the same or is counter-clockwise adjacent
  533. // to the current rotation, then we set a lower bound on the orientation angle.
  534. // For example, if currentRotation is ROTATION_0 and proposed is ROTATION_90,
  535. // then we want to check orientationAngle > 45 + GAP / 2.
  536. if (rotation == currentRotation
  537. || rotation == (currentRotation + 1) % 4) {
  538. int lowerBound = rotation * 90 - 45
  539. + ADJACENT_ORIENTATION_ANGLE_GAP / 2;
  540. if (rotation == 0) {
  541. if (orientationAngle >= 315 && orientationAngle < lowerBound + 360) {
  542. return false;
  543. }
  544. } else {
  545. if (orientationAngle < lowerBound) {
  546. return false;
  547. }
  548. }
  549. }
  550. // If the specified rotation is the same or is clockwise adjacent,
  551. // then we set an upper bound on the orientation angle.
  552. // For example, if currentRotation is ROTATION_0 and rotation is ROTATION_270,
  553. // then we want to check orientationAngle < 315 - GAP / 2.
  554. if (rotation == currentRotation
  555. || rotation == (currentRotation + 3) % 4) {
  556. int upperBound = rotation * 90 + 45
  557. - ADJACENT_ORIENTATION_ANGLE_GAP / 2;
  558. if (rotation == 0) {
  559. if (orientationAngle <= 45 && orientationAngle > upperBound) {
  560. return false;
  561. }
  562. } else {
  563. if (orientationAngle > upperBound) {
  564. return false;
  565. }
  566. }
  567. }
  568. }
  569. return true;
  570. }
  571. /**
  572. * Returns true if the predicted rotation is ready to be advertised as a
  573. * proposed rotation.
  574. */
  575. private boolean isPredictedRotationAcceptableLocked(long now) {
  576. // The predicted rotation must have settled long enough.
  577. if (now < mPredictedRotationTimestampNanos + PROPOSAL_SETTLE_TIME_NANOS) {
  578. return false;
  579. }
  580. // The last flat state (time since picked up) must have been sufficiently long ago.
  581. if (now < mFlatTimestampNanos + PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS) {
  582. return false;
  583. }
  584. // The last swing state (time since last movement to put down) must have been
  585. // sufficiently long ago.
  586. if (now < mSwingTimestampNanos + PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS) {
  587. return false;
  588. }
  589. // The last acceleration state must have been sufficiently long ago.
  590. if (now < mAccelerationTimestampNanos
  591. + PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS) {
  592. return false;
  593. }
  594. // Looks good!
  595. return true;
  596. }
  597. private void resetLocked() {
  598. mLastFilteredTimestampNanos = Long.MIN_VALUE;
  599. mProposedRotation = -1;
  600. mFlatTimestampNanos = Long.MIN_VALUE;
  601. mSwingTimestampNanos = Long.MIN_VALUE;
  602. mAccelerationTimestampNanos = Long.MIN_VALUE;
  603. clearPredictedRotationLocked();
  604. clearTiltHistoryLocked();
  605. }
  606. private void clearPredictedRotationLocked() {
  607. mPredictedRotation = -1;
  608. mPredictedRotationTimestampNanos = Long.MIN_VALUE;
  609. }
  610. private void updatePredictedRotationLocked(long now, int rotation) {
  611. if (mPredictedRotation != rotation) {
  612. mPredictedRotation = rotation;
  613. mPredictedRotationTimestampNanos = now;
  614. }
  615. }
  616. private boolean isAcceleratingLocked(float magnitude) {
  617. return magnitude < MIN_ACCELERATION_MAGNITUDE
  618. || magnitude > MAX_ACCELERATION_MAGNITUDE;
  619. }
  620. private void clearTiltHistoryLocked() {
  621. mTiltHistoryTimestampNanos[0] = Long.MIN_VALUE;
  622. mTiltHistoryIndex = 1;
  623. }
  624. private void addTiltHistoryEntryLocked(long now, float tilt) {
  625. mTiltHistory[mTiltHistoryIndex] = tilt;
  626. mTiltHistoryTimestampNanos[mTiltHistoryIndex] = now;
  627. mTiltHistoryIndex = (mTiltHistoryIndex + 1) % TILT_HISTORY_SIZE;
  628. mTiltHistoryTimestampNanos[mTiltHistoryIndex] = Long.MIN_VALUE;
  629. }
  630. private boolean isFlatLocked(long now) {
  631. for (int i = mTiltHistoryIndex; (i = nextTiltHistoryIndexLocked(i)) >= 0; ) {
  632. if (mTiltHistory[i] < FLAT_ANGLE) {
  633. break;
  634. }
  635. if (mTiltHistoryTimestampNanos[i] + FLAT_TIME_NANOS <= now) {
  636. // Tilt has remained greater than FLAT_TILT_ANGLE for FLAT_TIME_NANOS.
  637. return true;
  638. }
  639. }
  640. return false;
  641. }
  642. private boolean isSwingingLocked(long now, float tilt) {
  643. for (int i = mTiltHistoryIndex; (i = nextTiltHistoryIndexLocked(i)) >= 0; ) {
  644. if (mTiltHistoryTimestampNanos[i] + SWING_TIME_NANOS < now) {
  645. break;
  646. }
  647. if (mTiltHistory[i] + SWING_AWAY_ANGLE_DELTA <= tilt) {
  648. // Tilted away by SWING_AWAY_ANGLE_DELTA within SWING_TIME_NANOS.
  649. return true;
  650. }
  651. }
  652. return false;
  653. }
  654. private int nextTiltHistoryIndexLocked(int index) {
  655. index = (index == 0 ? TILT_HISTORY_SIZE : index) - 1;
  656. return mTiltHistoryTimestampNanos[index] != Long.MIN_VALUE ? index : -1;
  657. }
  658. private float remainingMS(long now, long until) {
  659. return now >= until ? 0 : (until - now) * 0.000001f;
  660. }
  661. }
  662. }