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