Power Manager support for light sensor backlight management.

Change-Id: I470e2d7d12abf0dbfd31d84859b06bfae3cb36a1
Signed-off-by: Mike Lockwood <lockwood@android.com>
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 99e008c..a63d3fc 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -28,6 +28,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.database.Cursor;
 import android.hardware.Sensor;
 import android.hardware.SensorEvent;
@@ -89,6 +90,9 @@
     private static final int LONG_KEYLIGHT_DELAY = 6000;        // t+6 sec
     private static final int LONG_DIM_TIME = 7000;              // t+N-5 sec
 
+    // How long to wait to debounce light sensor changes.
+    private static final int LIGHT_SENSOR_DELAY = 1000;
+
     // trigger proximity if distance is less than 5 cm
     private static final float PROXIMITY_THRESHOLD = 5.0f;
 
@@ -193,6 +197,8 @@
     private Sensor mLightSensor;
     private boolean mLightSensorEnabled;
     private float mLightSensorValue = -1;
+    private float mLightSensorPendingValue = -1;
+    private int mLightSensorBrightness = -1;
     private boolean mDimScreen = true;
     private long mNextTimeout;
     private volatile int mPokey = 0;
@@ -205,6 +211,10 @@
     private int mScreenBrightnessOverride = -1;
     private boolean mHasHardwareAutoBrightness;
     private boolean mAutoBrightessEnabled;
+    private int[] mAutoBrightnessLevels;
+    private int[] mLcdBacklightValues;
+    private int[] mButtonBacklightValues;
+    private int[] mKeyboardBacklightValues;
 
     // Used when logging number and duration of touch-down cycles
     private long mTotalTouchDownTime;
@@ -425,8 +435,19 @@
         mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
         mScreenOffIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
 
