Merge "Import translations. DO NOT MERGE" into nyc-mr2-dev
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index ebfb837..dfd2d87 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1092,6 +1092,26 @@
     <!-- Period of time in which to consider light samples in milliseconds. -->
     <integer name="config_autoBrightnessAmbientLightHorizon">10000</integer>
 
+    <!-- This flag enables light sensor sampling while dozing. A single sample is taken upon
+         entering doze mode, and another sample is taken every time the display enters STATE_DOZE
+         or STATE_DOZE_SUSPEND. It is recommended that config_dozeSensorLuxLevels and
+         config_dozeBrightnessBacklightValues have entries so that the doze mode brightness can be
+         determined dynamically.
+     -->
+    <bool name="config_allowAutoBrightnessActiveDozeLightSensor">false</bool>
+
+    <!-- This flag should be used with config_allowAutoBrightnessActiveDozeLightSensor set to true.
+
+         The screen brightness of a device is based off of a ring buffer of the last n seconds of
+         ambient light sensor sample readings.
+
+         If this flag is true, then this buffer is cleared every time a new sample is taken in doze
+         mode and the screen brightness is based off the new reading. This mode may be better suited
+         for watches.
+
+         If this flag is false, then this buffer is untouched. -->
+    <bool name="config_useNewSensorSamplesForDoze">false</bool>
+
     <!-- Screen brightness used to dim the screen when the user activity
          timeout expires.  May be less than the minimum allowed brightness setting
          that can be set by the user. -->
@@ -1187,21 +1207,6 @@
     <integer-array name="config_dynamicHysteresisLuxLevels">
     </integer-array>
 
-    <!-- This flag requires config_dozeBrightnessBacklightValues to have two or more entries; it is
-         recommended that config_screenBrightnessDoze be greater than or equal to all these entries
-         since this value is used as the doze screen brightness until a new sensor sample is
-         acquired. This flag only affects the screen brightness while dozing.
-
-         The screen brightness of a device is based off of a ring buffer of the last n seconds of
-         ambient light sensor sample readings.
-
-         If this flag is true, then this buffer is cleared and the screen brightness is based off of
-         ambient light sensor readings that are obtained while the device is dozing.  This mode may
-         be better suited for watches.
-
-         If this flag is false, then this buffer is untouched. -->
-    <bool name="config_useNewSensorSamplesForDoze">false</bool>
-
     <!-- Array of ambient light sensor lux threshold values for determining screen brightness for
          devices that have both an ambient light sensor and the screen on while dozing. This is
          used to determine the screen brightness while dozing by calculating the index to use for
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d95f6e9..19ad216 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1676,6 +1676,7 @@
   <java-symbol type="array" name="config_notificationFallbackVibePattern" />
   <java-symbol type="array" name="config_onlySingleDcAllowed" />
   <java-symbol type="bool" name="config_useNewSensorSamplesForDoze" />
+  <java-symbol type="bool" name="config_allowAutoBrightnessActiveDozeLightSensor" />
   <java-symbol type="bool" name="config_useAttentionLight" />
   <java-symbol type="bool" name="config_animateScreenLights" />
   <java-symbol type="bool" name="config_automatic_brightness_available" />
diff --git a/packages/SystemUI/res/drawable/ic_device_thermostat_24.xml b/packages/SystemUI/res/drawable/ic_device_thermostat_24.xml
new file mode 100644
index 0000000..1972f6e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_device_thermostat_24.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2016 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"
+        android:tint="?attr/colorControlNormal">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M15,13L15,5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v8c-1.21,0.91 -2,2.37 -2,4 0,2.76 2.24,5 5,5s5,-2.24 5,-5c0,-1.63 -0.79,-3.09 -2,-4zM11,5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1h-1v1h1v2h-1v1h1v2h-2L11,5z"/>
+</vector>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index 0d4b9e2..7883fd8 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -344,7 +344,7 @@
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"নেটওয়ার্ক নিরীক্ষণ\nকরা হতে পারে"</string>
     <string name="description_target_search" msgid="3091587249776033139">"অনুসন্ধান করুন"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> এর জন্য উপরের দিকে স্লাইড করুন৷"</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> এর জন্য বাম দিকে স্লাইড করুন৷"</string>
