Add window manager support for overriding button and keyboard backlight values.

The new backlightBrightness field works similarly as the existing WindowManager.LayoutParams.screenBrightness field

Needed for bugs:
    b/2233655 (under low ambient light the touch keys remain illuminated during video playback and never timeout)
    b/2221079 (Backlight for home/search/back/etc buttons should turn off when in dock in night mode)

Change-Id: I60dfecdc7bb653b0db38094464de651220b3d438
diff --git a/api/current.xml b/api/current.xml
index fed1e45..12c2eee 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -167061,6 +167061,39 @@
  visibility="public"
 >
 </field>
+<field name="BRIGHTNESS_OVERRIDE_FULL"
+ type="float"
+ transient="false"
+ volatile="false"
+ value="1.0f"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="BRIGHTNESS_OVERRIDE_NONE"
+ type="float"
+ transient="false"
+ volatile="false"
+ value="-1.0f"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="BRIGHTNESS_OVERRIDE_OFF"
+ type="float"
+ transient="false"
+ volatile="false"
+ value="0.0f"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="CREATOR"
  type="android.os.Parcelable.Creator"
  transient="false"
@@ -167917,6 +167950,16 @@
  visibility="public"
 >
 </field>
+<field name="buttonBrightness"
+ type="float"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="dimAmount"
  type="float"
  transient="false"
diff --git a/core/java/android/os/LocalPowerManager.java b/core/java/android/os/LocalPowerManager.java
index 03331aa..d348f07 100644
--- a/core/java/android/os/LocalPowerManager.java
+++ b/core/java/android/os/LocalPowerManager.java
@@ -49,4 +49,5 @@
     boolean isScreenOn();
 
     void setScreenBrightnessOverride(int brightness);
+    void setButtonBrightnessOverride(int brightness);
 }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 6696533..fe329f2 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -649,7 +649,28 @@
          * be cleared automatically after the window is displayed.
          */
         public static final int SOFT_INPUT_IS_FORWARD_NAVIGATION = 0x100;
-        
+
+        /**
+         * Default value for {@link #screenBrightness} and {@link #buttonBrightness}
+         * indicating that the brightness value is not overridden for this window
+         * and normal brightness policy should be used.
+         */
+        public static final float BRIGHTNESS_OVERRIDE_NONE = -1.0f;
+
+        /**
+         * Value for {@link #screenBrightness} and {@link #buttonBrightness}
+         * indicating that the screen or button backlight brightness should be set
+         * to the lowest value when this window is in front.
+         */
+        public static final float BRIGHTNESS_OVERRIDE_OFF = 0.0f;
+
+        /**
+         * Value for {@link #screenBrightness} and {@link #buttonBrightness}
+         * indicating that the screen or button backlight brightness should be set
+         * to the hightest value when this window is in front.
+         */
+        public static final float BRIGHTNESS_OVERRIDE_FULL = 1.0f;
+
         /**
          * Desired operating mode for any soft input area.  May any combination
          * of:
@@ -717,9 +738,17 @@
          * preferred screen brightness.  0 to 1 adjusts the brightness from
          * dark to full bright.
          */
-        public float screenBrightness = -1.0f;
+        public float screenBrightness = BRIGHTNESS_OVERRIDE_NONE;
         
         /**
+         * This can be used to override the standard behavior of the button and
+         * keyboard backlights.  A value of less than 0, the default, means to
+         * use the standard backlight behavior.  0 to 1 adjusts the brightness
+         * from dark to full bright.
+         */
+        public float buttonBrightness = BRIGHTNESS_OVERRIDE_NONE;
+
+        /**
          * Identifier for this window.  This will usually be filled in for
          * you.
          */
@@ -816,6 +845,7 @@
             out.writeFloat(alpha);
             out.writeFloat(dimAmount);
             out.writeFloat(screenBrightness);
+            out.writeFloat(buttonBrightness);
             out.writeStrongBinder(token);
             out.writeString(packageName);
             TextUtils.writeToParcel(mTitle, out, parcelableFlags);
@@ -851,6 +881,7 @@
             alpha = in.readFloat();
             dimAmount = in.readFloat();
             screenBrightness = in.readFloat();
+            buttonBrightness = in.readFloat();
             token = in.readStrongBinder();
             packageName = in.readString();
             mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
