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