+    <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> এর জন্য বাঁ দিকে স্লাইড করুন৷"</string>
     <string name="zen_priority_introduction" msgid="3070506961866919502">"আপনার নির্দিষ্ট অ্যালার্ম, অনুস্মারক, ইভেন্ট, এবং কলারগুলি ব্যতীত আপনাকে শব্দ এবং কম্পনগুলির দ্বারা বিরক্ত করা হবে না৷"</string>
     <string name="zen_priority_customize_button" msgid="7948043278226955063">"কাস্টমাইজ করুন"</string>
     <string name="zen_silence_introduction_voice" msgid="2284540992298200729">"এটি অ্যালার্ম, সংগীত, ভিডিও এবং গেমগুলি থেকে আসা সমস্ত রকমের ধ্বনি এবং কম্পনগুলিকে বন্ধ করে৷ আপনি এখনও ফোন কলগুলি করতে পারবেন৷"</string>
@@ -541,7 +541,7 @@
     <string name="keyboard_key_back" msgid="2337450286042721351">"ফিরুন"</string>
     <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"উপরে"</string>
     <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"নিচে"</string>
-    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"বাম"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"বাঁ"</string>
     <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"ডান"</string>
     <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"কেন্দ্র"</string>
     <string name="keyboard_key_tab" msgid="3871485650463164476">"ট্যাব"</string>
@@ -628,7 +628,7 @@
   </string-array>
     <string name="other" msgid="4060683095962566764">"অন্যান্য"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"বিভক্ত-স্ক্রীন বিভাজক"</string>
-    <string name="accessibility_action_divider_left_full" msgid="2801570521881574972">"বাম দিকের অংশ নিয়ে পূর্ণ স্ক্রীন"</string>
+    <string name="accessibility_action_divider_left_full" msgid="2801570521881574972">"বাঁ দিকের অংশ নিয়ে পূর্ণ স্ক্রীন"</string>
     <string name="accessibility_action_divider_left_70" msgid="3612060638991687254">"৭০% বাকি আছে"</string>
     <string name="accessibility_action_divider_left_50" msgid="1248083470322193075">"৫০% বাকি আছে"</string>
     <string name="accessibility_action_divider_left_30" msgid="543324403127069386">"৩০% বাকি আছে"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index fa85cfd..d5478b7 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -367,7 +367,7 @@
     <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Càrrega ràpida (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar-se)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Càrrega lenta (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar-se)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Canvia d\'usuari"</string>
-    <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Canvia l\'usuari. Usuari actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
+    <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Canvia d\'usuari. Usuari actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Usuari actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_quick_contact" msgid="3020367729287990475">"Mostra el perfil"</string>
     <string name="user_add_user" msgid="5110251524486079492">"Afegeix un usuari"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 9eea375..cf20c27 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -284,4 +284,6 @@
 
     <bool name="quick_settings_show_full_alarm">false</bool>
 
+    <bool name="config_showTemperatureWarning">false</bool>
+
 </resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 94d79f2..cbac1dc 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -44,6 +44,7 @@
     <item type="id" name="notification_screenshot"/>
     <item type="id" name="notification_hidden"/>
     <item type="id" name="notification_volumeui"/>
+    <item type="id" name="notification_temperature"/>
     <item type="id" name="transformation_start_x_tag"/>
     <item type="id" name="transformation_start_y_tag"/>
     <item type="id" name="transformation_start_scale_x_tag"/>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 3ceb331..7f68be0 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1694,4 +1694,12 @@
     <!-- Label that replaces other notification controls when the notification is from the system
          and cannot be silenced (see @string/show_silently) or blocked (see @string/block) -->
     <string name="cant_silence_or_block">Notifications can\'t be silenced or blocked</string>
+
+    <!-- Title for notification (and dialog) that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=30] -->
+    <string name="high_temp_title">Phone is getting warm</string>
+    <!-- Message body for notification that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=70] -->
+    <string name="high_temp_notif_message">Some features limited while phone cools down</string>
+    <!-- Text body for dialog alerting user that their phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=300] -->
+    <string name="high_temp_dialog_message">Your phone will automatically try to cool down. You can still use your phone, but it may run slower.\n\nOnce your phone has cooled down, it will run normally.</string>
+
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index b831235..4cb40d5 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -49,7 +49,8 @@
     private static final String TAG = PowerUI.TAG + ".Notification";
     private static final boolean DEBUG = PowerUI.DEBUG;
 
