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 17 package com.android.server.wm; 18 19 import static android.provider.DeviceConfig.NAMESPACE_WINDOW_MANAGER; 20 21 import static com.android.server.wm.WindowOrientationListenerProto.ENABLED; 22 import static com.android.server.wm.WindowOrientationListenerProto.ROTATION; 23 24 import android.app.ActivityThread; 25 import android.content.Context; 26 import android.hardware.Sensor; 27 import android.hardware.SensorEvent; 28 import android.hardware.SensorEventListener; 29 import android.hardware.SensorManager; 30 import android.os.CancellationSignal; 31 import android.os.Handler; 32 import android.os.SystemClock; 33 import android.os.SystemProperties; 34 import android.provider.DeviceConfig; 35 import android.rotationresolver.RotationResolverInternal; 36 import android.util.Slog; 37 import android.util.proto.ProtoOutputStream; 38 import android.view.Surface; 39 40 import com.android.internal.annotations.VisibleForTesting; 41 import com.android.internal.util.FrameworkStatsLog; 42 import com.android.server.LocalServices; 43 44 import java.io.PrintWriter; 45 import java.util.List; 46 import java.util.Set; 47 48 /** 49 * A special helper class used by the WindowManager 50 * for receiving notifications from the SensorManager when 51 * the orientation of the device has changed. 52 * 53 * NOTE: If changing anything here, please run the API demo 54 * "App/Activity/Screen Orientation" to ensure that all orientation 55 * modes still work correctly. 56 * 57 * You can also visualize the behavior of the WindowOrientationListener. 58 * Refer to frameworks/base/tools/orientationplot/README.txt for details. 59 */ 60 public abstract class WindowOrientationListener { 61 private static final String TAG = "WindowOrientationListener"; 62 private static final boolean LOG = SystemProperties.getBoolean( 63 "debug.orientation.log", false); 64 65 private static final boolean USE_GRAVITY_SENSOR = false; 66 private static final int DEFAULT_BATCH_LATENCY = 100000; 67 private static final String KEY_ROTATION_RESOLVER_TIMEOUT = "rotation_resolver_timeout_millis"; 68 private static final String KEY_ROTATION_MEMORIZATION_TIMEOUT = 69 "rotation_memorization_timeout_millis"; 70 private static final long DEFAULT_ROTATION_RESOLVER_TIMEOUT_MILLIS = 700L; 71 private static final long DEFAULT_ROTATION_MEMORIZATION_TIMEOUT_MILLIS = 3_000L; // 3 seconds 72 73 private Handler mHandler; 74 private SensorManager mSensorManager; 75 private boolean mEnabled; 76 private int mRate; 77 private String mSensorType; 78 private Sensor mSensor; 79 80 @VisibleForTesting 81 OrientationJudge mOrientationJudge; 82 83 @VisibleForTesting 84 RotationResolverInternal mRotationResolverService; 85 86 private int mCurrentRotation = -1; 87 private final Context mContext; 88 89 private final Object mLock = new Object(); 90 91 @Surface.Rotation 92 private final int mDefaultRotation; 93 94 /** 95 * Creates a new WindowOrientationListener. 96 * 97 * @param context for the WindowOrientationListener. 98 * @param handler Provides the Looper for receiving sensor updates. 99 * @param defaultRotation Default rotation of the display. 100 */ WindowOrientationListener(Context context, Handler handler, @Surface.Rotation int defaultRotation)101 public WindowOrientationListener(Context context, Handler handler, 102 @Surface.Rotation int defaultRotation) { 103 this(context, handler, defaultRotation, SensorManager.SENSOR_DELAY_UI); 104 } 105 106 /** 107 * Creates a new WindowOrientationListener. 108 * 109 * @param context for the WindowOrientationListener. 110 * @param handler Provides the Looper for receiving sensor updates. 111 * @param defaultRotation Default rotation of the display. 112 * @param rate at which sensor events are processed (see also 113 * {@link android.hardware.SensorManager SensorManager}). Use the default 114 * value of {@link android.hardware.SensorManager#SENSOR_DELAY_NORMAL 115 * SENSOR_DELAY_NORMAL} for simple screen orientation change detection. 116 * 117 * This constructor is private since no one uses it. 118 */ WindowOrientationListener(Context context, Handler handler, @Surface.Rotation int defaultRotation, int rate)119 private WindowOrientationListener(Context context, Handler handler, 120 @Surface.Rotation int defaultRotation, int rate) { 121 mContext = context; 122 mHandler = handler; 123 mDefaultRotation = defaultRotation; 124 mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); 125 mRate = rate; 126 List<Sensor> l = mSensorManager.getSensorList(Sensor.TYPE_DEVICE_ORIENTATION); 127 Sensor wakeUpDeviceOrientationSensor = null; 128 Sensor nonWakeUpDeviceOrientationSensor = null; 129 /** 130 * Prefer the wakeup form of the sensor if implemented. 131 * It's OK to look for just two types of this sensor and use 132 * the last found. Typical devices will only have one sensor of 133 * this type. 134 */ 135 for (Sensor s : l) { 136 if (s.isWakeUpSensor()) { 137 wakeUpDeviceOrientationSensor = s; 138 } else { 139 nonWakeUpDeviceOrientationSensor = s; 140 } 141 } 142 143 if (wakeUpDeviceOrientationSensor != null) { 144 mSensor = wakeUpDeviceOrientationSensor; 145 } else { 146 mSensor = nonWakeUpDeviceOrientationSensor; 147 } 148 149 if (mSensor != null) { 150 mOrientationJudge = new OrientationSensorJudge(); 151 } 152 153 if (mOrientationJudge == null) { 154 mSensor = mSensorManager.getDefaultSensor(USE_GRAVITY_SENSOR 155 ? Sensor.TYPE_GRAVITY : Sensor.TYPE_ACCELEROMETER); 156 if (mSensor != null) { 157 // Create listener only if sensors do exist 158 mOrientationJudge = new AccelSensorJudge(context); 159 } 160 } 161 } 162 163 /** 164 * Enables the WindowOrientationListener so it will monitor the sensor and call 165 * {@link #onProposedRotationChanged(int)} when the device orientation changes. 166 */ enable()167 public void enable() { 168 enable(true /* clearCurrentRotation */); 169 } 170 171 /** 172 * Enables the WindowOrientationListener so it will monitor the sensor and call 173 * {@link #onProposedRotationChanged(int)} when the device orientation changes. 174 * 175 * @param clearCurrentRotation True if the current proposed sensor rotation should be cleared as 176 * part of the reset. 177 */ enable(boolean clearCurrentRotation)178 public void enable(boolean clearCurrentRotation) { 179 synchronized (mLock) { 180 if (mSensor == null) { 181 Slog.w(TAG, "Cannot detect sensors. Not enabled"); 182 return; 183 } 184 if (mEnabled) { 185 return; 186 } 187 if (LOG) { 188 Slog.d(TAG, "WindowOrientationListener enabled clearCurrentRotation=" 189 + clearCurrentRotation); 190 } 191 mOrientationJudge.resetLocked(clearCurrentRotation); 192 if (mSensor.getType() == Sensor.TYPE_ACCELEROMETER) { 193 mSensorManager.registerListener( 194 mOrientationJudge, mSensor, mRate, DEFAULT_BATCH_LATENCY, mHandler); 195 } else { 196 mSensorManager.registerListener(mOrientationJudge, mSensor, mRate, mHandler); 197 } 198 mEnabled = true; 199 } 200 } 201 202 /** 203 * Disables the WindowOrientationListener. 204 */ disable()205 public void disable() { 206 synchronized (mLock) { 207 if (mSensor == null) { 208 Slog.w(TAG, "Cannot detect sensors. Invalid disable"); 209 return; 210 } 211 if (mEnabled == true) { 212 if (LOG) { 213 Slog.d(TAG, "WindowOrientationListener disabled"); 214 } 215 mSensorManager.unregisterListener(mOrientationJudge); 216 mEnabled = false; 217 } 218 } 219 } 220 onTouchStart()221 public void onTouchStart() { 222 synchronized (mLock) { 223 if (mOrientationJudge != null) { 224 mOrientationJudge.onTouchStartLocked(); 225 } 226 } 227 } 228 onTouchEnd()229 public void onTouchEnd() { 230 long whenElapsedNanos = SystemClock.elapsedRealtimeNanos(); 231 232 synchronized (mLock) { 233 if (mOrientationJudge != null) { 234 mOrientationJudge.onTouchEndLocked(whenElapsedNanos); 235 } 236 } 237 } 238 getHandler()239 public Handler getHandler() { 240 return mHandler; 241 } 242 243 /** 244 * Sets the current rotation. 245 * 246 * @param rotation The current rotation. 247 */ setCurrentRotation(int rotation)248 public void setCurrentRotation(int rotation) { 249 synchronized (mLock) { 250 mCurrentRotation = rotation; 251 } 252 } 253 254 /** 255 * Gets the proposed rotation. 256 * 257 * This method only returns a rotation if the orientation listener is certain 258 * of its proposal. If the rotation is indeterminate, returns -1. 259 * 260 * @return The proposed rotation, or -1 if unknown. 261 */ getProposedRotation()262 public int getProposedRotation() { 263 synchronized (mLock) { 264 if (mEnabled) { 265 return mOrientationJudge.getProposedRotationLocked(); 266 } 267 return -1; 268 } 269 } 270 271 /** 272 * Returns true if sensor is enabled and false otherwise 273 */ canDetectOrientation()274 public boolean canDetectOrientation() { 275 synchronized (mLock) { 276 return mSensor != null; 277 } 278 } 279 280 281 /** 282 * Returns true if the rotation resolver feature is enabled by setting. It means {@link 283 * WindowOrientationListener} will then ask {@link RotationResolverInternal} for the appropriate 284 * screen rotation. 285 */ 286 @VisibleForTesting isRotationResolverEnabled()287 abstract boolean isRotationResolverEnabled(); 288 289 /** 290 * Called when the rotation view of the device has changed. 291 * 292 * This method is called whenever the orientation becomes certain of an orientation. 293 * It is called each time the orientation determination transitions from being 294 * uncertain to being certain again, even if it is the same orientation as before. 295 * 296 * This should only be called on the Handler thread. 297 * 298 * @param rotation The new orientation of the device, one of the Surface.ROTATION_* constants. 299 * @see android.view.Surface 300 */ onProposedRotationChanged(int rotation)301 public abstract void onProposedRotationChanged(int rotation); 302 303 /** 304 * Whether the device is in the lock screen. 305 * @return returns true if the key guard is showing on the lock screen. 306 */ isKeyguardShowingAndNotOccluded()307 public abstract boolean isKeyguardShowingAndNotOccluded(); 308 dumpDebug(ProtoOutputStream proto, long fieldId)309 public void dumpDebug(ProtoOutputStream proto, long fieldId) { 310 final long token = proto.start(fieldId); 311 synchronized (mLock) { 312 proto.write(ENABLED, mEnabled); 313 proto.write(ROTATION, mCurrentRotation); 314 } 315 proto.end(token); 316 } 317 dump(PrintWriter pw, String prefix)318 public void dump(PrintWriter pw, String prefix) { 319 synchronized (mLock) { 320 pw.println(prefix + TAG); 321 prefix += " "; 322 pw.println(prefix + "mEnabled=" + mEnabled); 323 pw.println(prefix + "mCurrentRotation=" + Surface.rotationToString(mCurrentRotation)); 324 pw.println(prefix + "mSensorType=" + mSensorType); 325 pw.println(prefix + "mSensor=" + mSensor); 326 pw.println(prefix + "mRate=" + mRate); 327 328 if (mOrientationJudge != null) { 329 mOrientationJudge.dumpLocked(pw, prefix); 330 } 331 } 332 } 333 334 /** 335 * Returns whether this WindowOrientationListener can remain enabled while the device is dozing. 336 * If this returns true, it implies that the underlying sensor can still run while the AP is 337 * asleep, and that the underlying sensor will wake the AP on an event. 338 */ shouldStayEnabledWhileDreaming()339 public boolean shouldStayEnabledWhileDreaming() { 340 if (mContext.getResources().getBoolean( 341 com.android.internal.R.bool.config_forceOrientationListenerEnabledWhileDreaming)) { 342 return true; 343 } 344 return mSensor.getType() == Sensor.TYPE_DEVICE_ORIENTATION && mSensor.isWakeUpSensor(); 345 } 346 347 abstract class OrientationJudge implements SensorEventListener { 348 // Number of nanoseconds per millisecond. 349 protected static final long NANOS_PER_MS = 1000000; 350 351 // Number of milliseconds per nano second. 352 protected static final float MILLIS_PER_NANO = 0.000001f; 353 354 // The minimum amount of time that must have elapsed since the screen was last touched 355 // before the proposed rotation can change. 356 protected static final long PROPOSAL_MIN_TIME_SINCE_TOUCH_END_NANOS = 357 500 * NANOS_PER_MS; 358 359 /** 360 * Gets the proposed rotation. 361 * 362 * This method only returns a rotation if the orientation listener is certain 363 * of its proposal. If the rotation is indeterminate, returns -1. 364 * 365 * Should only be called when holding WindowOrientationListener lock. 366 * 367 * @return The proposed rotation, or -1 if unknown. 368 */ getProposedRotationLocked()369 public abstract int getProposedRotationLocked(); 370 371 /** 372 * Notifies the orientation judge that the screen is being touched. 373 * 374 * Should only be called when holding WindowOrientationListener lock. 375 */ onTouchStartLocked()376 public abstract void onTouchStartLocked(); 377 378 /** 379 * Notifies the orientation judge that the screen is no longer being touched. 380 * 381 * Should only be called when holding WindowOrientationListener lock. 382 * 383 * @param whenElapsedNanos Given in the elapsed realtime nanos time base. 384 */ onTouchEndLocked(long whenElapsedNanos)385 public abstract void onTouchEndLocked(long whenElapsedNanos); 386 387 /** 388 * Resets the state of the judge. 389 * 390 * Should only be called when holding WindowOrientationListener lock. 391 * 392 * @param clearCurrentRotation True if the current proposed sensor rotation should be 393 * cleared as part of the reset. 394 */ resetLocked(boolean clearCurrentRotation)395 public abstract void resetLocked(boolean clearCurrentRotation); 396 397 /** 398 * Dumps internal state of the orientation judge. 399 * 400 * Should only be called when holding WindowOrientationListener lock. 401 */ dumpLocked(PrintWriter pw, String prefix)402 public abstract void dumpLocked(PrintWriter pw, String prefix); 403 404 @Override onAccuracyChanged(Sensor sensor, int accuracy)405 public abstract void onAccuracyChanged(Sensor sensor, int accuracy); 406 407 @Override onSensorChanged(SensorEvent event)408 public abstract void onSensorChanged(SensorEvent event); 409 } 410 411 /** 412 * This class filters the raw accelerometer data and tries to detect actual changes in 413 * orientation. This is a very ill-defined problem so there are a lot of tweakable parameters, 414 * but here's the outline: 415 * 416 * - Low-pass filter the accelerometer vector in cartesian coordinates. We do it in 417 * cartesian space because the orientation calculations are sensitive to the 418 * absolute magnitude of the acceleration. In particular, there are singularities 419 * in the calculation as the magnitude approaches 0. By performing the low-pass 420 * filtering early, we can eliminate most spurious high-frequency impulses due to noise. 421 * 422 * - Convert the acceleromter vector from cartesian to spherical coordinates. 423 * Since we're dealing with rotation of the device, this is the sensible coordinate 424 * system to work in. The zenith direction is the Z-axis, the direction the screen 425 * is facing. The radial distance is referred to as the magnitude below. 426 * The elevation angle is referred to as the "tilt" below. 427 * The azimuth angle is referred to as the "orientation" below (and the azimuth axis is 428 * the Y-axis). 429 * See http://en.wikipedia.org/wiki/Spherical_coordinate_system for reference. 430 * 431 * - If the tilt angle is too close to horizontal (near 90 or -90 degrees), do nothing. 432 * The orientation angle is not meaningful when the device is nearly horizontal. 433 * The tilt angle thresholds are set differently for each orientation and different 434 * limits are applied when the device is facing down as opposed to when it is facing 435 * forward or facing up. 436 * 437 * - When the orientation angle reaches a certain threshold, consider transitioning 438 * to the corresponding orientation. These thresholds have some hysteresis built-in 439 * to avoid oscillations between adjacent orientations. 440 * 441 * - Wait for the device to settle for a little bit. Once that happens, issue the 442 * new orientation proposal. 443 * 444 * Details are explained inline. 445 * 446 * See http://en.wikipedia.org/wiki/Low-pass_filter#Discrete-time_realization for 447 * signal processing background. 448 */ 449 final class AccelSensorJudge extends OrientationJudge { 450 // We work with all angles in degrees in this class. 451 private static final float RADIANS_TO_DEGREES = (float) (180 / Math.PI); 452 453 // Indices into SensorEvent.values for the accelerometer sensor. 454 private static final int ACCELEROMETER_DATA_X = 0; 455 private static final int ACCELEROMETER_DATA_Y = 1; 456 private static final int ACCELEROMETER_DATA_Z = 2; 457 458 // The minimum amount of time that a predicted rotation must be stable before it 459 // is accepted as a valid rotation proposal. This value can be quite small because 460 // the low-pass filter already suppresses most of the noise so we're really just 461 // looking for quick confirmation that the last few samples are in agreement as to 462 // the desired orientation. 463 private static final long PROPOSAL_SETTLE_TIME_NANOS = 40 * NANOS_PER_MS; 464 465 // The minimum amount of time that must have elapsed since the device last exited 466 // the flat state (time since it was picked up) before the proposed rotation 467 // can change. 468 private static final long PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS = 500 * NANOS_PER_MS; 469 470 // The minimum amount of time that must have elapsed since the device stopped 471 // swinging (time since device appeared to be in the process of being put down 472 // or put away into a pocket) before the proposed rotation can change. 473 private static final long PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS = 300 * NANOS_PER_MS; 474 475 // The minimum amount of time that must have elapsed since the device stopped 476 // undergoing external acceleration before the proposed rotation can change. 477 private static final long PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS = 478 500 * NANOS_PER_MS; 479 480 // If the tilt angle remains greater than the specified angle for a minimum of 481 // the specified time, then the device is deemed to be lying flat 482 // (just chillin' on a table). 483 private static final float FLAT_ANGLE = 80; 484 private static final long FLAT_TIME_NANOS = 1000 * NANOS_PER_MS; 485 486 // If the tilt angle has increased by at least delta degrees within the specified amount 487 // of time, then the device is deemed to be swinging away from the user 488 // down towards flat (tilt = 90). 489 private static final float SWING_AWAY_ANGLE_DELTA = 20; 490 private static final long SWING_TIME_NANOS = 300 * NANOS_PER_MS; 491 492 // The maximum sample inter-arrival time in milliseconds. 493 // If the acceleration samples are further apart than this amount in time, we reset the 494 // state of the low-pass filter and orientation properties. This helps to handle 495 // boundary conditions when the device is turned on, wakes from suspend or there is 496 // a significant gap in samples. 497 private static final long MAX_FILTER_DELTA_TIME_NANOS = 1000 * NANOS_PER_MS; 498 499 // The acceleration filter time constant. 500 // 501 // This time constant is used to tune the acceleration filter such that 502 // impulses and vibrational noise (think car dock) is suppressed before we 503 // try to calculate the tilt and orientation angles. 504 // 505 // The filter time constant is related to the filter cutoff frequency, which is the 506 // frequency at which signals are attenuated by 3dB (half the passband power). 507 // Each successive octave beyond this frequency is attenuated by an additional 6dB. 508 // 509 // Given a time constant t in seconds, the filter cutoff frequency Fc in Hertz 510 // is given by Fc = 1 / (2pi * t). 511 // 512 // The higher the time constant, the lower the cutoff frequency, so more noise 513 // will be suppressed. 514 // 515 // Filtering adds latency proportional the time constant (inversely proportional 516 // to the cutoff frequency) so we don't want to make the time constant too 517 // large or we can lose responsiveness. Likewise we don't want to make it too 518 // small or we do a poor job suppressing acceleration spikes. 519 // Empirically, 100ms seems to be too small and 500ms is too large. 520 private static final float FILTER_TIME_CONSTANT_MS = 200.0f; 521 522 /* State for orientation detection. */ 523 524 // Thresholds for minimum and maximum allowable deviation from gravity. 525 // 526 // If the device is undergoing external acceleration (being bumped, in a car 527 // that is turning around a corner or a plane taking off) then the magnitude 528 // may be substantially more or less than gravity. This can skew our orientation 529 // detection by making us think that up is pointed in a different direction. 530 // 531 // Conversely, if the device is in freefall, then there will be no gravity to 532 // measure at all. This is problematic because we cannot detect the orientation 533 // without gravity to tell us which way is up. A magnitude near 0 produces 534 // singularities in the tilt and orientation calculations. 535 // 536 // In both cases, we postpone choosing an orientation. 537 // 538 // However, we need to tolerate some acceleration because the angular momentum 539 // of turning the device can skew the observed acceleration for a short period of time. 540 private static final float NEAR_ZERO_MAGNITUDE = 1; // m/s^2 541 private static final float ACCELERATION_TOLERANCE = 4; // m/s^2 542 private static final float MIN_ACCELERATION_MAGNITUDE = 543 SensorManager.STANDARD_GRAVITY - ACCELERATION_TOLERANCE; 544 private static final float MAX_ACCELERATION_MAGNITUDE = 545 SensorManager.STANDARD_GRAVITY + ACCELERATION_TOLERANCE; 546 547 // Maximum absolute tilt angle at which to consider orientation data. Beyond this (i.e. 548 // when screen is facing the sky or ground), we completely ignore orientation data 549 // because it's too unstable. 550 private static final int MAX_TILT = 80; 551 552 // The tilt angle below which we conclude that the user is holding the device 553 // overhead reading in bed and lock into that state. 554 private static final int TILT_OVERHEAD_ENTER = -40; 555 556 // The tilt angle above which we conclude that the user would like a rotation 557 // change to occur and unlock from the overhead state. 558 private static final int TILT_OVERHEAD_EXIT = -15; 559 560 // The gap angle in degrees between adjacent orientation angles for hysteresis. 561 // This creates a "dead zone" between the current orientation and a proposed 562 // adjacent orientation. No orientation proposal is made when the orientation 563 // angle is within the gap between the current orientation and the adjacent 564 // orientation. 565 private static final int ADJACENT_ORIENTATION_ANGLE_GAP = 45; 566 567 // The tilt angle range in degrees for each orientation. 568 // Beyond these tilt angles, we don't even consider transitioning into the 569 // specified orientation. We place more stringent requirements on unnatural 570 // orientations than natural ones to make it less likely to accidentally transition 571 // into those states. 572 // The first value of each pair is negative so it applies a limit when the device is 573 // facing down (overhead reading in bed). 574 // The second value of each pair is positive so it applies a limit when the device is 575 // facing up (resting on a table). 576 // The ideal tilt angle is 0 (when the device is vertical) so the limits establish 577 // how close to vertical the device must be in order to change orientation. 578 private final int[][] mTiltToleranceConfig = new int[][] { 579 /* ROTATION_0 */ { -25, 70 }, // note: these are overridden by config.xml 580 /* ROTATION_90 */ { -25, 65 }, 581 /* ROTATION_180 */ { -25, 60 }, 582 /* ROTATION_270 */ { -25, 65 } 583 }; 584 585 // Timestamp and value of the last accelerometer sample. 586 private long mLastFilteredTimestampNanos; 587 private float mLastFilteredX, mLastFilteredY, mLastFilteredZ; 588 589 // The last proposed rotation, -1 if unknown. 590 private int mProposedRotation; 591 592 // Value of the current predicted rotation, -1 if unknown. 593 private int mPredictedRotation; 594 595 // Timestamp of when the predicted rotation most recently changed. 596 private long mPredictedRotationTimestampNanos; 597 598 // Timestamp when the device last appeared to be flat for sure (the flat delay elapsed). 599 private long mFlatTimestampNanos; 600 private boolean mFlat; 601 602 // Timestamp when the device last appeared to be swinging. 603 private long mSwingTimestampNanos; 604 private boolean mSwinging; 605 606 // Timestamp when the device last appeared to be undergoing external acceleration. 607 private long mAccelerationTimestampNanos; 608 private boolean mAccelerating; 609 610 // Timestamp when the last touch to the touch screen ended 611 private long mTouchEndedTimestampNanos = Long.MIN_VALUE; 612 private boolean mTouched; 613 614 // Whether we are locked into an overhead usage mode. 615 private boolean mOverhead; 616 617 // History of observed tilt angles. 618 private static final int TILT_HISTORY_SIZE = 200; 619 private float[] mTiltHistory = new float[TILT_HISTORY_SIZE]; 620 private long[] mTiltHistoryTimestampNanos = new long[TILT_HISTORY_SIZE]; 621 private int mTiltHistoryIndex; 622 AccelSensorJudge(Context context)623 public AccelSensorJudge(Context context) { 624 // Load tilt tolerance configuration. 625 int[] tiltTolerance = context.getResources().getIntArray( 626 com.android.internal.R.array.config_autoRotationTiltTolerance); 627 if (tiltTolerance.length == 8) { 628 for (int i = 0; i < 4; i++) { 629 int min = tiltTolerance[i * 2]; 630 int max = tiltTolerance[i * 2 + 1]; 631 if (min >= -90 && min <= max && max <= 90) { 632 mTiltToleranceConfig[i][0] = min; 633 mTiltToleranceConfig[i][1] = max; 634 } else { 635 Slog.wtf(TAG, "config_autoRotationTiltTolerance contains invalid range: " 636 + "min=" + min + ", max=" + max); 637 } 638 } 639 } else { 640 Slog.wtf(TAG, "config_autoRotationTiltTolerance should have exactly 8 elements"); 641 } 642 } 643 644 @Override getProposedRotationLocked()645 public int getProposedRotationLocked() { 646 return mProposedRotation; 647 } 648 649 @Override dumpLocked(PrintWriter pw, String prefix)650 public void dumpLocked(PrintWriter pw, String prefix) { 651 pw.println(prefix + "AccelSensorJudge"); 652 prefix += " "; 653 pw.println(prefix + "mProposedRotation=" + mProposedRotation); 654 pw.println(prefix + "mPredictedRotation=" + mPredictedRotation); 655 pw.println(prefix + "mLastFilteredX=" + mLastFilteredX); 656 pw.println(prefix + "mLastFilteredY=" + mLastFilteredY); 657 pw.println(prefix + "mLastFilteredZ=" + mLastFilteredZ); 658 final long delta = SystemClock.elapsedRealtimeNanos() - mLastFilteredTimestampNanos; 659 pw.println(prefix + "mLastFilteredTimestampNanos=" + mLastFilteredTimestampNanos 660 + " (" + (delta * 0.000001f) + "ms ago)"); 661 pw.println(prefix + "mTiltHistory={last: " + getLastTiltLocked() + "}"); 662 pw.println(prefix + "mFlat=" + mFlat); 663 pw.println(prefix + "mSwinging=" + mSwinging); 664 pw.println(prefix + "mAccelerating=" + mAccelerating); 665 pw.println(prefix + "mOverhead=" + mOverhead); 666 pw.println(prefix + "mTouched=" + mTouched); 667 pw.print(prefix + "mTiltToleranceConfig=["); 668 for (int i = 0; i < 4; i++) { 669 if (i != 0) { 670 pw.print(", "); 671 } 672 pw.print("["); 673 pw.print(mTiltToleranceConfig[i][0]); 674 pw.print(", "); 675 pw.print(mTiltToleranceConfig[i][1]); 676 pw.print("]"); 677 } 678 pw.println("]"); 679 } 680 681 @Override onAccuracyChanged(Sensor sensor, int accuracy)682 public void onAccuracyChanged(Sensor sensor, int accuracy) { 683 } 684 685 @Override onSensorChanged(SensorEvent event)686 public void onSensorChanged(SensorEvent event) { 687 int proposedRotation; 688 int oldProposedRotation; 689 690 synchronized (mLock) { 691 // The vector given in the SensorEvent points straight up (towards the sky) under 692 // ideal conditions (the phone is not accelerating). I'll call this up vector 693 // elsewhere. 694 float x = event.values[ACCELEROMETER_DATA_X]; 695 float y = event.values[ACCELEROMETER_DATA_Y]; 696 float z = event.values[ACCELEROMETER_DATA_Z]; 697 698 if (LOG) { 699 Slog.v(TAG, "Raw acceleration vector: " 700 + "x=" + x + ", y=" + y + ", z=" + z 701 + ", magnitude=" + Math.sqrt(x * x + y * y + z * z)); 702 } 703 704 // Apply a low-pass filter to the acceleration up vector in cartesian space. 705 // Reset the orientation listener state if the samples are too far apart in time 706 // or when we see values of (0, 0, 0) which indicates that we polled the 707 // accelerometer too soon after turning it on and we don't have any data yet. 708 final long now = event.timestamp; 709 final long then = mLastFilteredTimestampNanos; 710 final float timeDeltaMS = (now - then) * 0.000001f; 711 final boolean skipSample; 712 if (now < then 713 || now > then + MAX_FILTER_DELTA_TIME_NANOS 714 || (x == 0 && y == 0 && z == 0)) { 715 if (LOG) { 716 Slog.v(TAG, "Resetting orientation listener."); 717 } 718 resetLocked(true /* clearCurrentRotation */); 719 skipSample = true; 720 } else { 721 final float alpha = timeDeltaMS / (FILTER_TIME_CONSTANT_MS + timeDeltaMS); 722 x = alpha * (x - mLastFilteredX) + mLastFilteredX; 723 y = alpha * (y - mLastFilteredY) + mLastFilteredY; 724 z = alpha * (z - mLastFilteredZ) + mLastFilteredZ; 725 if (LOG) { 726 Slog.v(TAG, "Filtered acceleration vector: " 727 + "x=" + x + ", y=" + y + ", z=" + z 728 + ", magnitude=" + Math.sqrt(x * x + y * y + z * z)); 729 } 730 skipSample = false; 731 } 732 mLastFilteredTimestampNanos = now; 733 mLastFilteredX = x; 734 mLastFilteredY = y; 735 mLastFilteredZ = z; 736 737 boolean isAccelerating = false; 738 boolean isFlat = false; 739 boolean isSwinging = false; 740 if (!skipSample) { 741 // Calculate the magnitude of the acceleration vector. 742 final float magnitude = (float) Math.sqrt(x * x + y * y + z * z); 743 if (magnitude < NEAR_ZERO_MAGNITUDE) { 744 if (LOG) { 745 Slog.v(TAG, "Ignoring sensor data, magnitude too close to zero."); 746 } 747 clearPredictedRotationLocked(); 748 } else { 749 // Determine whether the device appears to be undergoing external 750 // acceleration. 751 if (isAcceleratingLocked(magnitude)) { 752 isAccelerating = true; 753 mAccelerationTimestampNanos = now; 754 } 755 756 // Calculate the tilt angle. 757 // This is the angle between the up vector and the x-y plane (the plane of 758 // the screen) in a range of [-90, 90] degrees. 759 // -90 degrees: screen horizontal and facing the ground (overhead) 760 // 0 degrees: screen vertical 761 // 90 degrees: screen horizontal and facing the sky (on table) 762 final int tiltAngle = (int) Math.round( 763 Math.asin(z / magnitude) * RADIANS_TO_DEGREES); 764 addTiltHistoryEntryLocked(now, tiltAngle); 765 766 // Determine whether the device appears to be flat or swinging. 767 if (isFlatLocked(now)) { 768 isFlat = true; 769 mFlatTimestampNanos = now; 770 } 771 if (isSwingingLocked(now, tiltAngle)) { 772 isSwinging = true; 773 mSwingTimestampNanos = now; 774 } 775 776 // If the tilt angle is too close to horizontal then we cannot determine 777 // the orientation angle of the screen. 778 if (tiltAngle <= TILT_OVERHEAD_ENTER) { 779 mOverhead = true; 780 } else if (tiltAngle >= TILT_OVERHEAD_EXIT) { 781 mOverhead = false; 782 } 783 if (mOverhead) { 784 if (LOG) { 785 Slog.v(TAG, "Ignoring sensor data, device is overhead: " 786 + "tiltAngle=" + tiltAngle); 787 } 788 clearPredictedRotationLocked(); 789 } else if (Math.abs(tiltAngle) > MAX_TILT) { 790 if (LOG) { 791 Slog.v(TAG, "Ignoring sensor data, tilt angle too high: " 792 + "tiltAngle=" + tiltAngle); 793 } 794 clearPredictedRotationLocked(); 795 } else { 796 // Calculate the orientation angle. 797 // This is the angle between the x-y projection of the up vector onto 798 // the +y-axis, increasing clockwise in a range of [0, 360] degrees. 799 int orientationAngle = (int) Math.round( 800 -Math.atan2(-x, y) * RADIANS_TO_DEGREES); 801 if (orientationAngle < 0) { 802 // atan2 returns [-180, 180]; normalize to [0, 360] 803 orientationAngle += 360; 804 } 805 806 // Find the nearest rotation. 807 int nearestRotation = (orientationAngle + 45) / 90; 808 if (nearestRotation == 4) { 809 nearestRotation = 0; 810 } 811 812 // Determine the predicted orientation. 813 if (isTiltAngleAcceptableLocked(nearestRotation, tiltAngle) 814 && isOrientationAngleAcceptableLocked(nearestRotation, 815 orientationAngle)) { 816 updatePredictedRotationLocked(now, nearestRotation); 817 if (LOG) { 818 Slog.v(TAG, "Predicted: " 819 + "tiltAngle=" + tiltAngle 820 + ", orientationAngle=" + orientationAngle 821 + ", predictedRotation=" + mPredictedRotation 822 + ", predictedRotationAgeMS=" 823 + ((now - mPredictedRotationTimestampNanos) 824 * 0.000001f)); 825 } 826 } else { 827 if (LOG) { 828 Slog.v(TAG, "Ignoring sensor data, no predicted rotation: " 829 + "tiltAngle=" + tiltAngle 830 + ", orientationAngle=" + orientationAngle); 831 } 832 clearPredictedRotationLocked(); 833 } 834 } 835 } 836 } 837 mFlat = isFlat; 838 mSwinging = isSwinging; 839 mAccelerating = isAccelerating; 840 841 // Determine new proposed rotation. 842 oldProposedRotation = mProposedRotation; 843 if (mPredictedRotation < 0 || isPredictedRotationAcceptableLocked(now)) { 844 mProposedRotation = mPredictedRotation; 845 } 846 proposedRotation = mProposedRotation; 847 848 // Write final statistics about where we are in the orientation detection process. 849 if (LOG) { 850 Slog.v(TAG, "Result: currentRotation=" + mCurrentRotation 851 + ", proposedRotation=" + proposedRotation 852 + ", predictedRotation=" + mPredictedRotation 853 + ", timeDeltaMS=" + timeDeltaMS 854 + ", isAccelerating=" + isAccelerating 855 + ", isFlat=" + isFlat 856 + ", isSwinging=" + isSwinging 857 + ", isOverhead=" + mOverhead 858 + ", isTouched=" + mTouched 859 + ", timeUntilSettledMS=" + remainingMS(now, 860 mPredictedRotationTimestampNanos + PROPOSAL_SETTLE_TIME_NANOS) 861 + ", timeUntilAccelerationDelayExpiredMS=" + remainingMS(now, 862 mAccelerationTimestampNanos + PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS) 863 + ", timeUntilFlatDelayExpiredMS=" + remainingMS(now, 864 mFlatTimestampNanos + PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS) 865 + ", timeUntilSwingDelayExpiredMS=" + remainingMS(now, 866 mSwingTimestampNanos + PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS) 867 + ", timeUntilTouchDelayExpiredMS=" + remainingMS(now, 868 mTouchEndedTimestampNanos + PROPOSAL_MIN_TIME_SINCE_TOUCH_END_NANOS)); 869 } 870 } 871 872 // Tell the listener. 873 if (proposedRotation != oldProposedRotation && proposedRotation >= 0) { 874 if (LOG) { 875 Slog.v(TAG, "Proposed rotation changed! proposedRotation=" + proposedRotation 876 + ", oldProposedRotation=" + oldProposedRotation); 877 } 878 onProposedRotationChanged(proposedRotation); 879 } 880 } 881 882 @Override onTouchStartLocked()883 public void onTouchStartLocked() { 884 mTouched = true; 885 } 886 887 @Override onTouchEndLocked(long whenElapsedNanos)888 public void onTouchEndLocked(long whenElapsedNanos) { 889 mTouched = false; 890 mTouchEndedTimestampNanos = whenElapsedNanos; 891 } 892 893 @Override resetLocked(boolean clearCurrentRotation)894 public void resetLocked(boolean clearCurrentRotation) { 895 mLastFilteredTimestampNanos = Long.MIN_VALUE; 896 if (clearCurrentRotation) { 897 mProposedRotation = -1; 898 } 899 mFlatTimestampNanos = Long.MIN_VALUE; 900 mFlat = false; 901 mSwingTimestampNanos = Long.MIN_VALUE; 902 mSwinging = false; 903 mAccelerationTimestampNanos = Long.MIN_VALUE; 904 mAccelerating = false; 905 mOverhead = false; 906 clearPredictedRotationLocked(); 907 clearTiltHistoryLocked(); 908 } 909 910 911 /** 912 * Returns true if the tilt angle is acceptable for a given predicted rotation. 913 */ isTiltAngleAcceptableLocked(int rotation, int tiltAngle)914 private boolean isTiltAngleAcceptableLocked(int rotation, int tiltAngle) { 915 return tiltAngle >= mTiltToleranceConfig[rotation][0] 916 && tiltAngle <= mTiltToleranceConfig[rotation][1]; 917 } 918 919 /** 920 * Returns true if the orientation angle is acceptable for a given predicted rotation. 921 * 922 * This function takes into account the gap between adjacent orientations 923 * for hysteresis. 924 */ isOrientationAngleAcceptableLocked(int rotation, int orientationAngle)925 private boolean isOrientationAngleAcceptableLocked(int rotation, int orientationAngle) { 926 // If there is no current rotation, then there is no gap. 927 // The gap is used only to introduce hysteresis among advertised orientation 928 // changes to avoid flapping. 929 final int currentRotation = mCurrentRotation; 930 if (currentRotation >= 0) { 931 // If the specified rotation is the same or is counter-clockwise adjacent 932 // to the current rotation, then we set a lower bound on the orientation angle. 933 // For example, if currentRotation is ROTATION_0 and proposed is ROTATION_90, 934 // then we want to check orientationAngle > 45 + GAP / 2. 935 if (rotation == currentRotation 936 || rotation == (currentRotation + 1) % 4) { 937 int lowerBound = rotation * 90 - 45 938 + ADJACENT_ORIENTATION_ANGLE_GAP / 2; 939 if (rotation == 0) { 940 if (orientationAngle >= 315 && orientationAngle < lowerBound + 360) { 941 return false; 942 } 943 } else { 944 if (orientationAngle < lowerBound) { 945 return false; 946 } 947 } 948 } 949 950 // If the specified rotation is the same or is clockwise adjacent, 951 // then we set an upper bound on the orientation angle. 952 // For example, if currentRotation is ROTATION_0 and rotation is ROTATION_270, 953 // then we want to check orientationAngle < 315 - GAP / 2. 954 if (rotation == currentRotation 955 || rotation == (currentRotation + 3) % 4) { 956 int upperBound = rotation * 90 + 45 957 - ADJACENT_ORIENTATION_ANGLE_GAP / 2; 958 if (rotation == 0) { 959 if (orientationAngle <= 45 && orientationAngle > upperBound) { 960 return false; 961 } 962 } else { 963 if (orientationAngle > upperBound) { 964 return false; 965 } 966 } 967 } 968 } 969 return true; 970 } 971 972 /** 973 * Returns true if the predicted rotation is ready to be advertised as a 974 * proposed rotation. 975 */ isPredictedRotationAcceptableLocked(long now)976 private boolean isPredictedRotationAcceptableLocked(long now) { 977 // The predicted rotation must have settled long enough. 978 if (now < mPredictedRotationTimestampNanos + PROPOSAL_SETTLE_TIME_NANOS) { 979 return false; 980 } 981 982 // The last flat state (time since picked up) must have been sufficiently long ago. 983 if (now < mFlatTimestampNanos + PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS) { 984 return false; 985 } 986 987 // The last swing state (time since last movement to put down) must have been 988 // sufficiently long ago. 989 if (now < mSwingTimestampNanos + PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS) { 990 return false; 991 } 992 993 // The last acceleration state must have been sufficiently long ago. 994 if (now < mAccelerationTimestampNanos 995 + PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS) { 996 return false; 997 } 998 999 // The last touch must have ended sufficiently long ago. 1000 if (mTouched || now < mTouchEndedTimestampNanos 1001 + PROPOSAL_MIN_TIME_SINCE_TOUCH_END_NANOS) { 1002 return false; 1003 } 1004 1005 // Looks good! 1006 return true; 1007 } 1008 clearPredictedRotationLocked()1009 private void clearPredictedRotationLocked() { 1010 mPredictedRotation = -1; 1011 mPredictedRotationTimestampNanos = Long.MIN_VALUE; 1012 } 1013 updatePredictedRotationLocked(long now, int rotation)1014 private void updatePredictedRotationLocked(long now, int rotation) { 1015 if (mPredictedRotation != rotation) { 1016 mPredictedRotation = rotation; 1017 mPredictedRotationTimestampNanos = now; 1018 } 1019 } 1020 isAcceleratingLocked(float magnitude)1021 private boolean isAcceleratingLocked(float magnitude) { 1022 return magnitude < MIN_ACCELERATION_MAGNITUDE 1023 || magnitude > MAX_ACCELERATION_MAGNITUDE; 1024 } 1025 clearTiltHistoryLocked()1026 private void clearTiltHistoryLocked() { 1027 mTiltHistoryTimestampNanos[0] = Long.MIN_VALUE; 1028 mTiltHistoryIndex = 1; 1029 } 1030 addTiltHistoryEntryLocked(long now, float tilt)1031 private void addTiltHistoryEntryLocked(long now, float tilt) { 1032 mTiltHistory[mTiltHistoryIndex] = tilt; 1033 mTiltHistoryTimestampNanos[mTiltHistoryIndex] = now; 1034 mTiltHistoryIndex = (mTiltHistoryIndex + 1) % TILT_HISTORY_SIZE; 1035 mTiltHistoryTimestampNanos[mTiltHistoryIndex] = Long.MIN_VALUE; 1036 } 1037 isFlatLocked(long now)1038 private boolean isFlatLocked(long now) { 1039 for (int i = mTiltHistoryIndex; (i = nextTiltHistoryIndexLocked(i)) >= 0; ) { 1040 if (mTiltHistory[i] < FLAT_ANGLE) { 1041 break; 1042 } 1043 if (mTiltHistoryTimestampNanos[i] + FLAT_TIME_NANOS <= now) { 1044 // Tilt has remained greater than FLAT_TILT_ANGLE for FLAT_TIME_NANOS. 1045 return true; 1046 } 1047 } 1048 return false; 1049 } 1050 isSwingingLocked(long now, float tilt)1051 private boolean isSwingingLocked(long now, float tilt) { 1052 for (int i = mTiltHistoryIndex; (i = nextTiltHistoryIndexLocked(i)) >= 0; ) { 1053 if (mTiltHistoryTimestampNanos[i] + SWING_TIME_NANOS < now) { 1054 break; 1055 } 1056 if (mTiltHistory[i] + SWING_AWAY_ANGLE_DELTA <= tilt) { 1057 // Tilted away by SWING_AWAY_ANGLE_DELTA within SWING_TIME_NANOS. 1058 return true; 1059 } 1060 } 1061 return false; 1062 } 1063 nextTiltHistoryIndexLocked(int index)1064 private int nextTiltHistoryIndexLocked(int index) { 1065 index = (index == 0 ? TILT_HISTORY_SIZE : index) - 1; 1066 return mTiltHistoryTimestampNanos[index] != Long.MIN_VALUE ? index : -1; 1067 } 1068 getLastTiltLocked()1069 private float getLastTiltLocked() { 1070 int index = nextTiltHistoryIndexLocked(mTiltHistoryIndex); 1071 return index >= 0 ? mTiltHistory[index] : Float.NaN; 1072 } 1073 remainingMS(long now, long until)1074 private float remainingMS(long now, long until) { 1075 return now >= until ? 0 : (until - now) * 0.000001f; 1076 } 1077 } 1078 1079 final class OrientationSensorJudge extends OrientationJudge { 1080 private static final int ROTATION_UNSET = -1; 1081 private boolean mTouching; 1082 private long mTouchEndedTimestampNanos = Long.MIN_VALUE; 1083 private int mProposedRotation = -1; 1084 private int mDesiredRotation = -1; 1085 private boolean mRotationEvaluationScheduled; 1086 private long mRotationResolverTimeoutMillis; 1087 private long mRotationMemorizationTimeoutMillis; 1088 private final ActivityTaskManagerInternal mActivityTaskManagerInternal; 1089 private long mLastRotationResolutionTimeStamp; 1090 private int mLastRotationResolution = ROTATION_UNSET; 1091 private int mCurrentCallbackId = 0; 1092 private Runnable mCancelRotationResolverRequest; 1093 OrientationSensorJudge()1094 OrientationSensorJudge() { 1095 super(); 1096 setupRotationResolverParameters(); 1097 1098 mActivityTaskManagerInternal = 1099 LocalServices.getService(ActivityTaskManagerInternal.class); 1100 } 1101 setupRotationResolverParameters()1102 private void setupRotationResolverParameters() { 1103 DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_WINDOW_MANAGER, 1104 ActivityThread.currentApplication().getMainExecutor(), (properties) -> { 1105 final Set<String> keys = properties.getKeyset(); 1106 if (keys.contains(KEY_ROTATION_RESOLVER_TIMEOUT) 1107 || keys.contains(KEY_ROTATION_MEMORIZATION_TIMEOUT)) { 1108 readRotationResolverParameters(); 1109 } 1110 }); 1111 readRotationResolverParameters(); 1112 } 1113 readRotationResolverParameters()1114 private void readRotationResolverParameters() { 1115 mRotationResolverTimeoutMillis = DeviceConfig.getLong( 1116 NAMESPACE_WINDOW_MANAGER, 1117 KEY_ROTATION_RESOLVER_TIMEOUT, 1118 DEFAULT_ROTATION_RESOLVER_TIMEOUT_MILLIS); 1119 mRotationMemorizationTimeoutMillis = DeviceConfig.getLong( 1120 NAMESPACE_WINDOW_MANAGER, 1121 KEY_ROTATION_MEMORIZATION_TIMEOUT, 1122 DEFAULT_ROTATION_MEMORIZATION_TIMEOUT_MILLIS); 1123 } 1124 1125 @Override getProposedRotationLocked()1126 public int getProposedRotationLocked() { 1127 return mProposedRotation; 1128 } 1129 1130 @Override onTouchStartLocked()1131 public void onTouchStartLocked() { 1132 mTouching = true; 1133 } 1134 1135 @Override onTouchEndLocked(long whenElapsedNanos)1136 public void onTouchEndLocked(long whenElapsedNanos) { 1137 mTouching = false; 1138 mTouchEndedTimestampNanos = whenElapsedNanos; 1139 if (mDesiredRotation != mProposedRotation) { 1140 final long now = SystemClock.elapsedRealtimeNanos(); 1141 scheduleRotationEvaluationIfNecessaryLocked(now); 1142 } 1143 } 1144 1145 1146 @Override onSensorChanged(SensorEvent event)1147 public void onSensorChanged(SensorEvent event) { 1148 int reportedRotation = (int) event.values[0]; 1149 if (reportedRotation < 0 || reportedRotation > 3) { 1150 return; 1151 } 1152 1153 FrameworkStatsLog.write( 1154 FrameworkStatsLog.DEVICE_ROTATED, 1155 event.timestamp, 1156 rotationToLogEnum(reportedRotation), 1157 FrameworkStatsLog.DEVICE_ROTATED__ROTATION_EVENT_TYPE__ACTUAL_EVENT); 1158 1159 if (isRotationResolverEnabled()) { 1160 if (isKeyguardShowingAndNotOccluded()) { 1161 if (mLastRotationResolution != ROTATION_UNSET 1162 && SystemClock.uptimeMillis() - mLastRotationResolutionTimeStamp 1163 < mRotationMemorizationTimeoutMillis) { 1164 Slog.d(TAG, 1165 "Reusing the last rotation resolution: " + mLastRotationResolution); 1166 finalizeRotation(mLastRotationResolution); 1167 } else { 1168 finalizeRotation(mDefaultRotation); 1169 } 1170 return; 1171 } 1172 1173 if (mRotationResolverService == null) { 1174 mRotationResolverService = LocalServices.getService( 1175 RotationResolverInternal.class); 1176 if (mRotationResolverService == null) { 1177 finalizeRotation(reportedRotation); 1178 return; 1179 } 1180 } 1181 1182 String packageName = null; 1183 if (mActivityTaskManagerInternal != null) { 1184 final WindowProcessController controller = 1185 mActivityTaskManagerInternal.getTopApp(); 1186 if (controller != null 1187 && controller.mInfo != null 1188 && controller.mInfo.packageName != null) { 1189 packageName = controller.mInfo.packageName; 1190 } 1191 } 1192 1193 mCurrentCallbackId++; 1194 1195 if (mCancelRotationResolverRequest != null) { 1196 getHandler().removeCallbacks(mCancelRotationResolverRequest); 1197 } 1198 final CancellationSignal cancellationSignal = new CancellationSignal(); 1199 mCancelRotationResolverRequest = cancellationSignal::cancel; 1200 getHandler().postDelayed( 1201 mCancelRotationResolverRequest, mRotationResolverTimeoutMillis); 1202 1203 mRotationResolverService.resolveRotation( 1204 new RotationResolverInternal.RotationResolverCallbackInternal() { 1205 private final int mCallbackId = mCurrentCallbackId; 1206 @Override 1207 public void onSuccess(int result) { 1208 finalizeRotationIfFresh(result); 1209 } 1210 1211 @Override 1212 public void onFailure(int error) { 1213 finalizeRotationIfFresh(reportedRotation); 1214 } 1215 1216 private void finalizeRotationIfFresh(int rotation) { 1217 // Ignore the callback if it's not the latest. 1218 if (mCallbackId == mCurrentCallbackId) { 1219 getHandler().removeCallbacks(mCancelRotationResolverRequest); 1220 finalizeRotation(rotation); 1221 } else { 1222 Slog.d(TAG, String.format( 1223 "An outdated callback received [%s vs. %s]. Ignoring " 1224 + "it.", 1225 mCallbackId, mCurrentCallbackId)); 1226 } 1227 } 1228 }, 1229 packageName, 1230 reportedRotation, 1231 mCurrentRotation, 1232 mRotationResolverTimeoutMillis, 1233 cancellationSignal); 1234 } else { 1235 finalizeRotation(reportedRotation); 1236 } 1237 } 1238 1239 @Override onAccuracyChanged(Sensor sensor, int accuracy)1240 public void onAccuracyChanged(Sensor sensor, int accuracy) { } 1241 1242 @Override dumpLocked(PrintWriter pw, String prefix)1243 public void dumpLocked(PrintWriter pw, String prefix) { 1244 pw.println(prefix + "OrientationSensorJudge"); 1245 prefix += " "; 1246 pw.println(prefix + "mDesiredRotation=" + Surface.rotationToString(mDesiredRotation)); 1247 pw.println(prefix + "mProposedRotation=" 1248 + Surface.rotationToString(mProposedRotation)); 1249 pw.println(prefix + "mTouching=" + mTouching); 1250 pw.println(prefix + "mTouchEndedTimestampNanos=" + mTouchEndedTimestampNanos); 1251 pw.println(prefix + "mLastRotationResolution=" + mLastRotationResolution); 1252 } 1253 1254 @Override resetLocked(boolean clearCurrentRotation)1255 public void resetLocked(boolean clearCurrentRotation) { 1256 if (clearCurrentRotation) { 1257 mProposedRotation = -1; 1258 mDesiredRotation = -1; 1259 } 1260 mTouching = false; 1261 mTouchEndedTimestampNanos = Long.MIN_VALUE; 1262 unscheduleRotationEvaluationLocked(); 1263 } 1264 evaluateRotationChangeLocked()1265 public int evaluateRotationChangeLocked() { 1266 unscheduleRotationEvaluationLocked(); 1267 if (mDesiredRotation == mProposedRotation) { 1268 return -1; 1269 } 1270 final long now = SystemClock.elapsedRealtimeNanos(); 1271 if (isDesiredRotationAcceptableLocked(now)) { 1272 mProposedRotation = mDesiredRotation; 1273 return mProposedRotation; 1274 } else { 1275 scheduleRotationEvaluationIfNecessaryLocked(now); 1276 } 1277 return -1; 1278 } 1279 finalizeRotation(int reportedRotation)1280 private void finalizeRotation(int reportedRotation) { 1281 int newRotation; 1282 synchronized (mLock) { 1283 mDesiredRotation = reportedRotation; 1284 newRotation = evaluateRotationChangeLocked(); 1285 } 1286 if (newRotation >= 0) { 1287 mLastRotationResolution = newRotation; 1288 mLastRotationResolutionTimeStamp = SystemClock.uptimeMillis(); 1289 onProposedRotationChanged(newRotation); 1290 } 1291 } 1292 isDesiredRotationAcceptableLocked(long now)1293 private boolean isDesiredRotationAcceptableLocked(long now) { 1294 if (mTouching) { 1295 return false; 1296 } 1297 if (now < mTouchEndedTimestampNanos + PROPOSAL_MIN_TIME_SINCE_TOUCH_END_NANOS) { 1298 return false; 1299 } 1300 return true; 1301 } 1302 scheduleRotationEvaluationIfNecessaryLocked(long now)1303 private void scheduleRotationEvaluationIfNecessaryLocked(long now) { 1304 if (mRotationEvaluationScheduled || mDesiredRotation == mProposedRotation) { 1305 if (LOG) { 1306 Slog.d(TAG, "scheduleRotationEvaluationLocked: " + 1307 "ignoring, an evaluation is already scheduled or is unnecessary."); 1308 } 1309 return; 1310 } 1311 if (mTouching) { 1312 if (LOG) { 1313 Slog.d(TAG, "scheduleRotationEvaluationLocked: " + 1314 "ignoring, user is still touching the screen."); 1315 } 1316 return; 1317 } 1318 long timeOfNextPossibleRotationNanos = 1319 mTouchEndedTimestampNanos + PROPOSAL_MIN_TIME_SINCE_TOUCH_END_NANOS; 1320 if (now >= timeOfNextPossibleRotationNanos) { 1321 if (LOG) { 1322 Slog.d(TAG, "scheduleRotationEvaluationLocked: " + 1323 "ignoring, already past the next possible time of rotation."); 1324 } 1325 return; 1326 } 1327 // Use a delay instead of an absolute time since handlers are in uptime millis and we 1328 // use elapsed realtime. 1329 final long delayMs = 1330 (long) Math.ceil((timeOfNextPossibleRotationNanos - now) * MILLIS_PER_NANO); 1331 mHandler.postDelayed(mRotationEvaluator, delayMs); 1332 mRotationEvaluationScheduled = true; 1333 } 1334 unscheduleRotationEvaluationLocked()1335 private void unscheduleRotationEvaluationLocked() { 1336 if (!mRotationEvaluationScheduled) { 1337 return; 1338 } 1339 mHandler.removeCallbacks(mRotationEvaluator); 1340 mRotationEvaluationScheduled = false; 1341 } 1342 1343 private Runnable mRotationEvaluator = new Runnable() { 1344 @Override 1345 public void run() { 1346 int newRotation; 1347 synchronized (mLock) { 1348 mRotationEvaluationScheduled = false; 1349 newRotation = evaluateRotationChangeLocked(); 1350 } 1351 if (newRotation >= 0) { 1352 onProposedRotationChanged(newRotation); 1353 } 1354 } 1355 }; 1356 rotationToLogEnum(int rotation)1357 private int rotationToLogEnum(int rotation) { 1358 switch (rotation) { 1359 case 0: 1360 return FrameworkStatsLog.DEVICE_ROTATED__PROPOSED_ORIENTATION__ROTATION_0; 1361 case 1: 1362 return FrameworkStatsLog.DEVICE_ROTATED__PROPOSED_ORIENTATION__ROTATION_90; 1363 case 2: 1364 return FrameworkStatsLog.DEVICE_ROTATED__PROPOSED_ORIENTATION__ROTATION_180; 1365 case 3: 1366 return FrameworkStatsLog.DEVICE_ROTATED__PROPOSED_ORIENTATION__ROTATION_270; 1367 default: 1368 return FrameworkStatsLog.DEVICE_ROTATED__PROPOSED_ORIENTATION__UNKNOWN; 1369 } 1370 } 1371 } 1372 } 1373