summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/res/drawable/ic_device_thermostat_24.xml25
-rw-r--r--packages/SystemUI/res/values/config.xml2
-rw-r--r--packages/SystemUI/res/values/ids.xml1
-rw-r--r--packages/SystemUI/res/values/strings.xml8
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java75
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/PowerUI.java62
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java14
-rw-r--r--services/core/java/com/android/server/HardwarePropertiesManagerService.java15
8 files changed, 188 insertions, 14 deletions
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 000000000000..1972f6e4427c
--- /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/config.xml b/packages/SystemUI/res/values/config.xml
index 0f5d37ea3691..c025f932adf8 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -290,4 +290,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 2a895f98eefd..7ef2abdf9b2a 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -53,6 +53,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 194653ba15ce..d7033b26f563 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1766,4 +1766,12 @@
<!-- Tuner string -->
<string name="default_theme" translatable="false">Default</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 8a500c3219f0..7a45dd299151 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -50,7 +50,8 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
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;
@@ -65,6 +66,8 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
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)
@@ -89,6 +92,8 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
private boolean mPlaySound;
private boolean mInvalidCharger;
private SystemUIDialog mSaverConfirmation;
+ private boolean mTempWarning;
+ private SystemUIDialog mHighTempDialog;
public PowerNotificationWarnings(Context context, NotificationManager notificationManager,
PhoneStatusBar phoneStatusBar) {
@@ -105,6 +110,8 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
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
@@ -129,7 +136,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
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;
}
}
@@ -148,7 +155,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
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() {
@@ -178,12 +185,8 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
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) {
@@ -205,6 +208,53 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
}
@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.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();
}
@@ -317,6 +367,8 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
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);
}
@@ -333,6 +385,11 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
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 b651f2d99523..a7cbb3d94557 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -25,12 +25,15 @@ import android.content.IntentFilter;
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;
import java.io.FileDescriptor;
@@ -40,11 +43,13 @@ import java.util.Arrays;
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;
@@ -56,8 +61,12 @@ public class PowerUI extends SystemUI {
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,
@@ -76,6 +85,8 @@ public class PowerUI extends SystemUI {
false, obs, UserHandle.USER_ALL);
updateBatteryWarningLevels();
mReceiver.init();
+
+ initTemperatureWarning();
}
void updateBatteryWarningLevels() {
@@ -211,6 +222,53 @@ public class PowerUI extends SystemUI {
}
};
+ 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);
@@ -237,6 +295,8 @@ public class PowerUI extends SystemUI {
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);
}
@@ -248,6 +308,8 @@ public class PowerUI extends SystemUI {
void showInvalidChargerWarning();
void updateLowBatteryWarning();
boolean isInvalidChargerWarningShowing();
+ void dismissTemperatureWarning();
+ void showTemperatureWarning();
void dump(PrintWriter pw);
void userSwitched();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
index 5c87fb01e23c..7070961e39b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
@@ -117,4 +117,18 @@ public class PowerNotificationWarningsTest extends SysuiTestCase {
.notifyAsUser(anyString(), anyInt(), captor.capture(), any());
assertNotEqual(null, captor.getValue().sound);
}
+
+ @Test
+ public void testShowTemperatureWarning_NotifyAsUser() {
+ mPowerNotificationWarnings.showTemperatureWarning();
+ verify(mMockNotificationManager, times(1))
+ .notifyAsUser(anyString(), anyInt(), any(), any());
+ }
+
+ @Test
+ public void testDismissTemperatureWarning_CancelAsUser() {
+ mPowerNotificationWarnings.showTemperatureWarning();
+ mPowerNotificationWarnings.dismissTemperatureWarning();
+ verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(), anyInt(), any());
+ }
}
diff --git a/services/core/java/com/android/server/HardwarePropertiesManagerService.java b/services/core/java/com/android/server/HardwarePropertiesManagerService.java
index 23cf64a031af..36a16cd0a18b 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 @@ public class HardwarePropertiesManagerService extends IHardwarePropertiesManager
*
* @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 @@ public class HardwarePropertiesManagerService extends IHardwarePropertiesManager
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.");
}
}
}