-    private static final String TAG_NOTIFICATION = "low_battery";
+    private static final String TAG_NOTIFICATION_BATTERY = "low_battery";
+    private static final String TAG_NOTIFICATION_TEMPERATURE = "high_temp";
 
     private static final int SHOWING_NOTHING = 0;
     private static final int SHOWING_WARNING = 1;
@@ -64,6 +65,8 @@
     private static final String ACTION_SHOW_BATTERY_SETTINGS = "PNW.batterySettings";
     private static final String ACTION_START_SAVER = "PNW.startSaver";
     private static final String ACTION_DISMISSED_WARNING = "PNW.dismissedWarning";
+    private static final String ACTION_CLICKED_TEMP_WARNING = "PNW.clickedTempWarning";
+    private static final String ACTION_DISMISSED_TEMP_WARNING = "PNW.dismissedTempWarning";
 
     private static final AudioAttributes AUDIO_ATTRIBUTES = new AudioAttributes.Builder()
             .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
@@ -88,6 +91,8 @@
     private boolean mPlaySound;
     private boolean mInvalidCharger;
     private SystemUIDialog mSaverConfirmation;
+    private boolean mTempWarning;
+    private SystemUIDialog mHighTempDialog;
 
     public PowerNotificationWarnings(Context context, PhoneStatusBar phoneStatusBar) {
         mContext = context;
@@ -103,6 +108,8 @@
         pw.print("mInvalidCharger="); pw.println(mInvalidCharger);
         pw.print("mShowing="); pw.println(SHOWING_STRINGS[mShowing]);
         pw.print("mSaverConfirmation="); pw.println(mSaverConfirmation != null ? "not null" : null);
+        pw.print("mTempWarning="); pw.println(mTempWarning);
+        pw.print("mHighTempDialog="); pw.println(mHighTempDialog != null ? "not null" : null);
     }
 
     @Override
@@ -127,7 +134,7 @@
             showWarningNotification();
             mShowing = SHOWING_WARNING;
         } else {
-            mNoMan.cancelAsUser(TAG_NOTIFICATION, R.id.notification_power, UserHandle.ALL);
+            mNoMan.cancelAsUser(TAG_NOTIFICATION_BATTERY, R.id.notification_power, UserHandle.ALL);
             mShowing = SHOWING_NOTHING;
         }
     }
@@ -146,7 +153,7 @@
                         com.android.internal.R.color.system_notification_accent_color));
         SystemUI.overrideNotificationAppName(mContext, nb);
         final Notification n = nb.build();
-        mNoMan.notifyAsUser(TAG_NOTIFICATION, R.id.notification_power, n, UserHandle.ALL);
+        mNoMan.notifyAsUser(TAG_NOTIFICATION_BATTERY, R.id.notification_power, n, UserHandle.ALL);
     }
 
     private void showWarningNotification() {
@@ -176,12 +183,8 @@
             mPlaySound = false;
         }
         SystemUI.overrideNotificationAppName(mContext, nb);
-        mNoMan.notifyAsUser(TAG_NOTIFICATION, R.id.notification_power, nb.build(), UserHandle.ALL);
-    }
-
-    private PendingIntent pendingActivity(Intent intent) {
-        return PendingIntent.getActivityAsUser(mContext,
-                0, intent, 0, null, UserHandle.CURRENT);
+        mNoMan.notifyAsUser(
+                TAG_NOTIFICATION_BATTERY, R.id.notification_power, nb.build(), UserHandle.ALL);
     }
 
     private PendingIntent pendingBroadcast(String action) {
@@ -203,6 +206,54 @@
     }
 
     @Override
