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