2121import android .hardware .SensorEvent ;
2222import android .hardware .SensorEventListener ;
2323import android .hardware .SensorManager ;
24+ import android .os .SystemProperties ;
2425import android .util .FloatMath ;
2526import android .util .Log ;
2627import android .util .Slog ;
3435 * "App/Activity/Screen Orientation" to ensure that all orientation
3536 * modes still work correctly.
3637 *
37- * You can also visualize the behavior of the WindowOrientationListener by
38- * enabling the window orientation listener log using the Development Settings
39- * in the Dev Tools application (Development.apk)
40- * and running frameworks/base/tools/orientationplot/orientationplot.py.
41- *
42- * More information about how to tune this algorithm in
43- * frameworks/base/tools/orientationplot/README.txt.
38+ * You can also visualize the behavior of the WindowOrientationListener.
39+ * Refer to frameworks/base/tools/orientationplot/README.txt for details.
4440 *
4541 * @hide
4642 */
4743public abstract class WindowOrientationListener {
4844 private static final String TAG = "WindowOrientationListener" ;
49- private static final boolean DEBUG = false ;
50- private static final boolean localLOGV = DEBUG || false ;
45+ private static final boolean LOG = SystemProperties . getBoolean (
46+ "debug.orientation.log" , false ) ;
5147
5248 private static final boolean USE_GRAVITY_SENSOR = false ;
5349
@@ -56,7 +52,6 @@ public abstract class WindowOrientationListener {
5652 private int mRate ;
5753 private Sensor mSensor ;
5854 private SensorEventListenerImpl mSensorEventListener ;
59- boolean mLogEnabled ;
6055 int mCurrentRotation = -1 ;
6156
6257 /**
@@ -100,7 +95,9 @@ public void enable() {
10095 return ;
10196 }
10297 if (mEnabled == false ) {
103- if (localLOGV ) Log .d (TAG , "WindowOrientationListener enabled" );
98+ if (LOG ) {
99+ Log .d (TAG , "WindowOrientationListener enabled" );
100+ }
104101 mSensorManager .registerListener (mSensorEventListener , mSensor , mRate );
105102 mEnabled = true ;
106103 }
@@ -115,7 +112,9 @@ public void disable() {
115112 return ;
116113 }
117114 if (mEnabled == true ) {
118- if (localLOGV ) Log .d (TAG , "WindowOrientationListener disabled" );
115+ if (LOG ) {
116+ Log .d (TAG , "WindowOrientationListener disabled" );
117+ }
119118 mSensorManager .unregisterListener (mSensorEventListener );
120119 mEnabled = false ;
121120 }
@@ -164,16 +163,6 @@ public boolean canDetectOrientation() {
164163 */
165164 public abstract void onProposedRotationChanged (int rotation );
166165
167- /**
168- * Enables or disables the window orientation listener logging for use with
169- * the orientationplot.py tool.
170- * Logging is usually enabled via Development Settings. (See class comments.)
171- * @param enable True to enable logging.
172- */
173- public void setLogEnabled (boolean enable ) {
174- mLogEnabled = enable ;
175- }
176-
177166 /**
178167 * This class filters the raw accelerometer data and tries to detect actual changes in
179168 * orientation. This is a very ill-defined problem so there are a lot of tweakable parameters,
@@ -238,11 +227,16 @@ static final class SensorEventListenerImpl implements SensorEventListener {
238227 // can change.
239228 private static final long PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS = 500 * NANOS_PER_MS ;
240229
241- // The mininum amount of time that must have elapsed since the device stopped
230+ // The minimum amount of time that must have elapsed since the device stopped
242231 // swinging (time since device appeared to be in the process of being put down
243232 // or put away into a pocket) before the proposed rotation can change.
244233 private static final long PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS = 300 * NANOS_PER_MS ;
245234
235+ // The minimum amount of time that must have elapsed since the device stopped
236+ // undergoing external acceleration before the proposed rotation can change.
237+ private static final long PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS =
238+ 500 * NANOS_PER_MS ;
239+
246240 // If the tilt angle remains greater than the specified angle for a minimum of
247241 // the specified time, then the device is deemed to be lying flat
248242 // (just chillin' on a table).
@@ -300,10 +294,15 @@ static final class SensorEventListenerImpl implements SensorEventListener {
300294 // singularities in the tilt and orientation calculations.
301295 //
302296 // In both cases, we postpone choosing an orientation.
297+ //
298+ // However, we need to tolerate some acceleration because the angular momentum
299+ // of turning the device can skew the observed acceleration for a short period of time.
300+ private static final float NEAR_ZERO_MAGNITUDE = 1 ; // m/s^2
301+ private static final float ACCELERATION_TOLERANCE = 4 ; // m/s^2
303302 private static final float MIN_ACCELERATION_MAGNITUDE =
304- SensorManager .STANDARD_GRAVITY * 0.3f ;
303+ SensorManager .STANDARD_GRAVITY - ACCELERATION_TOLERANCE ;
305304 private static final float MAX_ACCELERATION_MAGNITUDE =
306- SensorManager .STANDARD_GRAVITY * 1.25f ;
305+ SensorManager .STANDARD_GRAVITY + ACCELERATION_TOLERANCE ;
307306
308307 // Maximum absolute tilt angle at which to consider orientation data. Beyond this (i.e.
309308 // when screen is facing the sky or ground), we completely ignore orientation data.
@@ -353,6 +352,9 @@ static final class SensorEventListenerImpl implements SensorEventListener {
353352 // Timestamp when the device last appeared to be swinging.
354353 private long mSwingTimestampNanos ;
355354
355+ // Timestamp when the device last appeared to be undergoing external acceleration.
356+ private long mAccelerationTimestampNanos ;
357+
356358 // History of observed tilt angles.
357359 private static final int TILT_HISTORY_SIZE = 40 ;
358360 private float [] mTiltHistory = new float [TILT_HISTORY_SIZE ];
@@ -374,15 +376,13 @@ public void onAccuracyChanged(Sensor sensor, int accuracy) {
374376
375377 @ Override
376378 public void onSensorChanged (SensorEvent event ) {
377- final boolean log = mOrientationListener .mLogEnabled ;
378-
379379 // The vector given in the SensorEvent points straight up (towards the sky) under ideal
380380 // conditions (the phone is not accelerating). I'll call this up vector elsewhere.
381381 float x = event .values [ACCELEROMETER_DATA_X ];
382382 float y = event .values [ACCELEROMETER_DATA_Y ];
383383 float z = event .values [ACCELEROMETER_DATA_Z ];
384384
385- if (log ) {
385+ if (LOG ) {
386386 Slog .v (TAG , "Raw acceleration vector: "
387387 + "x=" + x + ", y=" + y + ", z=" + z
388388 + ", magnitude=" + FloatMath .sqrt (x * x + y * y + z * z ));
@@ -399,7 +399,7 @@ public void onSensorChanged(SensorEvent event) {
399399 if (now < then
400400 || now > then + MAX_FILTER_DELTA_TIME_NANOS
401401 || (x == 0 && y == 0 && z == 0 )) {
402- if (log ) {
402+ if (LOG ) {
403403 Slog .v (TAG , "Resetting orientation listener." );
404404 }
405405 reset ();
@@ -409,7 +409,7 @@ public void onSensorChanged(SensorEvent event) {
409409 x = alpha * (x - mLastFilteredX ) + mLastFilteredX ;
410410 y = alpha * (y - mLastFilteredY ) + mLastFilteredY ;
411411 z = alpha * (z - mLastFilteredZ ) + mLastFilteredZ ;
412- if (log ) {
412+ if (LOG ) {
413413 Slog .v (TAG , "Filtered acceleration vector: "
414414 + "x=" + x + ", y=" + y + ", z=" + z
415415 + ", magnitude=" + FloatMath .sqrt (x * x + y * y + z * z ));
@@ -421,18 +421,24 @@ public void onSensorChanged(SensorEvent event) {
421421 mLastFilteredY = y ;
422422 mLastFilteredZ = z ;
423423
424+ boolean isAccelerating = false ;
424425 boolean isFlat = false ;
425426 boolean isSwinging = false ;
426427 if (!skipSample ) {
427428 // Calculate the magnitude of the acceleration vector.
428429 final float magnitude = FloatMath .sqrt (x * x + y * y + z * z );
429- if (magnitude < MIN_ACCELERATION_MAGNITUDE
430- || magnitude > MAX_ACCELERATION_MAGNITUDE ) {
431- if (log ) {
432- Slog .v (TAG , "Ignoring sensor data, magnitude out of range." );
430+ if (magnitude < NEAR_ZERO_MAGNITUDE ) {
431+ if (LOG ) {
432+ Slog .v (TAG , "Ignoring sensor data, magnitude too close to zero." );
433433 }
434434 clearPredictedRotation ();
435435 } else {
436+ // Determine whether the device appears to be undergoing external acceleration.
437+ if (isAccelerating (magnitude )) {
438+ isAccelerating = true ;
439+ mAccelerationTimestampNanos = now ;
440+ }
441+
436442 // Calculate the tilt angle.
437443 // This is the angle between the up vector and the x-y plane (the plane of
438444 // the screen) in a range of [-90, 90] degrees.
@@ -441,6 +447,7 @@ public void onSensorChanged(SensorEvent event) {
441447 // 90 degrees: screen horizontal and facing the sky (on table)
442448 final int tiltAngle = (int ) Math .round (
443449 Math .asin (z / magnitude ) * RADIANS_TO_DEGREES );
450+ addTiltHistoryEntry (now , tiltAngle );
444451
445452 // Determine whether the device appears to be flat or swinging.
446453 if (isFlat (now )) {
@@ -451,12 +458,11 @@ public void onSensorChanged(SensorEvent event) {
451458 isSwinging = true ;
452459 mSwingTimestampNanos = now ;
453460 }
454- addTiltHistoryEntry (now , tiltAngle );
455461
456462 // If the tilt angle is too close to horizontal then we cannot determine
457463 // the orientation angle of the screen.
458464 if (Math .abs (tiltAngle ) > MAX_TILT ) {
459- if (log ) {
465+ if (LOG ) {
460466 Slog .v (TAG , "Ignoring sensor data, tilt angle too high: "
461467 + "tiltAngle=" + tiltAngle );
462468 }
@@ -483,7 +489,7 @@ public void onSensorChanged(SensorEvent event) {
483489 && isOrientationAngleAcceptable (nearestRotation ,
484490 orientationAngle )) {
485491 updatePredictedRotation (now , nearestRotation );
486- if (log ) {
492+ if (LOG ) {
487493 Slog .v (TAG , "Predicted: "
488494 + "tiltAngle=" + tiltAngle
489495 + ", orientationAngle=" + orientationAngle
@@ -493,7 +499,7 @@ && isOrientationAngleAcceptable(nearestRotation,
493499 * 0.000001f ));
494500 }
495501 } else {
496- if (log ) {
502+ if (LOG ) {
497503 Slog .v (TAG , "Ignoring sensor data, no predicted rotation: "
498504 + "tiltAngle=" + tiltAngle
499505 + ", orientationAngle=" + orientationAngle );
@@ -511,15 +517,18 @@ && isOrientationAngleAcceptable(nearestRotation,
511517 }
512518
513519 // Write final statistics about where we are in the orientation detection process.
514- if (log ) {
520+ if (LOG ) {
515521 Slog .v (TAG , "Result: currentRotation=" + mOrientationListener .mCurrentRotation
516522 + ", proposedRotation=" + mProposedRotation
517523 + ", predictedRotation=" + mPredictedRotation
518524 + ", timeDeltaMS=" + timeDeltaMS
525+ + ", isAccelerating=" + isAccelerating
519526 + ", isFlat=" + isFlat
520527 + ", isSwinging=" + isSwinging
521528 + ", timeUntilSettledMS=" + remainingMS (now ,
522529 mPredictedRotationTimestampNanos + PROPOSAL_SETTLE_TIME_NANOS )
530+ + ", timeUntilAccelerationDelayExpiredMS=" + remainingMS (now ,
531+ mAccelerationTimestampNanos + PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS )
523532 + ", timeUntilFlatDelayExpiredMS=" + remainingMS (now ,
524533 mFlatTimestampNanos + PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS )
525534 + ", timeUntilSwingDelayExpiredMS=" + remainingMS (now ,
@@ -528,7 +537,7 @@ && isOrientationAngleAcceptable(nearestRotation,
528537
529538 // Tell the listener.
530539 if (mProposedRotation != oldProposedRotation && mProposedRotation >= 0 ) {
531- if (log ) {
540+ if (LOG ) {
532541 Slog .v (TAG , "Proposed rotation changed! proposedRotation=" + mProposedRotation
533542 + ", oldProposedRotation=" + oldProposedRotation );
534543 }
@@ -618,6 +627,12 @@ private boolean isPredictedRotationAcceptable(long now) {
618627 return false ;
619628 }
620629
630+ // The last acceleration state must have been sufficiently long ago.
631+ if (now < mAccelerationTimestampNanos
632+ + PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS ) {
633+ return false ;
634+ }
635+
621636 // Looks good!
622637 return true ;
623638 }
@@ -627,6 +642,7 @@ private void reset() {
627642 mProposedRotation = -1 ;
628643 mFlatTimestampNanos = Long .MIN_VALUE ;
629644 mSwingTimestampNanos = Long .MIN_VALUE ;
645+ mAccelerationTimestampNanos = Long .MIN_VALUE ;
630646 clearPredictedRotation ();
631647 clearTiltHistory ();
632648 }
@@ -643,6 +659,11 @@ private void updatePredictedRotation(long now, int rotation) {
643659 }
644660 }
645661
662+ private boolean isAccelerating (float magnitude ) {
663+ return magnitude < MIN_ACCELERATION_MAGNITUDE
664+ || magnitude > MAX_ACCELERATION_MAGNITUDE ;
665+ }
666+
646667 private void clearTiltHistory () {
647668 mTiltHistoryTimestampNanos [0 ] = Long .MIN_VALUE ;
648669 mTiltHistoryIndex = 1 ;
0 commit comments