+    public void dismissTemperatureWarning() {
+        if (!mTempWarning) {
+            return;
+        }
+        mTempWarning = false;
+        mNoMan.cancelAsUser(
+                TAG_NOTIFICATION_TEMPERATURE, R.id.notification_temperature, UserHandle.ALL);
+    }
+
+    @Override
+    public void showTemperatureWarning() {
+        if (mTempWarning) {
+            return;
+        }
+        mTempWarning = true;
+        final Notification.Builder nb = new Notification.Builder(mContext)
+                .setSmallIcon(R.drawable.ic_device_thermostat_24)
+                .setWhen(0)
+                .setShowWhen(false)
+                .setContentTitle(mContext.getString(R.string.high_temp_title))
+                .setContentText(mContext.getString(R.string.high_temp_notif_message))
+                .setPriority(Notification.PRIORITY_HIGH)
+                .setVisibility(Notification.VISIBILITY_PUBLIC)
+                .setContentIntent(pendingBroadcast(ACTION_CLICKED_TEMP_WARNING))
+                .setDeleteIntent(pendingBroadcast(ACTION_DISMISSED_TEMP_WARNING))
+                .setColor(mContext.getColor(
+                        com.android.internal.R.color.battery_saver_mode_color));
+        SystemUI.overrideNotificationAppName(mContext, nb);
+        final Notification n = nb.build();
+        mNoMan.notifyAsUser(
+                TAG_NOTIFICATION_TEMPERATURE, R.id.notification_temperature, n, UserHandle.ALL);
+
+    }
+
+    private void showTemperatureDialog() {
+        if (mHighTempDialog != null) return;
+        final SystemUIDialog d = new SystemUIDialog(mContext);
+        d.setIconAttribute(android.R.attr.alertDialogIcon);
+        d.setTitle(R.string.high_temp_title);
+        d.setMessage(R.string.high_temp_dialog_message);
+        d.setPositiveButton(com.android.internal.R.string.ok, null);
+        d.setShowForAllUsers(true);
+        d.setOnDismissListener(dialog -> mHighTempDialog = null);
+        d.show();
+        mHighTempDialog = d;
+    }
+
+    @Override
     public void updateLowBatteryWarning() {
         updateNotification();
     }
@@ -315,6 +366,8 @@
             filter.addAction(ACTION_SHOW_BATTERY_SETTINGS);
             filter.addAction(ACTION_START_SAVER);
             filter.addAction(ACTION_DISMISSED_WARNING);
+            filter.addAction(ACTION_CLICKED_TEMP_WARNING);
+            filter.addAction(ACTION_DISMISSED_TEMP_WARNING);
             mContext.registerReceiverAsUser(this, UserHandle.ALL, filter,
                     android.Manifest.permission.STATUS_BAR_SERVICE, mHandler);
         }
@@ -331,6 +384,11 @@
                 showStartSaverConfirmation();
             } else if (action.equals(ACTION_DISMISSED_WARNING)) {
                 dismissLowBatteryWarning();
+            } else if (ACTION_CLICKED_TEMP_WARNING.equals(action)) {
+                dismissTemperatureWarning();
+                showTemperatureDialog();
+            } else if (ACTION_DISMISSED_TEMP_WARNING.equals(action)) {
+                dismissTemperatureWarning();
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 109a456..bdb2295 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -24,13 +24,15 @@
 import android.database.ContentObserver;
 import android.os.BatteryManager;
 import android.os.Handler;
+import android.os.HardwarePropertiesManager;
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.text.format.DateUtils;
 import android.util.Log;
 import android.util.Slog;
-
+import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 
@@ -41,11 +43,13 @@
 public class PowerUI extends SystemUI {
     static final String TAG = "PowerUI";
     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    private static final long TEMPERATURE_INTERVAL = 30 * DateUtils.SECOND_IN_MILLIS;
 
     private final Handler mHandler = new Handler();
     private final Receiver mReceiver = new Receiver();
 
     private PowerManager mPowerManager;
+    private HardwarePropertiesManager mHardwarePropertiesManager;
     private WarningsUI mWarnings;
     private int mBatteryLevel = 100;
     private int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN;
@@ -57,8 +61,12 @@
 
     private long mScreenOffTime = -1;
 
+    private float mThrottlingTemp;
+
     public void start() {
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        mHardwarePropertiesManager = (HardwarePropertiesManager)
+                mContext.getSystemService(Context.HARDWARE_PROPERTIES_SERVICE);
         mScreenOffTime = mPowerManager.isScreenOn() ? -1 : SystemClock.elapsedRealtime();
         mWarnings = new PowerNotificationWarnings(mContext, getComponent(PhoneStatusBar.class));
 
@@ -74,6 +82,8 @@
                 false, obs, UserHandle.USER_ALL);
         updateBatteryWarningLevels();
         mReceiver.init();
+
+        initTemperatureWarning();
     }
 
     void updateBatteryWarningLevels() {
@@ -209,6 +219,53 @@
         }
     };
 
