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