diff options
| author | 2016-12-14 15:39:20 -0800 | |
|---|---|---|
| committer | 2017-01-04 16:53:44 -0800 | |
| commit | 67e97053c5efea9396be420e5b5015cd808ab417 (patch) | |
| tree | e6acf8943c7e44504f2b7c9a9fb1f88b449d1a5b | |
| parent | 2258e5fdb98d9625db43441bb15c92b858594e0a (diff) | |
Show notif when device reaches throttling temp
Adds logic to SystemUI that shows a notification alerting the user
that their phone has reached a certain temperature and has throttled
itself in order to cool down.
The logic is controlled by a configuration resource:
R.bool.config_showTemperatureWarning. If false, no action is taken.
When true, PowerUI checks every 30 seconds if the current temp of
HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN is greater than
the throttling temp of HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN.
If any one of the temperatures returned is greater, a notification is shown.
Clicking on the notification will show a dialog explaining more details
about what the device is doing in response to the high temperature.
The notification will disappear once the temperature drops below
the throttling temperature.
In order to check the temperature in SystemUI, HardwarePropertiesManager
has been updated to also allow any calls made by callers holding the
signature-level DEVICE_POWER permission.
Test: runtest systemui
Bug: 30995038
Change-Id: I1b3f122341911c68e90c8a49ad35267ac382b356
(cherry picked from commit b7caf1d06d5e4ef21cadcc6a68d4b4c4552fb7bc)
7 files changed, 168 insertions, 15 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 9eea3750a8ec..cf20c273fc1e 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 94d79f27e67f..cbac1dc4cf0f 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 3ceb331ff696..7f68be04882c 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 b831235d1179..67072180cbfb 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 @@ 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; @@ -64,6 +65,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) @@ -88,6 +91,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, PhoneStatusBar phoneStatusBar) { mContext = context; @@ -103,6 +108,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 @@ -127,7 +134,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; } } @@ -146,7 +153,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() { @@ -176,12 +183,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) { @@ -203,6 +206,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(); } @@ -315,6 +365,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); } @@ -331,6 +383,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 109a45660754..a7598685c628 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.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; @@ -41,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; @@ -57,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, getComponent(PhoneStatusBar.class)); @@ -74,6 +82,8 @@ public class PowerUI extends SystemUI { false, obs, UserHandle.USER_ALL); updateBatteryWarningLevels(); mReceiver.init(); + + initTemperatureWarning(); } void updateBatteryWarningLevels() { @@ -209,6 +219,47 @@ 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() { + // TODO: Add VR mode check + 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(); + } + + mHandler.postDelayed(this::updateTemperatureWarning, TEMPERATURE_INTERVAL); + } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.print("mLowBatteryAlertCloseLevel="); pw.println(mLowBatteryAlertCloseLevel); @@ -235,6 +286,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); } @@ -246,6 +299,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/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."); } } } |