DisplayPowerController.java revision 13c589b66c47aa4d988eecce9a12c39d580939c9
1/* 2 * Copyright (C) 2012 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 17package com.android.server.power; 18 19import com.android.server.LightsService; 20 21import android.animation.Animator; 22import android.animation.ObjectAnimator; 23import android.content.Context; 24import android.content.res.Resources; 25import android.hardware.Sensor; 26import android.hardware.SensorEvent; 27import android.hardware.SensorEventListener; 28import android.hardware.SensorManager; 29import android.hardware.SystemSensorManager; 30import android.os.AsyncTask; 31import android.os.Handler; 32import android.os.Looper; 33import android.os.Message; 34import android.os.SystemClock; 35import android.util.Slog; 36import android.util.Spline; 37import android.util.TimeUtils; 38 39import java.io.PrintWriter; 40import java.io.StringWriter; 41import java.util.concurrent.CountDownLatch; 42import java.util.concurrent.Executor; 43 44/** 45 * Controls the power state of the display. 46 * 47 * Handles the proximity sensor, light sensor, and animations between states 48 * including the screen off animation. 49 * 50 * This component acts independently of the rest of the power manager service. 51 * In particular, it does not share any state and it only communicates 52 * via asynchronous callbacks to inform the power manager that something has 53 * changed. 54 * 55 * Everything this class does internally is serialized on its handler although 56 * it may be accessed by other threads from the outside. 57 * 58 * Note that the power manager service guarantees that it will hold a suspend 59 * blocker as long as the display is not ready. So most of the work done here 60 * does not need to worry about holding a suspend blocker unless it happens 61 * independently of the display ready signal. 62 * 63 * For debugging, you can make the electron beam and brightness animations run 64 * slower by changing the "animator duration scale" option in Development Settings. 65 */ 66final class DisplayPowerController { 67 private static final String TAG = "DisplayPowerController"; 68 69 private static boolean DEBUG = false; 70 private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false; 71 private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false; 72 73 // If true, uses the electron beam on animation. 74 // We might want to turn this off if we cannot get a guarantee that the screen 75 // actually turns on and starts showing new content after the call to set the 76 // screen state returns. 77 private static final boolean USE_ELECTRON_BEAM_ON_ANIMATION = true; 78 79 private static final int ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS = 300; 80 private static final int ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS = 600; 81 82 private static final int MSG_UPDATE_POWER_STATE = 1; 83 private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 2; 84 private static final int MSG_LIGHT_SENSOR_DEBOUNCED = 3; 85 86 private static final int PROXIMITY_UNKNOWN = -1; 87 private static final int PROXIMITY_NEGATIVE = 0; 88 private static final int PROXIMITY_POSITIVE = 1; 89 90 // Proximity sensor debounce delay in milliseconds. 91 private static final int PROXIMITY_SENSOR_DEBOUNCE_DELAY = 250; 92 93 // Trigger proximity if distance is less than 5 cm. 94 private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f; 95 96 // Light sensor event rate in microseconds. 97 private static final int LIGHT_SENSOR_RATE = 1000000; 98 99 // Brightness animation ramp rate in brightness units per second. 100 private static final int BRIGHTNESS_RAMP_RATE_FAST = 200; 101 private static final int BRIGHTNESS_RAMP_RATE_SLOW = 50; 102 103 // Filter time constant in milliseconds for computing a moving 104 // average of light samples. Different constants are used 105 // to calculate the average light level when adapting to brighter or 106 // dimmer environments. 107 // This parameter only controls the filtering of light samples. 108 private static final long BRIGHTENING_LIGHT_TIME_CONSTANT = 500; 109 private static final long DIMMING_LIGHT_TIME_CONSTANT = 2000; 110 111 // Stability requirements in milliseconds for accepting a new brightness 112 // level. This is used for debouncing the light sensor. Different constants 113 // are used to debounce the light sensor when adapting to brighter or dimmer 114 // environments. 115 // This parameter controls how quickly brightness changes occur in response to 116 // an observed change in light level. 117 private static final long BRIGHTENING_LIGHT_DEBOUNCE = 2500; 118 private static final long DIMMING_LIGHT_DEBOUNCE = 10000; 119 120 private final Object mLock = new Object(); 121 122 // Notifier for sending asynchronous notifications. 123 private final Notifier mNotifier; 124 125 // A suspend blocker. 126 private final SuspendBlocker mSuspendBlocker; 127 128 // Our handler. 129 private final DisplayControllerHandler mHandler; 130 131 // Asynchronous callbacks into the power manager service. 132 // Only invoked from the handler thread while no locks are held. 133 private final Callbacks mCallbacks; 134 private Handler mCallbackHandler; 135 136 // The lights service. 137 private final LightsService mLights; 138 139 // The sensor manager. 140 private final SensorManager mSensorManager; 141 142 // The proximity sensor, or null if not available or needed. 143 private Sensor mProximitySensor; 144 145 // The light sensor, or null if not available or needed. 146 private Sensor mLightSensor; 147 148 // The dim screen brightness. 149 private final int mScreenBrightnessDimConfig; 150 151 // Auto-brightness. 152 private boolean mUseSoftwareAutoBrightnessConfig; 153 private Spline mScreenAutoBrightnessSpline; 154 155 // Amount of time to delay auto-brightness after screen on while waiting for 156 // the light sensor to warm-up in milliseconds. 157 // May be 0 if no warm-up is required. 158 private int mLightSensorWarmUpTimeConfig; 159 160 // The pending power request. 161 // Initially null until the first call to requestPowerState. 162 // Guarded by mLock. 163 private DisplayPowerRequest mPendingRequestLocked; 164 165 // True if a request has been made to wait for the proximity sensor to go negative. 166 // Guarded by mLock. 167 private boolean mPendingWaitForNegativeProximityLocked; 168 169 // True if the pending power request or wait for negative proximity flag 170 // has been changed since the last update occurred. 171 // Guarded by mLock. 172 private boolean mPendingRequestChangedLocked; 173 174 // Set to true when the important parts of the pending power request have been applied. 175 // The important parts are mainly the screen state. Brightness changes may occur 176 // concurrently. 177 // Guarded by mLock. 178 private boolean mDisplayReadyLocked; 179 180 // Set to true if a power state update is required. 181 // Guarded by mLock. 182 private boolean mPendingUpdatePowerStateLocked; 183 184 /* The following state must only be accessed by the handler thread. */ 185 186 // The currently requested power state. 187 // The power controller will progressively update its internal state to match 188 // the requested power state. Initially null until the first update. 189 private DisplayPowerRequest mPowerRequest; 190 191 // The current power state. 192 // Must only be accessed on the handler thread. 193 private DisplayPowerState mPowerState; 194 195 // True if the device should wait for negative proximity sensor before 196 // waking up the screen. This is set to false as soon as a negative 197 // proximity sensor measurement is observed or when the device is forced to 198 // go to sleep by the user. While true, the screen remains off. 199 private boolean mWaitingForNegativeProximity; 200 201 // The actual proximity sensor threshold value. 202 private float mProximityThreshold; 203 204 // Set to true if the proximity sensor listener has been registered 205 // with the sensor manager. 206 private boolean mProximitySensorEnabled; 207 208 // The debounced proximity sensor state. 209 private int mProximity = PROXIMITY_UNKNOWN; 210 211 // The raw non-debounced proximity sensor state. 212 private int mPendingProximity = PROXIMITY_UNKNOWN; 213 private long mPendingProximityDebounceTime; 214 215 // True if the screen was turned off because of the proximity sensor. 216 // When the screen turns on again, we report user activity to the power manager. 217 private boolean mScreenOffBecauseOfProximity; 218 219 // Set to true if the light sensor is enabled. 220 private boolean mLightSensorEnabled; 221 222 // The time when the light sensor was enabled. 223 private long mLightSensorEnableTime; 224 225 // The currently accepted average light sensor value. 226 private float mLightMeasurement; 227 228 // True if the light sensor measurement is valid. 229 private boolean mLightMeasurementValid; 230 231 // The number of light sensor samples that have been collected since the 232 // last time a light sensor reading was accepted. 233 private int mRecentLightSamples; 234 235 // The moving average of recent light sensor values. 236 private float mRecentLightAverage; 237 238 // True if recent light samples are getting brighter than the previous 239 // stable light measurement. 240 private boolean mRecentLightBrightening; 241 242 // The time constant to use for filtering based on whether the 243 // light appears to be brightening or dimming. 244 private long mRecentLightTimeConstant; 245 246 // The most recent light sample. 247 private float mLastLightSample; 248 249 // The time of the most light recent sample. 250 private long mLastLightSampleTime; 251 252 // The time when we accumulated the first recent light sample into mRecentLightSamples. 253 private long mFirstRecentLightSampleTime; 254 255 // The upcoming debounce light sensor time. 256 // This is only valid when mLightMeasurementValue && mRecentLightSamples >= 1. 257 private long mPendingLightSensorDebounceTime; 258 259 // The screen brightness level that has been chosen by the auto-brightness 260 // algorithm. The actual brightness should ramp towards this value. 261 // We preserve this value even when we stop using the light sensor so 262 // that we can quickly revert to the previous auto-brightness level 263 // while the light sensor warms up. 264 // Use -1 if there is no current auto-brightness value available. 265 private int mScreenAutoBrightness = -1; 266 267 // True if the screen auto-brightness value is actually being used to 268 // set the display brightness. 269 private boolean mUsingScreenAutoBrightness; 270 271 // Animators. 272 private ObjectAnimator mElectronBeamOnAnimator; 273 private ObjectAnimator mElectronBeamOffAnimator; 274 private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator; 275 276 /** 277 * Creates the display power controller. 278 */ 279 public DisplayPowerController(Looper looper, Context context, Notifier notifier, 280 LightsService lights, SuspendBlocker suspendBlocker, 281 Callbacks callbacks, Handler callbackHandler) { 282 mHandler = new DisplayControllerHandler(looper); 283 mNotifier = notifier; 284 mSuspendBlocker = suspendBlocker; 285 mCallbacks = callbacks; 286 mCallbackHandler = callbackHandler; 287 288 mLights = lights; 289 mSensorManager = new SystemSensorManager(mHandler.getLooper()); 290 291 final Resources resources = context.getResources(); 292 mScreenBrightnessDimConfig = resources.getInteger( 293 com.android.internal.R.integer.config_screenBrightnessDim); 294 mUseSoftwareAutoBrightnessConfig = resources.getBoolean( 295 com.android.internal.R.bool.config_automatic_brightness_available); 296 if (mUseSoftwareAutoBrightnessConfig) { 297 int[] lux = resources.getIntArray( 298 com.android.internal.R.array.config_autoBrightnessLevels); 299 int[] screenBrightness = resources.getIntArray( 300 com.android.internal.R.array.config_autoBrightnessLcdBacklightValues); 301 302 mScreenAutoBrightnessSpline = createAutoBrightnessSpline(lux, screenBrightness); 303 if (mScreenAutoBrightnessSpline == null) { 304 Slog.e(TAG, "Error in config.xml. config_autoBrightnessLcdBacklightValues " 305 + "(size " + screenBrightness.length + ") " 306 + "must be monotic and have exactly one more entry than " 307 + "config_autoBrightnessLevels (size " + lux.length + ") " 308 + "which must be strictly increasing. " 309 + "Auto-brightness will be disabled."); 310 mUseSoftwareAutoBrightnessConfig = false; 311 } 312 313 mLightSensorWarmUpTimeConfig = resources.getInteger( 314 com.android.internal.R.integer.config_lightSensorWarmupTime); 315 } 316 317 if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) { 318 mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); 319 if (mProximitySensor != null) { 320 mProximityThreshold = Math.min(mProximitySensor.getMaximumRange(), 321 TYPICAL_PROXIMITY_THRESHOLD); 322 } 323 } 324 325 if (mUseSoftwareAutoBrightnessConfig 326 && !DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) { 327 mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); 328 } 329 } 330 331 private static Spline createAutoBrightnessSpline(int[] lux, int[] brightness) { 332 try { 333 final int n = brightness.length; 334 float[] x = new float[n]; 335 float[] y = new float[n]; 336 y[0] = brightness[0]; 337 for (int i = 1; i < n; i++) { 338 x[i] = lux[i - 1]; 339 y[i] = brightness[i]; 340 } 341 342 Spline spline = Spline.createMonotoneCubicSpline(x, y); 343 if (false) { 344 Slog.d(TAG, "Auto-brightness spline: " + spline); 345 for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) { 346 Slog.d(TAG, String.format(" %7.1f: %7.1f", v, spline.interpolate(v))); 347 } 348 } 349 return spline; 350 } catch (IllegalArgumentException ex) { 351 Slog.e(TAG, "Could not create auto-brightness spline.", ex); 352 return null; 353 } 354 } 355 356 /** 357 * Returns true if the proximity sensor screen-off function is available. 358 */ 359 public boolean isProximitySensorAvailable() { 360 return mProximitySensor != null; 361 } 362 363 /** 364 * Requests a new power state. 365 * The controller makes a copy of the provided object and then 366 * begins adjusting the power state to match what was requested. 367 * 368 * @param request The requested power state. 369 * @param waitForNegativeProximity If true, issues a request to wait for 370 * negative proximity before turning the screen back on, assuming the screen 371 * was turned off by the proximity sensor. 372 * @return True if display is ready, false if there are important changes that must 373 * be made asynchronously (such as turning the screen on), in which case the caller 374 * should grab a wake lock, watch for {@link Callbacks#onStateChanged()} then try 375 * the request again later until the state converges. 376 */ 377 public boolean requestPowerState(DisplayPowerRequest request, 378 boolean waitForNegativeProximity) { 379 if (DEBUG) { 380 Slog.d(TAG, "requestPowerState: " 381 + request + ", waitForNegativeProximity=" + waitForNegativeProximity); 382 } 383 384 synchronized (mLock) { 385 boolean changed = false; 386 387 if (waitForNegativeProximity 388 && !mPendingWaitForNegativeProximityLocked) { 389 mPendingWaitForNegativeProximityLocked = true; 390 changed = true; 391 } 392 393 if (mPendingRequestLocked == null) { 394 mPendingRequestLocked = new DisplayPowerRequest(request); 395 changed = true; 396 } else if (!mPendingRequestLocked.equals(request)) { 397 mPendingRequestLocked.copyFrom(request); 398 changed = true; 399 } 400 401 if (changed) { 402 mDisplayReadyLocked = false; 403 } 404 405 if (changed && !mPendingRequestChangedLocked) { 406 mPendingRequestChangedLocked = true; 407 sendUpdatePowerStateLocked(); 408 } 409 410 return mDisplayReadyLocked; 411 } 412 } 413 414 private void sendUpdatePowerState() { 415 synchronized (mLock) { 416 sendUpdatePowerStateLocked(); 417 } 418 } 419 420 private void sendUpdatePowerStateLocked() { 421 if (!mPendingUpdatePowerStateLocked) { 422 mPendingUpdatePowerStateLocked = true; 423 Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE); 424 msg.setAsynchronous(true); 425 mHandler.sendMessage(msg); 426 } 427 } 428 429 private void initialize() { 430 final Executor executor = AsyncTask.THREAD_POOL_EXECUTOR; 431 mPowerState = new DisplayPowerState(new ElectronBeam(), 432 new PhotonicModulator(executor, 433 mLights.getLight(LightsService.LIGHT_ID_BACKLIGHT), 434 mSuspendBlocker)); 435 436 mElectronBeamOnAnimator = ObjectAnimator.ofFloat( 437 mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f); 438 mElectronBeamOnAnimator.setDuration(ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS); 439 mElectronBeamOnAnimator.addListener(mAnimatorListener); 440 441 mElectronBeamOffAnimator = ObjectAnimator.ofFloat( 442 mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 1.0f, 0.0f); 443 mElectronBeamOffAnimator.setDuration(ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS); 444 mElectronBeamOffAnimator.addListener(mAnimatorListener); 445 446 mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>( 447 mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS); 448 } 449 450 private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() { 451 @Override 452 public void onAnimationStart(Animator animation) { 453 } 454 @Override 455 public void onAnimationEnd(Animator animation) { 456 sendUpdatePowerState(); 457 } 458 @Override 459 public void onAnimationRepeat(Animator animation) { 460 } 461 @Override 462 public void onAnimationCancel(Animator animation) { 463 } 464 }; 465 466 private void updatePowerState() { 467 // Update the power state request. 468 final boolean mustNotify; 469 boolean mustInitialize = false; 470 synchronized (mLock) { 471 mPendingUpdatePowerStateLocked = false; 472 if (mPendingRequestLocked == null) { 473 return; // wait until first actual power request 474 } 475 476 if (mPowerRequest == null) { 477 mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked); 478 mWaitingForNegativeProximity = mPendingWaitForNegativeProximityLocked; 479 mPendingRequestChangedLocked = false; 480 mustInitialize = true; 481 } else if (mPendingRequestChangedLocked) { 482 mPowerRequest.copyFrom(mPendingRequestLocked); 483 mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked; 484 mPendingRequestChangedLocked = false; 485 mDisplayReadyLocked = false; 486 } 487 488 mustNotify = !mDisplayReadyLocked; 489 } 490 491 // Initialize things the first time the power state is changed. 492 if (mustInitialize) { 493 initialize(); 494 } 495 496 // Clear a request to wait for negative proximity if needed. 497 if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_OFF 498 || mProximity == PROXIMITY_NEGATIVE 499 || mProximitySensor == null) { 500 mWaitingForNegativeProximity = false; 501 } 502 503 // Turn on the proximity sensor if needed. 504 if (mProximitySensor != null) { 505 setProximitySensorEnabled(mPowerRequest.useProximitySensor 506 || mWaitingForNegativeProximity); 507 if (mProximitySensorEnabled && mProximity == PROXIMITY_POSITIVE) { 508 mScreenOffBecauseOfProximity = true; 509 setScreenOn(false); 510 } else if (mScreenOffBecauseOfProximity) { 511 mScreenOffBecauseOfProximity = false; 512 sendOnProximityNegative(); 513 } 514 } 515 516 // Turn on the light sensor if needed. 517 if (mLightSensor != null) { 518 setLightSensorEnabled(mPowerRequest.useAutoBrightness 519 && wantScreenOn(mPowerRequest.screenState)); 520 } 521 522 // Set the screen brightness. 523 if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) { 524 // Screen is dimmed. Overrides everything else. 525 animateScreenBrightness(mScreenBrightnessDimConfig, BRIGHTNESS_RAMP_RATE_FAST); 526 mUsingScreenAutoBrightness = false; 527 } else if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT) { 528 if (mScreenAutoBrightness >= 0 && mLightSensorEnabled) { 529 // Use current auto-brightness value. 530 animateScreenBrightness( 531 Math.max(mScreenAutoBrightness, mScreenBrightnessDimConfig), 532 mUsingScreenAutoBrightness ? BRIGHTNESS_RAMP_RATE_SLOW : 533 BRIGHTNESS_RAMP_RATE_FAST); 534 mUsingScreenAutoBrightness = true; 535 } else { 536 // Light sensor is disabled or not ready yet. 537 // Use the current brightness setting from the request, which is expected 538 // provide a nominal default value for the case where auto-brightness 539 // is not ready yet. 540 animateScreenBrightness( 541 Math.max(mPowerRequest.screenBrightness, mScreenBrightnessDimConfig), 542 BRIGHTNESS_RAMP_RATE_FAST); 543 mUsingScreenAutoBrightness = false; 544 } 545 } else { 546 // Screen is off. Don't bother changing the brightness. 547 mUsingScreenAutoBrightness = false; 548 } 549 550 // Animate the screen on or off. 551 if (!mScreenOffBecauseOfProximity) { 552 if (wantScreenOn(mPowerRequest.screenState)) { 553 // Want screen on. 554 // Wait for previous off animation to complete beforehand. 555 // It is relatively short but if we cancel it and switch to the 556 // on animation immediately then the results are pretty ugly. 557 if (!mElectronBeamOffAnimator.isStarted()) { 558 setScreenOn(true); 559 if (USE_ELECTRON_BEAM_ON_ANIMATION) { 560 if (!mElectronBeamOnAnimator.isStarted()) { 561 if (mPowerState.getElectronBeamLevel() == 1.0f) { 562 mPowerState.dismissElectronBeam(); 563 } else if (mPowerState.prepareElectronBeam(true)) { 564 mElectronBeamOnAnimator.start(); 565 } else { 566 mElectronBeamOnAnimator.end(); 567 } 568 } 569 } else { 570 mPowerState.setElectronBeamLevel(1.0f); 571 mPowerState.dismissElectronBeam(); 572 } 573 } 574 } else { 575 // Want screen off. 576 // Wait for previous on animation to complete beforehand. 577 if (!mElectronBeamOnAnimator.isStarted()) { 578 if (!mElectronBeamOffAnimator.isStarted()) { 579 if (mPowerState.getElectronBeamLevel() == 0.0f) { 580 setScreenOn(false); 581 } else if (mPowerState.prepareElectronBeam(false) 582 && mPowerState.isScreenOn()) { 583 mElectronBeamOffAnimator.start(); 584 } else { 585 mElectronBeamOffAnimator.end(); 586 } 587 } 588 } 589 } 590 } 591 592 // Report whether the display is ready for use. 593 // We mostly care about the screen state here, ignoring brightness changes 594 // which will be handled asynchronously. 595 if (mustNotify 596 && !mElectronBeamOnAnimator.isStarted() 597 && !mElectronBeamOffAnimator.isStarted() 598 && mPowerState.waitUntilClean(mCleanListener)) { 599 synchronized (mLock) { 600 if (!mPendingRequestChangedLocked) { 601 mDisplayReadyLocked = true; 602 } 603 } 604 sendOnStateChanged(); 605 } 606 } 607 608 private void setScreenOn(boolean on) { 609 if (!mPowerState.isScreenOn() == on) { 610 mPowerState.setScreenOn(on); 611 if (on) { 612 mNotifier.onScreenOn(); 613 } else { 614 mNotifier.onScreenOff(); 615 } 616 } 617 } 618 619 private void animateScreenBrightness(int target, int rate) { 620 if (mScreenBrightnessRampAnimator.animateTo(target, rate)) { 621 mNotifier.onScreenBrightness(target); 622 } 623 } 624 625 private final Runnable mCleanListener = new Runnable() { 626 @Override 627 public void run() { 628 sendUpdatePowerState(); 629 } 630 }; 631 632 private void setProximitySensorEnabled(boolean enable) { 633 if (enable) { 634 if (!mProximitySensorEnabled) { 635 mProximitySensorEnabled = true; 636 mPendingProximity = PROXIMITY_UNKNOWN; 637 mSensorManager.registerListener(mProximitySensorListener, mProximitySensor, 638 SensorManager.SENSOR_DELAY_NORMAL, mHandler); 639 } 640 } else { 641 if (mProximitySensorEnabled) { 642 mProximitySensorEnabled = false; 643 mProximity = PROXIMITY_UNKNOWN; 644 mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED); 645 mSensorManager.unregisterListener(mProximitySensorListener); 646 } 647 } 648 } 649 650 private void handleProximitySensorEvent(long time, boolean positive) { 651 if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) { 652 return; // no change 653 } 654 if (mPendingProximity == PROXIMITY_POSITIVE && positive) { 655 return; // no change 656 } 657 658 // Only accept a proximity sensor reading if it remains 659 // stable for the entire debounce delay. 660 mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED); 661 mPendingProximity = positive ? PROXIMITY_POSITIVE : PROXIMITY_NEGATIVE; 662 mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_DEBOUNCE_DELAY; 663 debounceProximitySensor(); 664 } 665 666 private void debounceProximitySensor() { 667 if (mPendingProximity != PROXIMITY_UNKNOWN) { 668 final long now = SystemClock.uptimeMillis(); 669 if (mPendingProximityDebounceTime <= now) { 670 mProximity = mPendingProximity; 671 sendUpdatePowerState(); 672 } else { 673 Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED); 674 msg.setAsynchronous(true); 675 mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime); 676 } 677 } 678 } 679 680 private void setLightSensorEnabled(boolean enable) { 681 if (enable) { 682 if (!mLightSensorEnabled) { 683 mLightSensorEnabled = true; 684 mLightSensorEnableTime = SystemClock.uptimeMillis(); 685 mSensorManager.registerListener(mLightSensorListener, mLightSensor, 686 LIGHT_SENSOR_RATE, mHandler); 687 } 688 } else { 689 if (mLightSensorEnabled) { 690 mLightSensorEnabled = false; 691 mLightMeasurementValid = false; 692 updateAutoBrightness(false); 693 mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED); 694 mSensorManager.unregisterListener(mLightSensorListener); 695 } 696 } 697 } 698 699 private void handleLightSensorEvent(long time, float lux) { 700 // Take the first few readings during the warm-up period and apply them 701 // immediately without debouncing. 702 if (!mLightMeasurementValid 703 || (time - mLightSensorEnableTime) < mLightSensorWarmUpTimeConfig) { 704 mLightMeasurement = lux; 705 mLightMeasurementValid = true; 706 mRecentLightSamples = 0; 707 updateAutoBrightness(true); 708 } 709 710 // Update our moving average. 711 if (lux != mLightMeasurement && (mRecentLightSamples == 0 712 || (lux < mLightMeasurement && mRecentLightBrightening) 713 || (lux > mLightMeasurement && !mRecentLightBrightening))) { 714 // If the newest light sample doesn't seem to be going in the 715 // same general direction as recent samples, then start over. 716 setRecentLight(time, lux, lux > mLightMeasurement); 717 } else if (mRecentLightSamples >= 1) { 718 // Add the newest light sample to the moving average. 719 accumulateRecentLight(time, lux); 720 } 721 if (DEBUG) { 722 Slog.d(TAG, "handleLightSensorEvent: lux=" + lux 723 + ", mLightMeasurementValid=" + mLightMeasurementValid 724 + ", mLightMeasurement=" + mLightMeasurement 725 + ", mRecentLightSamples=" + mRecentLightSamples 726 + ", mRecentLightAverage=" + mRecentLightAverage 727 + ", mRecentLightBrightening=" + mRecentLightBrightening 728 + ", mRecentLightTimeConstant=" + mRecentLightTimeConstant 729 + ", mFirstRecentLightSampleTime=" 730 + TimeUtils.formatUptime(mFirstRecentLightSampleTime) 731 + ", mPendingLightSensorDebounceTime=" 732 + TimeUtils.formatUptime(mPendingLightSensorDebounceTime)); 733 } 734 735 // Debounce. 736 mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED); 737 debounceLightSensor(); 738 } 739 740 private void setRecentLight(long time, float lux, boolean brightening) { 741 mRecentLightBrightening = brightening; 742 mRecentLightTimeConstant = brightening ? 743 BRIGHTENING_LIGHT_TIME_CONSTANT : DIMMING_LIGHT_TIME_CONSTANT; 744 mRecentLightSamples = 1; 745 mRecentLightAverage = lux; 746 mLastLightSample = lux; 747 mLastLightSampleTime = time; 748 mFirstRecentLightSampleTime = time; 749 mPendingLightSensorDebounceTime = time + (brightening ? 750 BRIGHTENING_LIGHT_DEBOUNCE : DIMMING_LIGHT_DEBOUNCE); 751 } 752 753 private void accumulateRecentLight(long time, float lux) { 754 final long timeDelta = time - mLastLightSampleTime; 755 mRecentLightSamples += 1; 756 mRecentLightAverage += (lux - mRecentLightAverage) * 757 timeDelta / (mRecentLightTimeConstant + timeDelta); 758 mLastLightSample = lux; 759 mLastLightSampleTime = time; 760 } 761 762 private void debounceLightSensor() { 763 if (mLightMeasurementValid && mRecentLightSamples >= 1) { 764 final long now = SystemClock.uptimeMillis(); 765 if (mPendingLightSensorDebounceTime <= now) { 766 accumulateRecentLight(now, mLastLightSample); 767 mLightMeasurement = mRecentLightAverage; 768 769 if (DEBUG) { 770 Slog.d(TAG, "debounceLightSensor: Accepted new measurement " 771 + mLightMeasurement + " after " 772 + (now - mFirstRecentLightSampleTime) + " ms based on " 773 + mRecentLightSamples + " recent samples."); 774 } 775 776 updateAutoBrightness(true); 777 778 // Now that we have debounced the light sensor data, we have the 779 // option of either leaving the sensor in a debounced state or 780 // restarting the debounce cycle by setting mRecentLightSamples to 0. 781 // 782 // If we leave the sensor debounced, then new average light measurements 783 // may be accepted immediately as long as they are trending in the same 784 // direction as they were before. If the measurements start 785 // jittering or trending in the opposite direction then the debounce 786 // cycle will automatically be restarted. The benefit is that the 787 // auto-brightness control can be more responsive to changes over a 788 // broad range. 789 // 790 // For now, we choose to be more responsive and leave the following line 791 // commented out. 792 // 793 // mRecentLightSamples = 0; 794 } else { 795 Message msg = mHandler.obtainMessage(MSG_LIGHT_SENSOR_DEBOUNCED); 796 msg.setAsynchronous(true); 797 mHandler.sendMessageAtTime(msg, mPendingLightSensorDebounceTime); 798 } 799 } 800 } 801 802 private void updateAutoBrightness(boolean sendUpdate) { 803 if (!mLightMeasurementValid) { 804 return; 805 } 806 807 final int newScreenAutoBrightness = interpolateBrightness( 808 mScreenAutoBrightnessSpline, mLightMeasurement); 809 if (mScreenAutoBrightness != newScreenAutoBrightness) { 810 if (DEBUG) { 811 Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness=" 812 + mScreenAutoBrightness + "newScreenAutoBrightness=" 813 + newScreenAutoBrightness); 814 } 815 816 mScreenAutoBrightness = newScreenAutoBrightness; 817 if (sendUpdate) { 818 sendUpdatePowerState(); 819 } 820 } 821 } 822 823 private static int interpolateBrightness(Spline spline, float lux) { 824 return Math.min(255, Math.max(0, (int)Math.round(spline.interpolate(lux)))); 825 } 826 827 private void sendOnStateChanged() { 828 mCallbackHandler.post(mOnStateChangedRunnable); 829 } 830 831 private final Runnable mOnStateChangedRunnable = new Runnable() { 832 @Override 833 public void run() { 834 mCallbacks.onStateChanged(); 835 } 836 }; 837 838 private void sendOnProximityNegative() { 839 mCallbackHandler.post(mOnProximityNegativeRunnable); 840 } 841 842 private final Runnable mOnProximityNegativeRunnable = new Runnable() { 843 @Override 844 public void run() { 845 mCallbacks.onProximityNegative(); 846 } 847 }; 848 849 public void dump(PrintWriter pw) { 850 synchronized (mLock) { 851 pw.println(); 852 pw.println("Display Controller Locked State:"); 853 pw.println(" mDisplayReadyLocked=" + mDisplayReadyLocked); 854 pw.println(" mPendingRequestLocked=" + mPendingRequestLocked); 855 pw.println(" mPendingRequestChangedLocked=" + mPendingRequestChangedLocked); 856 pw.println(" mPendingWaitForNegativeProximityLocked=" 857 + mPendingWaitForNegativeProximityLocked); 858 pw.println(" mPendingUpdatePowerStateLocked=" + mPendingUpdatePowerStateLocked); 859 } 860 861 pw.println(); 862 pw.println("Display Controller Configuration:"); 863 pw.println(" mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig); 864 pw.println(" mUseSoftwareAutoBrightnessConfig=" 865 + mUseSoftwareAutoBrightnessConfig); 866 pw.println(" mScreenAutoBrightnessSpline=" + mScreenAutoBrightnessSpline); 867 pw.println(" mLightSensorWarmUpTimeConfig=" + mLightSensorWarmUpTimeConfig); 868 869 if (Looper.myLooper() == mHandler.getLooper()) { 870 dumpLocal(pw); 871 } else { 872 final StringWriter out = new StringWriter(); 873 final CountDownLatch latch = new CountDownLatch(1); 874 Message msg = Message.obtain(mHandler, new Runnable() { 875 @Override 876 public void run() { 877 PrintWriter localpw = new PrintWriter(out); 878 try { 879 dumpLocal(localpw); 880 } finally { 881 localpw.flush(); 882 latch.countDown(); 883 } 884 } 885 }); 886 msg.setAsynchronous(true); 887 mHandler.sendMessage(msg); 888 try { 889 latch.await(); 890 pw.print(out.toString()); 891 } catch (InterruptedException ex) { 892 pw.println(); 893 pw.println("Failed to dump thread state due to interrupted exception!"); 894 } 895 } 896 } 897 898 private void dumpLocal(PrintWriter pw) { 899 pw.println(); 900 pw.println("Display Controller Thread State:"); 901 pw.println(" mPowerRequest=" + mPowerRequest); 902 pw.println(" mWaitingForNegativeProximity=" + mWaitingForNegativeProximity); 903 904 pw.println(" mProximitySensor=" + mProximitySensor); 905 pw.println(" mProximitySensorEnabled=" + mProximitySensorEnabled); 906 pw.println(" mProximityThreshold=" + mProximityThreshold); 907 pw.println(" mProximity=" + proximityToString(mProximity)); 908 pw.println(" mPendingProximity=" + proximityToString(mPendingProximity)); 909 pw.println(" mPendingProximityDebounceTime=" 910 + TimeUtils.formatUptime(mPendingProximityDebounceTime)); 911 pw.println(" mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity); 912 913 pw.println(" mLightSensor=" + mLightSensor); 914 pw.println(" mLightSensorEnabled=" + mLightSensorEnabled); 915 pw.println(" mLightSensorEnableTime=" 916 + TimeUtils.formatUptime(mLightSensorEnableTime)); 917 pw.println(" mLightMeasurement=" + mLightMeasurement); 918 pw.println(" mLightMeasurementValid=" + mLightMeasurementValid); 919 pw.println(" mLastLightSample=" + mLastLightSample); 920 pw.println(" mLastLightSampleTime=" 921 + TimeUtils.formatUptime(mLastLightSampleTime)); 922 pw.println(" mRecentLightSamples=" + mRecentLightSamples); 923 pw.println(" mRecentLightAverage=" + mRecentLightAverage); 924 pw.println(" mRecentLightBrightening=" + mRecentLightBrightening); 925 pw.println(" mRecentLightTimeConstant=" + mRecentLightTimeConstant); 926 pw.println(" mFirstRecentLightSampleTime=" 927 + TimeUtils.formatUptime(mFirstRecentLightSampleTime)); 928 pw.println(" mPendingLightSensorDebounceTime=" 929 + TimeUtils.formatUptime(mPendingLightSensorDebounceTime)); 930 pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness); 931 pw.println(" mUsingScreenAutoBrightness=" + mUsingScreenAutoBrightness); 932 933 if (mElectronBeamOnAnimator != null) { 934 pw.println(" mElectronBeamOnAnimator.isStarted()=" + 935 mElectronBeamOnAnimator.isStarted()); 936 } 937 if (mElectronBeamOffAnimator != null) { 938 pw.println(" mElectronBeamOffAnimator.isStarted()=" + 939 mElectronBeamOffAnimator.isStarted()); 940 } 941 942 if (mPowerState != null) { 943 mPowerState.dump(pw); 944 } 945 } 946 947 private static String proximityToString(int state) { 948 switch (state) { 949 case PROXIMITY_UNKNOWN: 950 return "Unknown"; 951 case PROXIMITY_NEGATIVE: 952 return "Negative"; 953 case PROXIMITY_POSITIVE: 954 return "Positive"; 955 default: 956 return Integer.toString(state); 957 } 958 } 959 960 private static boolean wantScreenOn(int state) { 961 switch (state) { 962 case DisplayPowerRequest.SCREEN_STATE_BRIGHT: 963 case DisplayPowerRequest.SCREEN_STATE_DIM: 964 return true; 965 } 966 return false; 967 } 968 969 /** 970 * Asynchronous callbacks from the power controller to the power manager service. 971 */ 972 public interface Callbacks { 973 void onStateChanged(); 974 void onProximityNegative(); 975 } 976 977 private final class DisplayControllerHandler extends Handler { 978 public DisplayControllerHandler(Looper looper) { 979 super(looper); 980 } 981 982 @Override 983 public void handleMessage(Message msg) { 984 switch (msg.what) { 985 case MSG_UPDATE_POWER_STATE: 986 updatePowerState(); 987 break; 988 989 case MSG_PROXIMITY_SENSOR_DEBOUNCED: 990 debounceProximitySensor(); 991 break; 992 993 case MSG_LIGHT_SENSOR_DEBOUNCED: 994 debounceLightSensor(); 995 break; 996 } 997 } 998 } 999 1000 private final SensorEventListener mProximitySensorListener = new SensorEventListener() { 1001 @Override 1002 public void onSensorChanged(SensorEvent event) { 1003 if (mProximitySensorEnabled) { 1004 final long time = SystemClock.uptimeMillis(); 1005 final float distance = event.values[0]; 1006 boolean positive = distance >= 0.0f && distance < mProximityThreshold; 1007 handleProximitySensorEvent(time, positive); 1008 } 1009 } 1010 1011 @Override 1012 public void onAccuracyChanged(Sensor sensor, int accuracy) { 1013 // Not used. 1014 } 1015 }; 1016 1017 private final SensorEventListener mLightSensorListener = new SensorEventListener() { 1018 @Override 1019 public void onSensorChanged(SensorEvent event) { 1020 if (mLightSensorEnabled) { 1021 final long time = SystemClock.uptimeMillis(); 1022 final float lux = event.values[0]; 1023 handleLightSensorEvent(time, lux); 1024 } 1025 } 1026 1027 @Override 1028 public void onAccuracyChanged(Sensor sensor, int accuracy) { 1029 // Not used. 1030 } 1031 }; 1032} 1033