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