+    private void initTemperatureWarning() {
+        if (!mContext.getResources().getBoolean(R.bool.config_showTemperatureWarning)) {
+            return;
+        }
+
+        // Get the throttling temperature. No need to check if we're not throttling.
+        float[] throttlingTemps = mHardwarePropertiesManager.getDeviceTemperatures(
+                HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
+                HardwarePropertiesManager.TEMPERATURE_THROTTLING);
+        if (throttlingTemps == null
+                || throttlingTemps.length == 0
+                || throttlingTemps[0] == HardwarePropertiesManager.UNDEFINED_TEMPERATURE) {
+            return;
+        }
+        mThrottlingTemp = throttlingTemps[0];
+
+        // We have passed all of the checks, start checking the temp
+        updateTemperatureWarning();
+    }
+
+    private void updateTemperatureWarning() {
+        PhoneStatusBar phoneStatusBar = getComponent(PhoneStatusBar.class);
+        if (phoneStatusBar != null && phoneStatusBar.isDeviceInVrMode()) {
+            // ensure the warning isn't showing, since VR shows its own warning
+            mWarnings.dismissTemperatureWarning();
+        } else {
+            float[] temps = mHardwarePropertiesManager.getDeviceTemperatures(
+                    HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
+                    HardwarePropertiesManager.TEMPERATURE_CURRENT);
+            boolean shouldShowTempWarning = false;
+            for (float temp : temps) {
+                if (temp >= mThrottlingTemp) {
+                    shouldShowTempWarning = true;
+                    break;
+                }
+            }
+            if (shouldShowTempWarning) {
+                mWarnings.showTemperatureWarning();
+            } else {
+                mWarnings.dismissTemperatureWarning();
+            }
+        }
+
+        // TODO: skip this when in VR mode since we already get a callback
+        mHandler.postDelayed(this::updateTemperatureWarning, TEMPERATURE_INTERVAL);
+    }
+
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.print("mLowBatteryAlertCloseLevel=");
         pw.println(mLowBatteryAlertCloseLevel);
@@ -235,6 +292,8 @@
                 Settings.Global.LOW_BATTERY_SOUND_TIMEOUT, 0));
         pw.print("bucket: ");
         pw.println(Integer.toString(findBatteryLevelBucket(mBatteryLevel)));
+        pw.print("mThrottlingTemp=");
+        pw.println(Float.toString(mThrottlingTemp));
         mWarnings.dump(pw);
     }
 
@@ -246,6 +305,8 @@
         void showInvalidChargerWarning();
         void updateLowBatteryWarning();
         boolean isInvalidChargerWarningShowing();
+        void dismissTemperatureWarning();
+        void showTemperatureWarning();
         void dump(PrintWriter pw);
         void userSwitched();
     }
diff --git a/services/core/java/com/android/server/HardwarePropertiesManagerService.java b/services/core/java/com/android/server/HardwarePropertiesManagerService.java
index 23cf64a..36a16cd 100644
--- a/services/core/java/com/android/server/HardwarePropertiesManagerService.java
+++ b/services/core/java/com/android/server/HardwarePropertiesManagerService.java
@@ -16,6 +16,8 @@
 
 package com.android.server;
 
+import android.Manifest;
+import android.app.ActivityManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -80,8 +82,9 @@
      *
      * @param callingPackage The calling package name.
      *
-     * @throws SecurityException if something other than the profile or device owner, or the
-     *        current VR service tries to retrieve information provided by this service.
+     * @throws SecurityException if something other than the profile or device owner, the
+     *        current VR service, or a caller holding the {@link Manifest.permission#DEVICE_POWER}
+     *        permission tries to retrieve information provided by this service.
      */
     private void enforceHardwarePropertiesRetrievalAllowed(String callingPackage)
             throws SecurityException {
@@ -100,9 +103,11 @@
         final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
         final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
         if (!dpm.isDeviceOwnerApp(callingPackage) && !dpm.isProfileOwnerApp(callingPackage)
-                && !vrService.isCurrentVrListener(callingPackage, userId)) {
-            throw new SecurityException("The caller is not a device or profile owner or bound "
-                + "VrListenerService.");
+                && !vrService.isCurrentVrListener(callingPackage, userId)
+                && mContext.checkCallingOrSelfPermission(Manifest.permission.DEVICE_POWER)
+                        != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("The caller is not a device or profile owner, bound "
+                + "VrListenerService, or holding the DEVICE_POWER permission.");
         }
     }
 }
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 8bfa7d7..f757666 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -178,8 +178,13 @@
     // Are we going to adjust brightness while dozing.
     private boolean mDozing;
 
