Skip to content

Commit daf5d89

Browse files
author
Jeff Brown
committed
Small tweaks to orientation.
Improved threshold for detecting external acceleration. Bug: 5976859 Change-Id: Iaf2298fba8eda72d1cacbb2f3aea72f460a9262f
1 parent 59bbef0 commit daf5d89

File tree

4 files changed

+75
-52
lines changed

4 files changed

+75
-52
lines changed

core/java/android/view/WindowOrientationListener.java

Lines changed: 61 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import android.hardware.SensorEvent;
2222
import android.hardware.SensorEventListener;
2323
import android.hardware.SensorManager;
24+
import android.os.SystemProperties;
2425
import android.util.FloatMath;
2526
import android.util.Log;
2627
import android.util.Slog;
@@ -34,20 +35,15 @@
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
*/
4743
public 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;

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

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -552,8 +552,6 @@ void observe() {
552552
Settings.System.USER_ROTATION), false, this);
553553
resolver.registerContentObserver(Settings.System.getUriFor(
554554
Settings.System.SCREEN_OFF_TIMEOUT), false, this);
555-
resolver.registerContentObserver(Settings.System.getUriFor(
556-
Settings.System.WINDOW_ORIENTATION_LISTENER_LOG), false, this);
557555
resolver.registerContentObserver(Settings.System.getUriFor(
558556
Settings.System.POINTER_LOCATION), false, this);
559557
resolver.registerContentObserver(Settings.Secure.getUriFor(
@@ -1098,10 +1096,6 @@ public void updateSettings() {
10981096
updateOrientationListenerLp();
10991097
}
11001098

1101-
mOrientationListener.setLogEnabled(
1102-
Settings.System.getInt(resolver,
1103-
Settings.System.WINDOW_ORIENTATION_LISTENER_LOG, 0) != 0);
1104-
11051099
if (mSystemReady) {
11061100
int pointerLocation = Settings.System.getInt(resolver,
11071101
Settings.System.POINTER_LOCATION, 0);

tools/orientationplot/README.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ USAGE
1616
The tool works by scaping the debug log output from WindowOrientationListener
1717
for interesting data and then plotting it.
1818

19-
1. Enable the Window Orientation Listener debugging data log using the
20-
Development Settings in the Dev Tools application (Development.apk).
21-
22-
2. Plug in the device. Ensure that it is the only device plugged in
19+
1. Plug in the device. Ensure that it is the only device plugged in
2320
since this script is of very little brain and will get confused otherwise.
2421

25-
3. Run "orientationplot.py".
22+
2. Enable the Window Orientation Listener debugging data log.
23+
adb shell setprop debug.orientation.log true
24+
adb shell stop
25+
adb shell start
2626

27-
4. When finished, remember to disable the debug log output since it is quite verbose!
27+
3. Run "orientationplot.py".
2828

2929

3030
WHAT IT ALL MEANS

tools/orientationplot/orientationplot.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ def __init__(self, adbout):
152152
self.time_until_settled = self._make_timeseries()
153153
self.time_until_flat_delay_expired = self._make_timeseries()
154154
self.time_until_swing_delay_expired = self._make_timeseries()
155+
self.time_until_acceleration_delay_expired = self._make_timeseries()
155156
self.stability_axes = self._add_timeseries_axes(
156157
6, 'Proposal Stability', 'ms', [-10, 600],
157158
sharex=shared_axis,
@@ -162,6 +163,8 @@ def __init__(self, adbout):
162163
self.stability_axes, 'time until flat delay expired', 'green')
163164
self.time_until_swing_delay_expired_line = self._add_timeseries_line(
164165
self.stability_axes, 'time until swing delay expired', 'blue')
166+
self.time_until_acceleration_delay_expired_line = self._add_timeseries_line(
167+
self.stability_axes, 'time until acceleration delay expired', 'red')
165168
self._add_timeseries_legend(self.stability_axes)
166169

167170
self.sample_latency = self._make_timeseries()
@@ -253,6 +256,7 @@ def _reset_parse_state(self):
253256
self.parse_time_until_settled = None
254257
self.parse_time_until_flat_delay_expired = None
255258
self.parse_time_until_swing_delay_expired = None
259+
self.parse_time_until_acceleration_delay_expired = None
256260
self.parse_sample_latency = None
257261

258262
# Update samples.
@@ -303,6 +307,7 @@ def update(self):
303307
self.parse_time_until_settled = self._get_following_number(line, 'timeUntilSettledMS=')
304308
self.parse_time_until_flat_delay_expired = self._get_following_number(line, 'timeUntilFlatDelayExpiredMS=')
305309
self.parse_time_until_swing_delay_expired = self._get_following_number(line, 'timeUntilSwingDelayExpiredMS=')
310+
self.parse_time_until_acceleration_delay_expired = self._get_following_number(line, 'timeUntilAccelerationDelayExpiredMS=')
306311

307312
self._append(self.raw_acceleration_x, timeindex, self.parse_raw_acceleration_x)
308313
self._append(self.raw_acceleration_y, timeindex, self.parse_raw_acceleration_y)
@@ -326,6 +331,7 @@ def update(self):
326331
self._append(self.time_until_settled, timeindex, self.parse_time_until_settled)
327332
self._append(self.time_until_flat_delay_expired, timeindex, self.parse_time_until_flat_delay_expired)
328333
self._append(self.time_until_swing_delay_expired, timeindex, self.parse_time_until_swing_delay_expired)
334+
self._append(self.time_until_acceleration_delay_expired, timeindex, self.parse_time_until_acceleration_delay_expired)
329335
self._append(self.sample_latency, timeindex, self.parse_sample_latency)
330336
self._reset_parse_state()
331337

@@ -349,6 +355,7 @@ def update(self):
349355
self._scroll(self.time_until_settled, bottom)
350356
self._scroll(self.time_until_flat_delay_expired, bottom)
351357
self._scroll(self.time_until_swing_delay_expired, bottom)
358+
self._scroll(self.time_until_acceleration_delay_expired, bottom)
352359
self._scroll(self.sample_latency, bottom)
353360

354361
# Redraw the plots.
@@ -368,6 +375,7 @@ def update(self):
368375
self.time_until_settled_line.set_data(self.time_until_settled)
369376
self.time_until_flat_delay_expired_line.set_data(self.time_until_flat_delay_expired)
370377
self.time_until_swing_delay_expired_line.set_data(self.time_until_swing_delay_expired)
378+
self.time_until_acceleration_delay_expired_line.set_data(self.time_until_acceleration_delay_expired)
371379
self.sample_latency_line.set_data(self.sample_latency)
372380

373381
self.fig.canvas.draw_idle()

0 commit comments

Comments
 (0)