@@ -870,6 +901,8 @@
         public static final int SOFT_INPUT_MODE_CHANGED = 1<<9;
         public static final int SCREEN_ORIENTATION_CHANGED = 1<<10;
         public static final int SCREEN_BRIGHTNESS_CHANGED = 1<<11;
+        /** {@hide} */
+        public static final int BUTTON_BRIGHTNESS_CHANGED = 1<<12;
     
         // internal buffer to backup/restore parameters under compatibility mode.
         private int[] mCompatibilityParamsBackup = null;
@@ -971,6 +1004,10 @@
                 screenBrightness = o.screenBrightness;
                 changes |= SCREEN_BRIGHTNESS_CHANGED;
             }
+            if (buttonBrightness != o.buttonBrightness) {
+                buttonBrightness = o.buttonBrightness;
+                changes |= BUTTON_BRIGHTNESS_CHANGED;
+            }
     
             if (screenOrientation != o.screenOrientation) {
                 screenOrientation = o.screenOrientation;
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index a838e89..feab7d2 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -209,7 +209,9 @@
     private boolean mLightSensorEnabled;
     private float mLightSensorValue = -1;
     private float mLightSensorPendingValue = -1;
-    private int mLightSensorBrightness = -1;
+    private int mLightSensorScreenBrightness = -1;
+    private int mLightSensorButtonBrightness = -1;
+    private int mLightSensorKeyboardBrightness = -1;
     private boolean mDimScreen = true;
     private long mNextTimeout;
     private volatile int mPokey = 0;
@@ -220,6 +222,7 @@
     private long mLastScreenOnTime;
     private boolean mPreventScreenOn;
     private int mScreenBrightnessOverride = -1;
+    private int mButtonBrightnessOverride = -1;
     private boolean mUseSoftwareAutoBrightness;
     private boolean mAutoBrightessEnabled;
     private int[] mAutoBrightnessLevels;
@@ -919,7 +922,8 @@
         pw.println("  mKeylightDelay=" + mKeylightDelay + " mDimDelay=" + mDimDelay
                 + " mScreenOffDelay=" + mScreenOffDelay);
         pw.println("  mPreventScreenOn=" + mPreventScreenOn
-                + "  mScreenBrightnessOverride=" + mScreenBrightnessOverride);
+                + "  mScreenBrightnessOverride=" + mScreenBrightnessOverride
+                + "  mButtonBrightnessOverride=" + mButtonBrightnessOverride);
         pw.println("  mTotalDelaySetting=" + mTotalDelaySetting);
         pw.println("  mLastScreenOnTime=" + mLastScreenOnTime);
         pw.println("  mBroadcastWakeLock=" + mBroadcastWakeLock);
@@ -933,8 +937,11 @@
         pw.println("  mProximityPendingValue=" + mProximityPendingValue);
         pw.println("  mLastProximityEventTime=" + mLastProximityEventTime);
         pw.println("  mLightSensorEnabled=" + mLightSensorEnabled);
-        pw.println("  mLightSensorValue=" + mLightSensorValue);
-        pw.println("  mLightSensorPendingValue=" + mLightSensorPendingValue);
+        pw.println("  mLightSensorValue=" + mLightSensorValue
+                + " mLightSensorPendingValue=" + mLightSensorPendingValue);
+        pw.println("  mLightSensorScreenBrightness=" + mLightSensorScreenBrightness
+                + " mLightSensorButtonBrightness=" + mLightSensorButtonBrightness
+                + " mLightSensorKeyboardBrightness=" + mLightSensorKeyboardBrightness);
         pw.println("  mUseSoftwareAutoBrightness=" + mUseSoftwareAutoBrightness);
         pw.println("  mAutoBrightessEnabled=" + mAutoBrightessEnabled);
         mScreenBrightness.dump(pw, "  mScreenBrightness: ");
@@ -1302,7 +1309,18 @@
             }
         }
     }
