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