-    // True if we are collecting one last light sample when dozing to set the screen brightness
-    private boolean mActiveDozeLightSensor = false;
+    // True if we are collecting light samples when dozing to set the screen brightness. A single
+    // light sample is collected when entering doze mode. If autobrightness is enabled, calls to
+    // DisplayPowerController#updatePowerState in doze mode will also collect light samples.
+    private final boolean mUseActiveDozeLightSensorConfig;
+
+    // True if the ambient light sensor ring buffer should be cleared when entering doze mode.
+    private final boolean mUseNewSensorSamplesForDoze;
 
     // True if we are collecting a brightness adjustment sample, along with some data
     // for the initial state of the sample.
@@ -197,6 +202,7 @@
             int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig,
             long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
             int ambientLightHorizon, float autoBrightnessAdjustmentMaxGamma,
+            boolean activeDozeLightSensor, boolean useNewSensorSamplesForDoze,
             LuxLevels luxLevels) {
         mCallbacks = callbacks;
         mTwilight = LocalServices.getService(TwilightManager.class);
@@ -215,6 +221,8 @@
         mAmbientLightHorizon = ambientLightHorizon;
         mWeightingIntercept = ambientLightHorizon;
         mScreenAutoBrightnessAdjustmentMaxGamma = autoBrightnessAdjustmentMaxGamma;
+        mUseNewSensorSamplesForDoze = useNewSensorSamplesForDoze;
+        mUseActiveDozeLightSensorConfig = activeDozeLightSensor;
         mLuxLevels = luxLevels;
 
         mHandler = new AutomaticBrightnessHandler(looper);
@@ -242,20 +250,18 @@
         // switch to a wake-up light sensor instead but for now we will simply disable the sensor
         // and hold onto the last computed screen auto brightness.  We save the dozing flag for
         // debugging purposes.
-        mDozing = dozing;
-        boolean enableSensor = enable && !dozing;
-        if (enableSensor && !mLightSensorEnabled && mActiveDozeLightSensor) {
-            mActiveDozeLightSensor = false;
-        } else if (!enableSensor && mLightSensorEnabled && mLuxLevels.hasDynamicDozeBrightness()) {
-            // keep the light sensor active until another light sample is taken in doze mode
-            mActiveDozeLightSensor = true;
-            if (mLuxLevels.useNewSensorSamplesForDoze()) {
-                mAmbientLightRingBuffer.clear();
-                mInitialHorizonAmbientLightRingBuffer.clear();
-                mAmbientLuxValid = false;
-                return;
+        boolean enableSensor = enable && (dozing ? mUseActiveDozeLightSensorConfig : true);
+        if (enableSensor && dozing && !mDozing && mLightSensorEnabled
+                && mUseNewSensorSamplesForDoze) {
+            mAmbientLightRingBuffer.clear();
+            mInitialHorizonAmbientLightRingBuffer.clear();
+            if (DEBUG) {
+                Slog.d(TAG, "configure: Clearing ambient light ring buffers when entering doze.");
             }
+            mAmbientLuxValid = false;
+            adjustLightSensorRate(mInitialLightSensorRate);
         }
+        mDozing = dozing;
         boolean changed = setLightSensorEnabled(enableSensor);
         changed |= setScreenAutoBrightnessAdjustment(adjustment);
         changed |= setUseTwilight(useTwilight);
@@ -315,6 +321,9 @@
     private boolean setLightSensorEnabled(boolean enable) {
         if (enable) {
             if (!mLightSensorEnabled) {
+                if (DEBUG) {
+                    Slog.d(TAG, "setLightSensorEnabled: sensor enabled");
+                }
                 mLightSensorEnabled = true;
                 mAmbientLightRingBuffer.clear();
                 mInitialHorizonAmbientLightRingBuffer.clear();
@@ -327,6 +336,9 @@
             }
         } else {
             if (mLightSensorEnabled) {
+                if (DEBUG) {
+                    Slog.d(TAG, "setLightSensorEnabled: sensor disabled");
+                }
                 mLightSensorEnabled = false;
                 mRecentLightSamples = 0;
                 mCurrentLightSensorRate = -1;
@@ -346,8 +358,11 @@
         }
         applyLightSensorMeasurement(time, lux);
         updateAmbientLux(time);
-        if (mActiveDozeLightSensor) {
+        if (mUseActiveDozeLightSensorConfig && mDozing) {
             // disable the ambient light sensor and update the screen brightness
+            if (DEBUG) {
+                Slog.d(TAG, "handleLightSensorEvent: doze ambient light sensor reading: " + lux);
+            }
             setLightSensorEnabled(false);
             updateAutoBrightness(true /*sendUpdate*/);
         }
@@ -566,7 +581,7 @@
         }
 
         int newScreenAutoBrightness;
-        if (mActiveDozeLightSensor) {
+        if (mUseActiveDozeLightSensorConfig && mDozing) {
             newScreenAutoBrightness = mLuxLevels.getDozeBrightness(mAmbientLux);
         } else {
             newScreenAutoBrightness =
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index de5bffd..c103312 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -153,8 +153,8 @@
     // True if should use light sensor to automatically determine doze screen brightness.
     private final boolean mAllowAutoBrightnessWhileDozingConfig;
 
-    // True if using only new sensor samples to automatically determine doze screen brightness.
-    private boolean mUseNewSensorSamplesForDoze;
+    // True if collecting light sensor samples in doze mode.
+    private boolean mUseActiveDozeLightSensorConfig;
 
     // True if we should fade the screen while turning it off, false if we should play
     // a stylish color fade animation instead.
@@ -357,11 +357,12 @@
                     com.android.internal.R.array.config_dozeSensorLuxLevels);
             int[] dozeBrightnessBacklightValues = resources.getIntArray(
                     com.android.internal.R.array.config_dozeBrightnessBacklightValues);
-            mUseNewSensorSamplesForDoze = resources.getBoolean(
+            boolean useNewSensorSamplesForDoze = resources.getBoolean(
                     com.android.internal.R.bool.config_useNewSensorSamplesForDoze);
+            mUseActiveDozeLightSensorConfig = resources.getBoolean(
+                    com.android.internal.R.bool.config_allowAutoBrightnessActiveDozeLightSensor);
             LuxLevels luxLevels = new LuxLevels(brightHysteresisLevels, darkHysteresisLevels,
-                    luxHysteresisLevels, mUseNewSensorSamplesForDoze, dozeSensorLuxLevels,
-                    dozeBrightnessBacklightValues);
+                    luxHysteresisLevels, dozeSensorLuxLevels, dozeBrightnessBacklightValues);
 
             Spline screenAutoBrightnessSpline = createAutoBrightnessSpline(lux, screenBrightness);
             if (screenAutoBrightnessSpline == null) {
@@ -389,7 +390,8 @@
                         mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
                         initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
                         autoBrightnessResetAmbientLuxAfterWarmUp, ambientLightHorizon,
-                        autoBrightnessAdjustmentMaxGamma, luxLevels);
+                        autoBrightnessAdjustmentMaxGamma, mUseActiveDozeLightSensorConfig,
+                        useNewSensorSamplesForDoze, luxLevels);
             }
         }
 
@@ -643,8 +645,9 @@
         if (mAutomaticBrightnessController != null) {
             final boolean autoBrightnessEnabledInDoze = mAllowAutoBrightnessWhileDozingConfig
                     && (state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND);
-            autoBrightnessEnabled = mPowerRequest.useAutoBrightness
+            autoBrightnessEnabled = (mPowerRequest.useAutoBrightness
                     && (state == Display.STATE_ON || autoBrightnessEnabledInDoze)
+                    || mUseActiveDozeLightSensorConfig && autoBrightnessEnabledInDoze)
                     && brightness < 0;
             final boolean userInitiatedChange = autoBrightnessAdjustmentChanged
                     && mPowerRequest.brightnessSetByUser;
@@ -687,8 +690,11 @@
         if (state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND) {
             if (brightness < 0) {
                 brightness = mScreenBrightnessDozeConfig;
-            } else if (mUseNewSensorSamplesForDoze) {
+            } else if (mUseActiveDozeLightSensorConfig) {
                 brightness = Math.min(brightness, mScreenBrightnessDozeConfig);
+                if (DEBUG) {
+                    Slog.d(TAG, "updatePowerState: ALS-based doze brightness: " + brightness);
+                }
             }
         }
 
diff --git a/services/core/java/com/android/server/display/LuxLevels.java b/services/core/java/com/android/server/display/LuxLevels.java
index a13626d..a796871 100644
--- a/services/core/java/com/android/server/display/LuxLevels.java
+++ b/services/core/java/com/android/server/display/LuxLevels.java
@@ -26,12 +26,10 @@
 
     private static final boolean DEBUG = true;
 
-    private final boolean mUseNewSensorSamplesForDoze;
-
     private final float[] mBrightLevels;
     private final float[] mDarkLevels;
     private final float[] mLuxHysteresisLevels;
-    private final float[] mDozeBacklightLevels;
+    private final float[] mDozeBrightnessBacklightValues;
     private final float[] mDozeSensorLuxLevels;
 
   /**
@@ -41,31 +39,29 @@
    * {@code luxLevels} has length n+1.
    *
    * {@code dozeSensorLuxLevels} has length r.
-   * {@code dozeBacklightLevels} has length r+1.
+   * {@code dozeBrightnessBacklightValues} has length r+1.
    *
    * @param brightLevels an array of brightening hysteresis constraint constants
    * @param darkLevels an array of darkening hysteresis constraint constants
    * @param luxHysteresisLevels a monotonically increasing array of illuminance thresholds in lux
    * @param dozeSensorLuxLevels a monotonically increasing array of ALS thresholds in lux
-   * @param dozeBacklightLevels an array of screen brightness values for doze mode in lux
+   * @param dozeBrightnessBacklightValues an array of screen brightness values for doze mode in lux
    */
     public LuxLevels(int[] brightLevels, int[] darkLevels, int[] luxHysteresisLevels,
-            boolean useNewSensorSamplesForDoze, int[] dozeSensorLuxLevels,
-            int[] dozeBacklightLevels) {
+            int[] dozeSensorLuxLevels, int[] dozeBrightnessBacklightValues) {
         if (brightLevels.length != darkLevels.length ||
             darkLevels.length !=luxHysteresisLevels.length + 1) {
             throw new IllegalArgumentException("Mismatch between hysteresis array lengths.");
         }
-        if (dozeBacklightLevels.length > 0 && dozeSensorLuxLevels.length > 0
-            && dozeBacklightLevels.length != dozeSensorLuxLevels.length + 1) {
+        if (dozeBrightnessBacklightValues.length > 0 && dozeSensorLuxLevels.length > 0
+            && dozeBrightnessBacklightValues.length != dozeSensorLuxLevels.length + 1) {
             throw new IllegalArgumentException("Mismatch between doze lux array lengths.");
         }
         mBrightLevels = setArrayFormat(brightLevels, 1000.0f);
         mDarkLevels = setArrayFormat(darkLevels, 1000.0f);
         mLuxHysteresisLevels = setArrayFormat(luxHysteresisLevels, 1.0f);
-        mUseNewSensorSamplesForDoze = useNewSensorSamplesForDoze;
         mDozeSensorLuxLevels = setArrayFormat(dozeSensorLuxLevels, 1.0f);
-        mDozeBacklightLevels = setArrayFormat(dozeBacklightLevels, 1.0f);
+        mDozeBrightnessBacklightValues = setArrayFormat(dozeBrightnessBacklightValues, 1.0f);
     }
 
     /**
@@ -98,7 +94,7 @@
      * Return the doze backlight brightness level for the given ambient sensor lux level.
      */
     public int getDozeBrightness(float lux) {
-        int dozeBrightness = (int) getReferenceLevel(lux, mDozeBacklightLevels,
+        int dozeBrightness = (int) getReferenceLevel(lux, mDozeBrightnessBacklightValues,
             mDozeSensorLuxLevels);
         if (DEBUG) {
             Slog.d(TAG, "doze brightness: " + dozeBrightness + ", lux=" + lux);
@@ -126,13 +122,6 @@
     }
 
     /**
-     * Return if new ALS samples should be used for determining screen brightness while dozing.
-     */
-    public boolean useNewSensorSamplesForDoze() {
-        return mUseNewSensorSamplesForDoze;
-    }
-
-    /**
      * Return a float array where each i-th element equals {@code configArray[i]/divideFactor}.
      */
     private float[] setArrayFormat(int[] configArray, float divideFactor) {