diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 4676a0a000edf5a090a907d6a09cbd0c0cd06875..05e2332cc00031df448ede123ff1b5a3bca32984 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -128,4 +128,5 @@ interface IPowerManager
     const int GO_TO_SLEEP_REASON_MAX = 10;
     const int GO_TO_SLEEP_FLAG_NO_DOZE = 1 << 0;
 
+    void setKeyboardVisibility(boolean visible);
 }
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 2ac2d70c90d757c3e0b05dc83575c3afe190bbc3..66a6a61c05453da1da384565c4837ca7e864fcc4 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -491,7 +491,8 @@ public final class PowerManager {
             BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM_VR,
             BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM_VR,
             BRIGHTNESS_CONSTRAINT_TYPE_DEFAULT_VR,
-            BRIGHTNESS_CONSTRAINT_TYPE_DEFAULT_BUTTON
+            BRIGHTNESS_CONSTRAINT_TYPE_DEFAULT_BUTTON,
+            BRIGHTNESS_CONSTRAINT_TYPE_DEFAULT_KEYBOARD
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface BrightnessConstraint{}
@@ -549,6 +550,12 @@ public final class PowerManager {
      */
     public static final int BRIGHTNESS_CONSTRAINT_TYPE_DEFAULT_BUTTON = 8;
 
+    /**
+     * Brightness constraint type: minimum allowed value.
+     * @hide
+     */
+    public static final int BRIGHTNESS_CONSTRAINT_TYPE_DEFAULT_KEYBOARD = 9;
+
     /**
      * @hide
      */
@@ -2393,6 +2400,18 @@ public final class PowerManager {
         }
     }
 
+    /**
+     * @hide
+     */
+    public void setKeyboardVisibility(boolean visible) {
+        try {
+            if (mService != null) {
+                mService.setKeyboardVisibility(visible);
+            }
+        } catch (RemoteException e) {
+        }
+    }
+
     /**
      * If true, the doze component is not started until after the screen has been
      * turned off and the screen off animation has been performed.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 0d735057bcb283eb4fbc361810927c73786053f6..b123b7dcce93f6f6068650299f8375508b507972 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10804,6 +10804,13 @@ public final class Settings {
          */
         public static final String BUTTON_BRIGHTNESS = "button_brightness";
 
+        /**
+         * The keyboard brightness to be used while the screen is on.
+         * Valid value range is between 0 and {@link PowerManager#getMaximumKeyboardBrightness()}
+         * @hide
+         */
+        public static final String KEYBOARD_BRIGHTNESS = "keyboard_brightness";
+
         /**
          * These entries are considered common between the personal and the managed profile,
          * since the managed profile doesn't get to change them.
diff --git a/core/res/res/values/lmodroid_config.xml b/core/res/res/values/lmodroid_config.xml
index 282af1ccd99ea13b0211c562bf97d5ef98876840..4957a5e26388d568e602d488592093714f66dfac 100644
--- a/core/res/res/values/lmodroid_config.xml
+++ b/core/res/res/values/lmodroid_config.xml
@@ -150,4 +150,12 @@
     <integer name="config_deviceSupportsButtonBrightnessControl">0</integer>
     <dimen name="config_buttonBrightnessSettingDefaultFloat">1.0</dimen>
 
+    <!-- Keyboard backlight control. Possible values are:
+            0 - Not supported
+            1 - Supported, but only on/off mode
+            2 - Supported with variable brightness control
+    -->
+    <integer name="config_deviceSupportsKeyboardBrightnessControl">0</integer>
+    <dimen name="config_keyboardBrightnessSettingDefaultFloat">1.0</dimen>
+
 </resources>
diff --git a/core/res/res/values/lmodroid_symbols.xml b/core/res/res/values/lmodroid_symbols.xml
index e787bfc4cff5d313161a710adf3191b6bec41a32..2ee697c22911b532d5271ed86f0188214f64d2d1 100644
--- a/core/res/res/values/lmodroid_symbols.xml
+++ b/core/res/res/values/lmodroid_symbols.xml
@@ -59,8 +59,10 @@
     <!-- Camera key type -->
     <java-symbol type="bool" name="config_singleStageCameraKey" />
 
-    <!-- Button backlight -->
+    <!-- Button and keyboard backlight -->
     <java-symbol type="integer" name="config_deviceSupportsButtonBrightnessControl" />
+    <java-symbol type="integer" name="config_deviceSupportsKeyboardBrightnessControl" />
     <java-symbol type="dimen" name="config_buttonBrightnessSettingDefaultFloat" />
+    <java-symbol type="dimen" name="config_keyboardBrightnessSettingDefaultFloat" />
 
 </resources>
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 489faaefd2b8968a042416fc424b51fc12a48a2e..78d79ad2f12ddeed18d679c437a1323894fbff90 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -1133,14 +1133,22 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
             if (buttonsLight != null) {
                 buttonsLight.setBrightness(brightnessState);
             }
+            LogicalLight keyboardLight = mLights.getLight(LightsManager.LIGHT_ID_KEYBOARD);
+            if (keyboardLight != null) {
+                keyboardLight.setBrightness(brightnessState);
+            }
         }
 
-        // Disable button lights when dozing
+        // Disable button and keyboard lights when dozing
         if (state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND) {
             LogicalLight buttonsLight = mLights.getLight(LightsManager.LIGHT_ID_BUTTONS);
             if (buttonsLight != null) {
                 buttonsLight.setBrightness(PowerManager.BRIGHTNESS_OFF_FLOAT);
             }
+            LogicalLight keyboardLight = mLights.getLight(LightsManager.LIGHT_ID_KEYBOARD);
+            if (keyboardLight != null) {
+                keyboardLight.setBrightness(PowerManager.BRIGHTNESS_OFF_FLOAT);
+            }
         }
 
         // Always use the VR brightness when in the VR state.
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 7650abee808b7ede2a2e5673db4a23118040ad98..9a189db254dd22c6039d33873d1c7586c8c71698 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2734,6 +2734,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
         }
     }
 
+    private boolean isBuiltInKeyboardVisible() {
+        return mHaveBuiltInKeyboard && !isHidden(mLidKeyboardAccessibility);
+    }
+
     /** {@inheritDoc} */
     @Override
     public void adjustConfigurationLw(Configuration config, int keyboardPresence,
@@ -5686,6 +5690,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
     }
 
     private void applyLidSwitchState() {
+        mPowerManager.setKeyboardVisibility(isBuiltInKeyboardVisible());
+
         final int lidState = mDefaultDisplayPolicy.getLidState();
         if (lidState == LID_CLOSED) {
             int lidBehavior = getLidBehavior();
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 3522653b67ed8f3323aac55105eea6b99f547308..124ec6f5d7c1091d7eac7ba51b457bc457568a3a 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -308,9 +308,12 @@ public final class PowerManagerService extends SystemService
     private DreamManagerInternal mDreamManager;
     private LogicalLight mAttentionLight;
     private LogicalLight mButtonsLight;
+    private LogicalLight mKeyboardLight;
 
     private int mButtonTimeout;
     private float mButtonBrightness;
+    private boolean mKeyboardVisible;
+    private float mKeyboardBrightness;
 
     private boolean mButtonLightOnKeypressOnly;
 
@@ -572,8 +575,9 @@ public final class PowerManagerService extends SystemService
     public final float mScreenBrightnessMaximumVr;
     public final float mScreenBrightnessDefaultVr;
 
-    // Button brightness
+    // Button and keyboard brightness
     public final float mButtonBrightnessDefault;
+    public final float mKeyboardBrightnessDefault;
 
     // Value we store for tracking face down behavior.
     private boolean mIsFaceDown = false;
@@ -1091,6 +1095,9 @@ public final class PowerManagerService extends SystemService
         mButtonBrightnessDefault = mContext.getResources().getFloat(
                 com.android.internal.R.dimen
                         .config_buttonBrightnessSettingDefaultFloat);
+        mKeyboardBrightnessDefault = mContext.getResources().getFloat(
+                com.android.internal.R.dimen
+                        .config_keyboardBrightnessSettingDefaultFloat);
 
         synchronized (mLock) {
             mWakeLockSuspendBlocker =
@@ -1208,6 +1215,7 @@ public final class PowerManagerService extends SystemService
             mLightsManager = getLocalService(LightsManager.class);
             mAttentionLight = mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
             mButtonsLight = mLightsManager.getLight(LightsManager.LIGHT_ID_BUTTONS);
+            mKeyboardLight = mLightsManager.getLight(LightsManager.LIGHT_ID_KEYBOARD);
 
             // Initialize display power management.
             mDisplayManagerInternal.initPowerManagement(
@@ -1297,6 +1305,9 @@ public final class PowerManagerService extends SystemService
         resolver.registerContentObserver(Settings.System.getUriFor(
                 Settings.System.BUTTON_BACKLIGHT_ONLY_WHEN_PRESSED),
                 false, mSettingsObserver, UserHandle.USER_ALL);
+        resolver.registerContentObserver(Settings.Secure.getUriFor(
+                Settings.Secure.KEYBOARD_BRIGHTNESS),
+                false, mSettingsObserver, UserHandle.USER_ALL);
         IVrManager vrManager = IVrManager.Stub.asInterface(getBinderService(Context.VR_SERVICE));
         if (vrManager != null) {
             try {
@@ -1452,6 +1463,9 @@ public final class PowerManagerService extends SystemService
         mButtonLightOnKeypressOnly = Settings.System.getIntForUser(resolver,
                 Settings.System.BUTTON_BACKLIGHT_ONLY_WHEN_PRESSED,
                 0, UserHandle.USER_CURRENT) == 1;
+        mKeyboardBrightness = Settings.Secure.getFloatForUser(resolver,
+                Settings.Secure.KEYBOARD_BRIGHTNESS, mKeyboardBrightnessDefault,
+                UserHandle.USER_CURRENT);
 
         mDirty |= DIRTY_SETTINGS;
     }
@@ -2715,6 +2729,21 @@ public final class PowerManagerService extends SystemService
                                     }
                                 }
                             }
+
+                            if (mKeyboardLight != null) {
+                                float keyboardBrightness = BRIGHTNESS_OFF_FLOAT;
+                                if (isValidBrightness(mButtonBrightnessOverrideFromWindowManager)) {
+                                    if (mButtonBrightnessOverrideFromWindowManager >
+                                            PowerManager.BRIGHTNESS_MIN) {
+                                        keyboardBrightness =
+                                                mButtonBrightnessOverrideFromWindowManager;
+                                    }
+                                } else if (isValidKeyboardBrightness(mKeyboardBrightness)) {
+                                    keyboardBrightness = mKeyboardBrightness;
+                                }
+                                mKeyboardLight.setBrightness(mKeyboardVisible ?
+                                        keyboardBrightness : BRIGHTNESS_OFF_FLOAT);
+                            }
                         }
                     } else {
                         groupNextTimeout = lastUserActivityTime + screenOffTimeout;
@@ -2725,6 +2754,9 @@ public final class PowerManagerService extends SystemService
                                     mButtonsLight.setBrightness(BRIGHTNESS_OFF_FLOAT);
                                     mDisplayGroupPowerStateMapper.setButtonOnLocked(groupId, false);
                                 }
+                                if (mKeyboardLight != null) {
+                                    mKeyboardLight.setBrightness(BRIGHTNESS_OFF_FLOAT);
+                                }
                             }
                         }
                     }