-        mHasHardwareAutoBrightness = mContext.getResources().getBoolean(
+        Resources resources = mContext.getResources();
+        mHasHardwareAutoBrightness = resources.getBoolean(
                 com.android.internal.R.bool.config_hardware_automatic_brightness_available);
+        if (!mHasHardwareAutoBrightness) {
+            mAutoBrightnessLevels = resources.getIntArray(
+                    com.android.internal.R.array.config_autoBrightnessLevels);
+            mLcdBacklightValues = resources.getIntArray(
+                    com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
+            mButtonBacklightValues = resources.getIntArray(
+                    com.android.internal.R.array.config_autoBrightnessButtonBacklightValues);
+            mKeyboardBacklightValues = resources.getIntArray(
+                    com.android.internal.R.array.config_autoBrightnessKeyboardBacklightValues);
+        }
 
        ContentResolver resolver = mContext.getContentResolver();
         Cursor settingsCursor = resolver.query(Settings.System.CONTENT_URI, null,
@@ -553,7 +574,7 @@
             switch (wl.flags & LOCK_MASK)
             {
                 case PowerManager.FULL_WAKE_LOCK:
-                    wl.minState = (mKeyboardVisible ? ALL_BRIGHT : SCREEN_BUTTON_BRIGHT);
+                    wl.minState = SCREEN_BRIGHT;
                     break;
                 case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
                     wl.minState = SCREEN_BRIGHT;
@@ -851,6 +872,12 @@
         pw.println("  mStayOnWhilePluggedInScreenDimLock=" + mStayOnWhilePluggedInScreenDimLock);
         pw.println("  mStayOnWhilePluggedInPartialLock=" + mStayOnWhilePluggedInPartialLock);
         pw.println("  mPreventScreenOnPartialLock=" + mPreventScreenOnPartialLock);
+        pw.println("  mProximitySensorActive=" + mProximitySensorActive);
+        pw.println("  mLightSensorEnabled=" + mLightSensorEnabled);
+        pw.println("  mLightSensorValue=" + mLightSensorValue);
+        pw.println("  mLightSensorPendingValue=" + mLightSensorPendingValue);
+        pw.println("  mHasHardwareAutoBrightness=" + mHasHardwareAutoBrightness);
+        pw.println("  mAutoBrightessEnabled=" + mAutoBrightessEnabled);
         mScreenBrightness.dump(pw, "  mScreenBrightness: ");
         mKeyboardBrightness.dump(pw, "  mKeyboardBrightness: ");
         mButtonBrightness.dump(pw, "  mButtonBrightness: ");
@@ -1254,6 +1281,11 @@
         int err = Power.setScreenState(on);
         if (err == 0) {
             enableLightSensor(on && mAutoBrightessEnabled);
+            if (!on) {
+                // make sure button and key backlights are off too
+                mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS, 0);
+                mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD, 0);
+            }
         }
         return err;
     }
@@ -1712,6 +1744,8 @@
         try {
             if (mScreenBrightnessOverride >= 0) {
                 return mScreenBrightnessOverride;
+            } else if (mLightSensorBrightness >= 0) {
+                return mLightSensorBrightness;
             }
             final int brightness = Settings.System.getInt(mContext.getContentResolver(),
                                                           SCREEN_BRIGHTNESS);
@@ -1795,8 +1829,9 @@
             if (mLastEventTime <= time || force) {
                 mLastEventTime = time;
                 if ((mUserActivityAllowed && !mProximitySensorActive) || force) {
-                    // Only turn on button backlights if a button was pressed.
-                    if (eventType == BUTTON_EVENT) {
+                    // Only turn on button backlights if a button was pressed
+                    // and auto brightness is disabled
+                    if (eventType == BUTTON_EVENT && !mAutoBrightessEnabled) {
                         mUserState = (mKeyboardVisible ? ALL_BRIGHT : SCREEN_BUTTON_BRIGHT);
                     } else {
                         // don't clear button/keyboard backlights when the screen is touched.
@@ -1821,12 +1856,75 @@
         }
     }
 
-    private void lightSensorChangedLocked(float value) {
+    private int getAutoBrightnessValue(int sensorValue, int[] values) {
+        try {
+            int i;
+            for (i = 0; i < mAutoBrightnessLevels.length; i++) {
+                if (sensorValue < mAutoBrightnessLevels[i]) {
+                    break;
+                }
+            }
+            return values[i];
+        } catch (Exception e) {
+            // guard against null pointer or index out of bounds errors
+            Log.e(TAG, "getAutoBrightnessValue", e);
+            return 255;
+        }
+    }
+
+    private Runnable mAutoBrightnessTask = new Runnable() {
+        public void run() {
+            int value = (int)mLightSensorPendingValue;
+            if (value >= 0) {
+                mLightSensorPendingValue = -1;
+                lightSensorChangedLocked(value);
+            }
+        }
+    };
+
+    private void lightSensorChangedLocked(int value) {
         if (mDebugLightSensor) {
             Log.d(TAG, "lightSensorChangedLocked " + value);
         }
-        mLightSensorValue = value;
-        // more to do here
+
+        if (mLightSensorValue != value) {
+            mLightSensorValue = value;
+            if ((mPowerState & BATTERY_LOW_BIT) == 0) {
+                int lcdValue = getAutoBrightnessValue(value, mLcdBacklightValues);
+                int buttonValue = getAutoBrightnessValue(value, mButtonBacklightValues);
+                int keyboardValue = getAutoBrightnessValue(value, mKeyboardBacklightValues);
+                mLightSensorBrightness = lcdValue;
+
+                if (mDebugLightSensor) {
+                    Log.d(TAG, "lcdValue " + lcdValue);
+                    Log.d(TAG, "buttonValue " + buttonValue);
+                    Log.d(TAG, "keyboardValue " + keyboardValue);
+                }
+
+                if (mScreenBrightnessOverride < 0) {
+                    mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BACKLIGHT,
+                            lcdValue);
+                }
+                mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS,
+                        buttonValue);
+                mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD,
+                        keyboardValue);
+
+                // update our animation state
+                if (ANIMATE_SCREEN_LIGHTS) {
+                    mScreenBrightness.curValue = lcdValue;
+                    mScreenBrightness.animating = false;
+                }
+                if (ANIMATE_BUTTON_LIGHTS) {
+                    mButtonBrightness.curValue = buttonValue;
+                    mButtonBrightness.animating = false;
+                }
+                if (ANIMATE_KEYBOARD_LIGHTS) {
+                    mKeyboardBrightness.curValue = keyboardValue;
+                    mKeyboardBrightness.animating = false;
+                }
+            }
+        }
     }
 
     /**
@@ -1914,6 +2012,8 @@
 
     private void setScreenBrightnessMode(int mode) {
         mAutoBrightessEnabled = (mode == SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+        // reset computed brightness
+        mLightSensorBrightness = -1;
 
         if (mHasHardwareAutoBrightness) {
             // When setting auto-brightness, must reset the brightness afterwards
@@ -2217,7 +2317,13 @@
                 if (mDebugLightSensor) {
                     Log.d(TAG, "onSensorChanged: light value: " + value);
                 }
-                lightSensorChangedLocked(value);
+                mHandler.removeCallbacks(mAutoBrightnessTask);
+                if (mLightSensorValue != value) {
+                    mLightSensorPendingValue = value;
+                    mHandler.postDelayed(mAutoBrightnessTask, LIGHT_SENSOR_DELAY);
+                } else {
+                    mLightSensorPendingValue = -1;
+                }
             }
         }