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