@@ -3451,6 +3483,10 @@ public final class PowerManagerService extends SystemService
         return value > PowerManager.BRIGHTNESS_MIN && value <= PowerManager.BRIGHTNESS_MAX;
     }
 
+    private static boolean isValidKeyboardBrightness(float value) {
+        return value > PowerManager.BRIGHTNESS_MIN && value <= PowerManager.BRIGHTNESS_MAX;
+    }
+
     @VisibleForTesting
     int getDesiredScreenPolicyLocked(int groupId) {
         final int wakefulness = mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId);
@@ -4430,6 +4466,7 @@ public final class PowerManagerService extends SystemService
             pw.println("  mStayOnWhilePluggedInSetting=" + mStayOnWhilePluggedInSetting);
             pw.println("  mButtonTimeout=" + mButtonTimeout);
             pw.println("  mButtonBrightness=" + mButtonBrightness);
+            pw.println("  mKeyboardBrightness=" + mKeyboardBrightness);
             pw.println("  mScreenBrightnessModeSetting=" + mScreenBrightnessModeSetting);
             pw.println("  mButtonBrightnessOverrideFromWindowManager="
                     + mButtonBrightnessOverrideFromWindowManager);
@@ -5586,6 +5623,8 @@ public final class PowerManagerService extends SystemService
                     return mScreenBrightnessDefaultVr;
                 case PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_DEFAULT_BUTTON:
                     return mButtonBrightnessDefault;
+                case PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_DEFAULT_KEYBOARD:
+                    return mKeyboardBrightnessDefault;
                 default:
                     return PowerManager.BRIGHTNESS_INVALID_FLOAT;
             }
@@ -6000,6 +6039,22 @@ public final class PowerManagerService extends SystemService
             }
         }
 
+        @Override // Binder call
+        public void setKeyboardVisibility(boolean visible) {
+            synchronized (mLock) {
+                if (DEBUG_SPEW) {
+                    Slog.d(TAG, "setKeyboardVisibility: " + visible);
+                }
+                if (mKeyboardVisible != visible) {
+                    mKeyboardVisible = visible;
+                    synchronized (mLock) {
+                        mDirty |= DIRTY_USER_ACTIVITY;
+                        updatePowerStateLocked();
+                    }
+                }
+            }
+        }
+
         @Override // Binder call
         public void setDozeAfterScreenOff(boolean on) {
             mContext.enforceCallingOrSelfPermission(