-    
+
+    public void setButtonBrightnessOverride(int brightness) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+
+         synchronized (mLocks) {
+           if (mButtonBrightnessOverride != brightness) {
+                mButtonBrightnessOverride = brightness;
+                updateLightsLocked(mPowerState, BUTTON_BRIGHT_BIT | KEYBOARD_BRIGHT_BIT);
+            }
+        }
+    }
+
     /**
      * Sanity-check that gets called 5 seconds after any call to
      * preventScreenOn(true).  This ensures that the original call
@@ -1451,8 +1469,7 @@
                         err = setScreenStateLocked(true);
                         long identity = Binder.clearCallingIdentity();
                         try {
-                            mBatteryStats.noteScreenBrightness(
-                                    getPreferredBrightness());
+                            mBatteryStats.noteScreenBrightness(getPreferredBrightness());
                             mBatteryStats.noteScreenOn();
                         } catch (RemoteException e) {
                             Log.w(TAG, "RemoteException calling noteScreenOn on BatteryStatsService", e);
@@ -1523,6 +1540,8 @@
 
     private void updateLightsLocked(int newState, int forceState) {
         final int oldState = mPowerState;
+        newState = applyButtonState(newState);
+        newState = applyKeyboardState(newState);
         final int realDifference = (newState ^ oldState);
         final int difference = realDifference | forceState;
         if (difference == 0) {
@@ -1541,9 +1560,9 @@
                 if ((newState & KEYBOARD_BRIGHT_BIT) == 0) {
                     mKeyboardBrightness.setTargetLocked(Power.BRIGHTNESS_OFF,
                             ANIM_STEPS, INITIAL_KEYBOARD_BRIGHTNESS,
-                            preferredBrightness);
+                            Power.BRIGHTNESS_ON);
                 } else {
-                    mKeyboardBrightness.setTargetLocked(preferredBrightness,
+                    mKeyboardBrightness.setTargetLocked(Power.BRIGHTNESS_ON,
                             ANIM_STEPS, INITIAL_KEYBOARD_BRIGHTNESS,
                             Power.BRIGHTNESS_OFF);
                 }
@@ -1562,9 +1581,9 @@
                 if ((newState & BUTTON_BRIGHT_BIT) == 0) {
                     mButtonBrightness.setTargetLocked(Power.BRIGHTNESS_OFF,
                             ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
-                            preferredBrightness);
+                            Power.BRIGHTNESS_ON);
                 } else {
-                    mButtonBrightness.setTargetLocked(preferredBrightness,
+                    mButtonBrightness.setTargetLocked(Power.BRIGHTNESS_ON,
                             ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
                             Power.BRIGHTNESS_OFF);
                 }
@@ -1820,9 +1839,9 @@
         try {
             if (mScreenBrightnessOverride >= 0) {
                 return mScreenBrightnessOverride;
-            } else if (mLightSensorBrightness >= 0 && mUseSoftwareAutoBrightness
+            } else if (mLightSensorScreenBrightness >= 0 && mUseSoftwareAutoBrightness
                     && mAutoBrightessEnabled) {
-                return mLightSensorBrightness;
+                return mLightSensorScreenBrightness;
             }
             final int brightness = Settings.System.getInt(mContext.getContentResolver(),
                                                           SCREEN_BRIGHTNESS);
@@ -1833,6 +1852,40 @@
         }
     }
 
+    private int applyButtonState(int state) {
+        int brightness = -1;
+        if (mButtonBrightnessOverride >= 0) {
+            brightness = mButtonBrightnessOverride;
+        } else if (mLightSensorButtonBrightness >= 0 && mUseSoftwareAutoBrightness) {
+            brightness = mLightSensorButtonBrightness;
+        }
+        if (brightness > 0) {
+            return state | BUTTON_BRIGHT_BIT;
+        } else if (brightness == 0) {
+            return state & ~BUTTON_BRIGHT_BIT;
+        } else {
+            return state;
+        }
+    }
+
+    private int applyKeyboardState(int state) {
+        int brightness = -1;
+        if (!mKeyboardVisible) {
+            brightness = 0;
+        } else if (mButtonBrightnessOverride >= 0) {
+            brightness = mButtonBrightnessOverride;
+        } else if (mLightSensorKeyboardBrightness >= 0 && mUseSoftwareAutoBrightness) {
+            brightness =  mLightSensorKeyboardBrightness;
+        }
+        if (brightness > 0) {
+            return state | KEYBOARD_BRIGHT_BIT;
+        } else if (brightness == 0) {
+            return state & ~KEYBOARD_BRIGHT_BIT;
+        } else {
+            return state;
+        }
+    }
+
     public boolean isScreenOn() {
         synchronized (mLocks) {
             return (mPowerState & SCREEN_ON_BIT) != 0;
@@ -2008,7 +2061,9 @@
                 } else {
                     keyboardValue = 0;
                 }
-                mLightSensorBrightness = lcdValue;
+                mLightSensorScreenBrightness = lcdValue;
+                mLightSensorButtonBrightness = buttonValue;
+                mLightSensorKeyboardBrightness = keyboardValue;
 
                 if (mDebugLightSensor) {
                     Log.d(TAG, "lcdValue " + lcdValue);
@@ -2032,31 +2087,35 @@
                                 lcdValue, brightnessMode);
                     }
                 }
-                if (ANIMATE_BUTTON_LIGHTS) {
-                    if (mButtonBrightness.setTargetLocked(buttonValue,
-                            AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
-                            (int)mButtonBrightness.curValue)) {
-                        startAnimation = true;
+                if (mButtonBrightnessOverride < 0) {
+                    if (ANIMATE_BUTTON_LIGHTS) {
+                        if (mButtonBrightness.setTargetLocked(buttonValue,
+                                AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
+                                (int)mButtonBrightness.curValue)) {
+                            startAnimation = true;
+                        }
+                    } else {
+                        int brightnessMode = (mUseSoftwareAutoBrightness
+                                            ? HardwareService.BRIGHTNESS_MODE_SENSOR
+                                            : HardwareService.BRIGHTNESS_MODE_USER);
+                        mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS,
+                                buttonValue, brightnessMode);
                     }
-                } else {
-                    int brightnessMode = (mUseSoftwareAutoBrightness
-                                        ? HardwareService.BRIGHTNESS_MODE_SENSOR
-                                        : HardwareService.BRIGHTNESS_MODE_USER);
-                    mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS,
-                            buttonValue, brightnessMode);
                 }
-                if (ANIMATE_KEYBOARD_LIGHTS) {
-                    if (mKeyboardBrightness.setTargetLocked(keyboardValue,
-                            AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
-                            (int)mKeyboardBrightness.curValue)) {
-                        startAnimation = true;
+                if (mButtonBrightnessOverride < 0 || !mKeyboardVisible) {
+                    if (ANIMATE_KEYBOARD_LIGHTS) {
+                        if (mKeyboardBrightness.setTargetLocked(keyboardValue,
+                                AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
+                                (int)mKeyboardBrightness.curValue)) {
+                            startAnimation = true;
+                        }
+                    } else {
+                        int brightnessMode = (mUseSoftwareAutoBrightness
+                                            ? HardwareService.BRIGHTNESS_MODE_SENSOR
+                                            : HardwareService.BRIGHTNESS_MODE_USER);
+                        mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD,
+                                keyboardValue, brightnessMode);
                     }
-                } else {
-                    int brightnessMode = (mUseSoftwareAutoBrightness
-                                        ? HardwareService.BRIGHTNESS_MODE_SENSOR
-                                        : HardwareService.BRIGHTNESS_MODE_USER);
-                    mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD,
-                            keyboardValue, brightnessMode);
                 }
                 if (startAnimation) {
                     if (mDebugLightSensor) {
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index a013c75..0481340 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -9313,6 +9313,7 @@
         boolean orientationChangeComplete = true;
         Session holdScreen = null;
         float screenBrightness = -1;
+        float buttonBrightness = -1;
         boolean focusDisplayed = false;
         boolean animating = false;
 
@@ -10072,6 +10073,10 @@
                                 && screenBrightness < 0) {
                             screenBrightness = w.mAttrs.screenBrightness;
                         }
+                        if (!syswin && w.mAttrs.buttonBrightness >= 0
+                                && buttonBrightness < 0) {
+                            buttonBrightness = w.mAttrs.buttonBrightness;
+                        }
                         if (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
                                 || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD
                                 || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR) {
@@ -10318,6 +10323,12 @@
             mPowerManager.setScreenBrightnessOverride((int)
                     (screenBrightness * Power.BRIGHTNESS_ON));
         }
+        if (buttonBrightness < 0 || buttonBrightness > 1.0f) {
+            mPowerManager.setButtonBrightnessOverride(-1);
+        } else {
+            mPowerManager.setButtonBrightnessOverride((int)
+                    (buttonBrightness * Power.BRIGHTNESS_ON));
+        }
         if (holdScreen != mHoldingScreenOn) {
             mHoldingScreenOn = holdScreen;
             Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen);