Merge "DO NOT MERGE Implement USB High Temperature warning dialog(1/N)" into pi-dev
diff --git a/packages/SystemUI/res/layout/overheat_dialog_content.xml b/packages/SystemUI/res/layout/overheat_dialog_content.xml
new file mode 100644
index 0000000..d78272f
--- /dev/null
+++ b/packages/SystemUI/res/layout/overheat_dialog_content.xml
@@ -0,0 +1,39 @@
+<!--
+ Copyright (C) 2018 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.
+-->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/contentPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="48dp">
+
+ <ScrollView
+ android:id="@+id/scrollView"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/alarm_dialog_panel_padding"
+ android:paddingEnd="?android:attr/dialogPreferredPadding"
+ android:paddingStart="?android:attr/dialogPreferredPadding"
+ android:clipToPadding="false">
+
+ <TextView
+ android:id="@android:id/message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/high_temp_alarm_notify_message"
+ style="@android:style/TextAppearance.Material.Subhead"/>
+ </ScrollView>
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/overheat_dialog_title.xml b/packages/SystemUI/res/layout/overheat_dialog_title.xml
new file mode 100644
index 0000000..65a512a
--- /dev/null
+++ b/packages/SystemUI/res/layout/overheat_dialog_title.xml
@@ -0,0 +1,46 @@
+<!--
+ Copyright (C) 2018 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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/title_template"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center_vertical|start"
+ android:paddingStart="?android:attr/dialogPreferredPadding"
+ android:paddingEnd="?android:attr/dialogPreferredPadding"
+ android:paddingTop="@dimen/alarm_dialog_panel_padding">
+
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="32dip"
+ android:layout_height="32dip"
+ android:layout_marginEnd="8dip"
+ android:scaleType="fitCenter"
+ android:tint="?android:attr/colorError"
+ android:src="?android:attr/alertDialogIcon"/>
+
+ <com.android.internal.widget.DialogTitle
+ android:id="@+id/alertTitle"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textAlignment="viewStart"
+ android:text="@string/high_temp_alarm_title"
+ android:importantForAccessibility="noHideDescendants"
+ style="?android:attr/windowTitleStyle"/>
+</LinearLayout>
diff --git a/packages/SystemUI/res/raw/overheat_alarm.ogg b/packages/SystemUI/res/raw/overheat_alarm.ogg
new file mode 100644
index 0000000..5624f42
--- /dev/null
+++ b/packages/SystemUI/res/raw/overheat_alarm.ogg
Binary files differ
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index a68ba9b..317fe31 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -368,17 +368,31 @@
<bool name="quick_settings_show_full_alarm">false</bool>
+ <!-- Whether or not beep sound should be when overheat -->
+ <bool name="config_alarmTemperatureBeepSound">false</bool>
+
<!-- Whether to show a warning notification when the device reaches a certain temperature. -->
<integer name="config_showTemperatureWarning">0</integer>
+ <!-- Whether to show a alarm dialog when device of usb cable reaches a certain temperature. -->
+ <integer name="config_showTemperatureAlarm">0</integer>
+
<!-- Temp at which to show a warning notification if config_showTemperatureWarning is true.
If < 0, uses the skin temperature sensor shutdown value from
HardwarePropertiesManager#getDeviceTemperatures - config_warningTemperatureTolerance. -->
<integer name="config_warningTemperature">-1</integer>
+ <!-- Temp at which to show a alarm dialog if config_showTemperatureAlarm is true.
+ If < 0, uses the skin temperature sensor shutdown value of index[1] from
+ HardwarePropertiesManager#getDeviceTemperatures -->
+ <integer name="config_alarmTemperature">60</integer>
+
<!-- Fudge factor for how much below the shutdown temp to show the warning. -->
<integer name="config_warningTemperatureTolerance">2</integer>
+ <!-- Fudge factor for how much below the overheat temp to dismiss alarm. -->
+ <integer name="config_alarmTemperatureTolerance">5</integer>
+
<!-- Accessibility actions -->
<item type="id" name="action_split_task_to_left" />
<item type="id" name="action_split_task_to_right" />
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 79e1fae..f5f198d 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1023,4 +1023,11 @@
<!-- How much we expand the touchable region of the status bar below the notch to catch touches
that just start below the notch. -->
<dimen name="display_cutout_touchable_region_size">12dp</dimen>
+
+ <!-- Padding for overheat alarm dialog message of content -->
+ <dimen name="alarm_dialog_panel_padding">24dp</dimen>
+
+ <!-- Padding for overheat alarm dialog message of content -->
+ <dimen name="alarm_dialog_message_space">28dp</dimen>
+
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 18f378e..114fbe4 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2067,6 +2067,14 @@
<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>
+ <!-- Title for alarm dialog alerting user the usb adapter has reached a certain temperature that should disconnect charging cable immediately. [CHAR LIMIT=30] -->
+ <string name="high_temp_alarm_title">Unplug charger</string>
+ <!-- Text body for dialog alerting user the usb adapter has reached a certain temperature that should disconnect charging cable immediately. [CHAR LIMIT=300] -->
+ <string name="high_temp_alarm_notify_message">There\u2019s an issue charging this device. Unplug the power adapter and take care as the cable may be warm.</string>
+ <!-- Text link for user to see more detail about overheat alarm. [CHAR LIMIT=300] -->
+ <string name="high_temp_alarm_help_care_steps">See care steps</string>
+ <!-- Help link of context for usb overheat web page -->
+ <string name="high_temp_alarm_help_url" translatable="false">help_uri_usb_warm</string>
<!-- SysUI Tuner: Button to select lock screen shortcut [CHAR LIMIT=60] -->
<string name="lockscreen_shortcut_left">Left shortcut</string>
diff --git a/packages/SystemUI/src/com/android/systemui/power/OverheatAlarmController.java b/packages/SystemUI/src/com/android/systemui/power/OverheatAlarmController.java
new file mode 100644
index 0000000..db15909
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/power/OverheatAlarmController.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package com.android.systemui.power;
+
+import static android.content.Context.VIBRATOR_SERVICE;
+
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.media.AudioAttributes;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
+import com.android.systemui.media.NotificationPlayer;
+
+/**
+ * A Controller handle beep sound, vibration and TTS depend on state of OverheatAlarmDialog.
+ */
+public class OverheatAlarmController {
+ private static final String TAG = OverheatAlarmController.class.getSimpleName();
+
+ private static final int VIBRATION_INTERVAL = 2000;
+ private static final long[] VIBRATION_PATTERN = new long[]{0, 400, 200, 400, 200, 400, 200};
+
+ private static OverheatAlarmController sInstance;
+
+ private final Vibrator mVibrator;
+
+ private NotificationPlayer mPlayer;
+ private VibrationEffect mVibrationEffect;
+
+ private boolean mShouldVibrate;
+
+ /**
+ * The constructor only used to create singleton sInstance.
+ */
+ private OverheatAlarmController(Context context) {
+ mVibrator = (Vibrator) context.getSystemService(VIBRATOR_SERVICE);
+ }
+
+ /**
+ * Get singleton OverheatAlarmController instance.
+ */
+ public static OverheatAlarmController getInstance(Context context) {
+ if (context == null) {
+ throw new IllegalArgumentException();
+ }
+ if (sInstance == null) {
+ sInstance = new OverheatAlarmController(context);
+ }
+ return sInstance;
+ }
+
+ /**
+ * Starting alarm beep sound and vibration.
+ */
+ @VisibleForTesting
+ public void startAlarm(Context context) {
+ if (mPlayer != null) {
+ return;
+ }
+ playSound(context);
+ startVibrate();
+ }
+
+ /**
+ * Stop alarming beep sound, vibrating, and TTS if initialized.
+ */
+ @VisibleForTesting
+ public void stopAlarm() {
+ stopPlayer();
+ stopVibrate();
+ }
+
+ @VisibleForTesting
+ protected void playSound(Context context) {
+ Uri uri = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
+ .authority(context.getBasePackageName())
+ .appendPath(Integer.toString(R.raw.overheat_alarm)).build();
+
+ if (mPlayer == null) {
+ mPlayer = new NotificationPlayer(TAG);
+ }
+ mPlayer.setUsesWakeLock(context);
+ mPlayer.play(context, uri, true /* looping */, getAlertAudioAttributes());
+ }
+
+ @VisibleForTesting
+ protected void stopPlayer() {
+ if (mPlayer != null) {
+ mPlayer.stop();
+ mPlayer = null;
+ }
+ }
+
+ @VisibleForTesting
+ protected void startVibrate() {
+ mShouldVibrate = true;
+ if (mVibrationEffect == null) {
+ mVibrationEffect = VibrationEffect.createWaveform(VIBRATION_PATTERN, -1);
+ }
+ performVibrate();
+ }
+
+ @VisibleForTesting
+ protected void performVibrate() {
+ if (mShouldVibrate && mVibrator != null) {
+ mVibrator.vibrate(mVibrationEffect, getAlertAudioAttributes());
+ Handler.getMain().sendMessageDelayed(
+ obtainMessage(OverheatAlarmController::performVibrate, this),
+ VIBRATION_INTERVAL);
+ }
+ }
+
+ @VisibleForTesting
+ protected void stopVibrate() {
+ if (mVibrator != null) {
+ mVibrator.cancel();
+ }
+ mShouldVibrate = false;
+ }
+
+ /**
+ * Build AudioAttributes for mPlayer(NotificationPlayer) and vibrator
+ * Use the alarm channel so it can vibrate in DnD mode, unless alarms are
+ * specifically disabled in DnD.
+ */
+ private static AudioAttributes getAlertAudioAttributes() {
+ AudioAttributes.Builder builder = new AudioAttributes.Builder();
+ builder.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION);
+ builder.setUsage(AudioAttributes.USAGE_ALARM);
+ // Set FLAG_BYPASS_INTERRUPTION_POLICY and FLAG_BYPASS_MUTE so that it enables
+ // audio in any DnD mode, even in total silence DnD mode (requires MODIFY_PHONE_STATE).
+ builder.setFlags(
+ AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY | AudioAttributes.FLAG_BYPASS_MUTE);
+ return builder.build();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/power/OverheatAlarmDialog.java b/packages/SystemUI/src/com/android/systemui/power/OverheatAlarmDialog.java
new file mode 100644
index 0000000..1ecec51
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/power/OverheatAlarmDialog.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package com.android.systemui.power;
+
+import android.app.AlertDialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.TextView;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import com.android.systemui.R;
+
+/**
+ * The alarm dialog shown when the device overheats.
+ * When the temperature exceeds a threshold, we're showing this dialog to notify the user.
+ * Once the dialog shows, a sound and vibration will be played until the user touches the dialog.
+ */
+public class OverheatAlarmDialog extends AlertDialog {
+ private final OverheatDialogDelegate mOverheatDialogDelegate;
+ private final View mContentView, mTitleView;
+
+ private static boolean sHasUserInteracted;
+
+ private OverheatAlarmDialog.PowerEventReceiver mPowerEventReceiver;
+
+ /**
+ * OverheatAlarmDialog should appear over system panels and keyguard.
+ */
+ public OverheatAlarmDialog(Context context) {
+ super(context, R.style.Theme_SystemUI_Dialog_Alert);
+ mOverheatDialogDelegate = new OverheatDialogDelegate();
+
+ // Setup custom views, the purpose of set custom title and message is inject
+ // AccessibilityDelegate to solve beep sound and talk back mix problem
+ final LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ mContentView = inflater.inflate(R.layout.overheat_dialog_content, null);
+ mTitleView = inflater.inflate(R.layout.overheat_dialog_title, null);
+ setView(mContentView);
+ setCustomTitle(mTitleView);
+
+ setupDialog();
+ }
+
+ @Override
+ public void dismiss() {
+ sHasUserInteracted = false;
+ getContext().unregisterReceiver(mPowerEventReceiver);
+ super.dismiss();
+ }
+
+ private void setupDialog() {
+ getWindow().getAttributes().privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+ getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL);
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
+ | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+ | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+ | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+ // Register ACTION_SCREEN_OFF for power Key event.
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_SCREEN_OFF);
+ mPowerEventReceiver = new OverheatAlarmDialog.PowerEventReceiver();
+ getContext().registerReceiverAsUser(mPowerEventReceiver, UserHandle.CURRENT, filter, null,
+ null);
+ }
+
+ @Override
+ public void setTitle(CharSequence title) {
+ if (mTitleView == null) {
+ super.setTitle(title);
+ return;
+ }
+ final TextView titleTextView = mTitleView.findViewById(R.id.alertTitle);
+ if (titleTextView != null) {
+ titleTextView.setText(title);
+ titleTextView.setAccessibilityDelegate(mOverheatDialogDelegate);
+ }
+ }
+
+ @Override
+ public void setMessage(CharSequence message) {
+ if (mContentView == null) {
+ super.setMessage(message);
+ return;
+ }
+ final TextView messageView = mContentView.findViewById(android.R.id.message);
+ if (messageView != null) {
+ messageView.setAccessibilityDelegate(mOverheatDialogDelegate);
+ messageView.requestAccessibilityFocus();
+ messageView.setText(message);
+ }
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (!sHasUserInteracted) {
+ switch (event.getKeyCode()) {
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ case KeyEvent.KEYCODE_BACK:
+ notifyAlarmBeepSoundChange();
+ sHasUserInteracted = true;
+ break;
+ }
+ }
+ return super.dispatchKeyEvent(event);
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ // Stop beep sound when touch alarm dialog.
+ if (!sHasUserInteracted) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN
+ || ev.getAction() == MotionEvent.ACTION_OUTSIDE) {
+ notifyAlarmBeepSoundChange();
+ sHasUserInteracted = true;
+ }
+ }
+ return super.dispatchTouchEvent(ev);
+ }
+
+ @VisibleForTesting
+ protected void notifyAlarmBeepSoundChange() {
+ this.getContext().sendBroadcast(new Intent(Intent.ACTION_ALARM_CHANGED).setPackage(
+ this.getContext().getPackageName())
+ .setFlags(Intent.FLAG_RECEIVER_FOREGROUND));
+ }
+
+ private final class PowerEventReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!sHasUserInteracted) {
+ notifyAlarmBeepSoundChange();
+ sHasUserInteracted = true;
+ }
+ }
+ }
+
+ /**
+ * Implement AccessibilityDelegate to stop beep sound while title or message view get
+ * accessibility focus, in case the alarm beep sound mix up talk back description.
+ */
+ private final class OverheatDialogDelegate extends View.AccessibilityDelegate {
+ @Override
+ public boolean performAccessibilityAction(View host, int action, Bundle args) {
+ if (action == AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS && !sHasUserInteracted) {
+ notifyAlarmBeepSoundChange();
+ sHasUserInteracted = true;
+ }
+ return super.performAccessibilityAction(host, action, args);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 288f058..c32a443 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -16,6 +16,10 @@
package com.android.systemui.power;
+import static android.content.DialogInterface.BUTTON_NEGATIVE;
+import static android.content.DialogInterface.BUTTON_POSITIVE;
+
+import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -47,10 +51,13 @@
import com.android.settingslib.Utils;
import com.android.settingslib.fuelgauge.BatterySaverUtils;
import com.android.settingslib.utils.PowerUtil;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.util.NotificationChannels;
+import com.android.systemui.volume.Events;
import java.io.PrintWriter;
import java.text.NumberFormat;
@@ -111,6 +118,7 @@
private final Context mContext;
private final NotificationManager mNoMan;
private final PowerManager mPowerMan;
+ private final KeyguardManager mKeyguard;
private final Handler mHandler = new Handler(Looper.getMainLooper());
private final Receiver mReceiver = new Receiver();
private final Intent mOpenBatterySettings = settings(Intent.ACTION_POWER_USAGE_SUMMARY);
@@ -134,25 +142,37 @@
private boolean mHighTempWarning;
private SystemUIDialog mHighTempDialog;
private SystemUIDialog mThermalShutdownDialog;
+ @VisibleForTesting
+ protected OverheatAlarmDialog mOverheatAlarmDialog;
public PowerNotificationWarnings(Context context) {
mContext = context;
mNoMan = mContext.getSystemService(NotificationManager.class);
mPowerMan = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ mKeyguard = mContext.getSystemService(KeyguardManager.class);
mReceiver.init();
}
@Override
public void dump(PrintWriter pw) {
- pw.print("mWarning="); pw.println(mWarning);
- pw.print("mPlaySound="); pw.println(mPlaySound);
- 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("mWarning=");
+ pw.println(mWarning);
+ pw.print("mPlaySound=");
+ pw.println(mPlaySound);
+ 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("mSaverEnabledConfirmation=");
pw.println(mSaverEnabledConfirmation != null ? "not null" : null);
- pw.print("mHighTempWarning="); pw.println(mHighTempWarning);
- pw.print("mHighTempDialog="); pw.println(mHighTempDialog != null ? "not null" : null);
+ pw.print("mHighTempWarning=");
+ pw.println(mHighTempWarning);
+ pw.print("mHighTempDialog=");
+ pw.println(mHighTempDialog != null ? "not null" : null);
+ pw.print("mOverheatAlarmDialog=");
+ pw.println(mOverheatAlarmDialog != null ? "not null" : null);
pw.print("mThermalShutdownDialog=");
pw.println(mThermalShutdownDialog != null ? "not null" : null);
}
@@ -370,6 +390,81 @@
mNoMan.notifyAsUser(TAG_TEMPERATURE, SystemMessage.NOTE_HIGH_TEMP, n, UserHandle.ALL);
}
+ /**
+ * PowerUI detect thermal overheat, notify to popup alarm dialog.
+ * Alarm with beep sound, showing overheat alarm dialog until user click OK or link of help.
+ * Do not auto dismiss even temperature drop.
+ *
+ * @param overheat true if device overheat, temperature >= threshold.
+ * false if device temperature <= threshold tolerance after overheat
+ * alarmed.
+ * @param shouldBeepSound true alarm beep sound until user interactive with device
+ * false showing alarm dialog only
+ */
+ @Override
+ public void notifyHighTemperatureAlarm(boolean overheat, boolean shouldBeepSound) {
+ // Overheat and non-null dialog are XOR(exclusive or) relationship
+ if (overheat ^ (mOverheatAlarmDialog != null)) {
+ // b/120188825 Since notifyHighTemperatureAlarm() could be triggered by
+ // non-ui thread such as ThermalEventListener.notifyThrottling()
+ mHandler.post(() -> setOverheatAlarmDialogShowing(overheat));
+ setAlarmShouldSound(shouldBeepSound);
+ }
+ }
+
+ /**
+ * Showing overheat alarm dialog until user click OK button or link of help to dismiss
+ *
+ * @param shouldShow whether to show overheat alarm dialog.
+ */
+ protected void setOverheatAlarmDialogShowing(boolean shouldShow) {
+ if (shouldShow && mOverheatAlarmDialog == null) {
+ OverheatAlarmDialog d = new OverheatAlarmDialog(mContext);
+ d.setCancelable(false);
+ d.setButton(BUTTON_NEGATIVE,
+ mContext.getString(R.string.high_temp_alarm_help_care_steps),
+ (dialogInterface, i) -> {
+ final String contextString = mContext.getString(
+ R.string.high_temp_alarm_help_url);
+ final Intent helpIntent = new Intent();
+ helpIntent.setClassName("com.android.settings",
+ "com.android.settings.HelpTrampoline");
+ helpIntent.putExtra(Intent.EXTRA_TEXT, contextString);
+ Dependency.get(ActivityStarter.class).startActivity(helpIntent,
+ true /* dismissShade */, resultCode -> {
+ mOverheatAlarmDialog = null;
+ });
+ });
+ d.setButton(BUTTON_POSITIVE, mContext.getString(com.android.internal.R.string.ok),
+ (dialogInterface, i) -> mOverheatAlarmDialog = null);
+ d.setOnDismissListener(dialogInterface -> {
+ mOverheatAlarmDialog = null;
+ Events.writeEvent(mContext, Events.EVENT_DISMISS_OVERHEAT_ALARM,
+ Events.DISMISS_REASON_DONE_CLICKED,
+ mKeyguard.isKeyguardLocked());
+ });
+ d.show();
+ Events.writeEvent(mContext, Events.EVENT_SHOW_OVERHEAT_ALARM,
+ Events.SHOW_REASON_OVERHEAD_ALARM_CHANGED,
+ mKeyguard.isKeyguardLocked());
+ mOverheatAlarmDialog = d;
+ }
+ }
+
+ /**
+ * Whether to alarm beep sound when overheat dialog showing.
+ *
+ * @param shouldSound whether to alarm beep sound.
+ */
+ protected void setAlarmShouldSound(boolean shouldSound) {
+ Log.d(TAG, "setAlarmShouldSound, " + shouldSound);
+ if (shouldSound) {
+ OverheatAlarmController.getInstance(mContext).startAlarm(mContext);
+ } else {
+ OverheatAlarmController.getInstance(mContext).stopAlarm();
+ }
+ }
+
private void showHighTemperatureDialog() {
if (mHighTempDialog != null) return;
final SystemUIDialog d = new SystemUIDialog(mContext);
@@ -643,6 +738,7 @@
filter.addAction(ACTION_ENABLE_AUTO_SAVER);
filter.addAction(ACTION_AUTO_SAVER_NO_THANKS);
filter.addAction(ACTION_DISMISS_AUTO_SAVER_SUGGESTION);
+ filter.addAction(Intent.ACTION_ALARM_CHANGED);
mContext.registerReceiverAsUser(this, UserHandle.ALL, filter,
android.Manifest.permission.DEVICE_POWER, mHandler);
}
@@ -682,6 +778,8 @@
} else if (ACTION_AUTO_SAVER_NO_THANKS.equals(action)) {
dismissAutoSaverSuggestion();
BatterySaverUtils.suppressAutoBatterySaver(context);
+ } else if (Intent.ACTION_ALARM_CHANGED.equals(action)) {
+ setAlarmShouldSound(false /* mHasUserInteracted */);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 0b9067e..80ebb6e 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -54,12 +54,15 @@
import java.io.PrintWriter;
import java.time.Duration;
import java.util.Arrays;
+import java.util.Locale;
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 static final long TEMPERATURE_LOGGING_INTERVAL = DateUtils.HOUR_IN_MILLIS;
+ private static final int TEMPERATURE_OVERHEAT_WARNING = 0;
+ private static final int TEMPERATURE_OVERHEAT_ALARM = 1;
private static final int MAX_RECENT_TEMPS = 125; // TEMPERATURE_LOGGING_INTERVAL plus a buffer
static final long THREE_HOURS_IN_MILLIS = DateUtils.HOUR_IN_MILLIS * 3;
private static final int CHARGE_CYCLE_PERCENT_RESET = 45;
@@ -80,15 +83,22 @@
private Estimate mLastEstimate;
private boolean mLowWarningShownThisChargeCycle;
private boolean mSevereWarningShownThisChargeCycle;
+ private boolean mEnableTemperatureWarning;
+ private boolean mEnableTemperatureAlarm;
+ private boolean mIsOverheatAlarming;
private int mLowBatteryAlertCloseLevel;
private final int[] mLowBatteryReminderLevels = new int[2];
private long mScreenOffTime = -1;
- private float mThresholdTemp;
- private float[] mRecentTemps = new float[MAX_RECENT_TEMPS];
- private int mNumTemps;
+ private float mThresholdWarningTemp;
+ private float mThresholdAlarmTemp;
+ private float mThresholdAlarmTempTolerance;
+ private float[] mRecentSkinTemps = new float[MAX_RECENT_TEMPS];
+ private float[] mRecentAlarmTemps = new float[MAX_RECENT_TEMPS];
+ private int mWarningNumTemps;
+ private int mAlarmNumTemps;
private long mNextLogTime;
private IThermalService mThermalService;
@@ -98,7 +108,7 @@
// by using the same instance (method references are not guaranteed to be the same object
// We create a method reference here so that we are guaranteed that we can remove a callback
// each time they are created).
- private final Runnable mUpdateTempCallback = this::updateTemperatureWarning;
+ private final Runnable mUpdateTempCallback = this::updateTemperature;
public void start() {
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -126,7 +136,7 @@
// to the temperature being too high.
showThermalShutdownDialog();
- initTemperatureWarning();
+ initTemperature();
}
@Override
@@ -135,7 +145,7 @@
// Safe to modify mLastConfiguration here as it's only updated by the main thread (here).
if ((mLastConfiguration.updateFrom(newConfig) & mask) != 0) {
- mHandler.post(this::initTemperatureWarning);
+ mHandler.post(this::initTemperature);
}
}
@@ -193,6 +203,7 @@
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_USER_SWITCHED);
+ filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
mContext.registerReceiver(this, filter, null, mHandler);
}
@@ -258,6 +269,8 @@
mScreenOffTime = -1;
} else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
mWarnings.userSwitched();
+ } else if (Intent.ACTION_POWER_DISCONNECTED.equals(action)) {
+ updateTemperature();
} else {
Slog.w(TAG, "unknown intent: " + intent);
}
@@ -364,18 +377,51 @@
return canShowWarning || canShowSevereWarning;
}
- private void initTemperatureWarning() {
- ContentResolver resolver = mContext.getContentResolver();
- Resources resources = mContext.getResources();
- if (Settings.Global.getInt(resolver, Settings.Global.SHOW_TEMPERATURE_WARNING,
- resources.getInteger(R.integer.config_showTemperatureWarning)) == 0) {
+ private void initTemperature() {
+ initTemperatureWarning();
+ initTemperatureAlarm();
+ if (mEnableTemperatureWarning || mEnableTemperatureAlarm) {
+ bindThermalService();
+ }
+ }
+
+ private void initTemperatureAlarm() {
+ mEnableTemperatureAlarm = mContext.getResources().getInteger(
+ R.integer.config_showTemperatureAlarm) != 0;
+ if (!mEnableTemperatureAlarm) {
return;
}
- mThresholdTemp = Settings.Global.getFloat(resolver, Settings.Global.WARNING_TEMPERATURE,
+ float[] throttlingTemps = mHardwarePropertiesManager.getDeviceTemperatures(
+ HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
+ HardwarePropertiesManager.TEMPERATURE_THROTTLING);
+ if (throttlingTemps == null || throttlingTemps.length < TEMPERATURE_OVERHEAT_ALARM + 1) {
+ mThresholdAlarmTemp = mContext.getResources().getInteger(
+ R.integer.config_alarmTemperature);
+ } else {
+ mThresholdAlarmTemp = throttlingTemps[TEMPERATURE_OVERHEAT_ALARM];
+ }
+ mThresholdAlarmTempTolerance = mThresholdAlarmTemp - mContext.getResources().getInteger(
+ R.integer.config_alarmTemperatureTolerance);
+ Log.d(TAG, "mThresholdAlarmTemp=" + mThresholdAlarmTemp + ", mThresholdAlarmTempTolerance="
+ + mThresholdAlarmTempTolerance);
+ }
+
+ private void initTemperatureWarning() {
+ ContentResolver resolver = mContext.getContentResolver();
+ Resources resources = mContext.getResources();
+ mEnableTemperatureWarning = Settings.Global.getInt(resolver,
+ Settings.Global.SHOW_TEMPERATURE_WARNING,
+ resources.getInteger(R.integer.config_showTemperatureWarning)) != 0;
+ if (!mEnableTemperatureWarning) {
+ return;
+ }
+
+ mThresholdWarningTemp = Settings.Global.getFloat(resolver,
+ Settings.Global.WARNING_TEMPERATURE,
resources.getInteger(R.integer.config_warningTemperature));
- if (mThresholdTemp < 0f) {
+ if (mThresholdWarningTemp < 0f) {
// Get the shutdown temperature, adjust for warning tolerance.
float[] throttlingTemps = mHardwarePropertiesManager.getDeviceTemperatures(
HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
@@ -385,10 +431,12 @@
|| throttlingTemps[0] == HardwarePropertiesManager.UNDEFINED_TEMPERATURE) {
return;
}
- mThresholdTemp = throttlingTemps[0] -
- resources.getInteger(R.integer.config_warningTemperatureTolerance);
+ mThresholdWarningTemp = throttlingTemps[0] - resources.getInteger(
+ R.integer.config_warningTemperatureTolerance);
}
+ }
+ private void bindThermalService() {
if (mThermalService == null) {
// Enable push notifications of throttling from vendor thermal
// management subsystem via thermalservice, in addition to our
@@ -416,7 +464,7 @@
mHandler.removeCallbacks(mUpdateTempCallback);
// We have passed all of the checks, start checking the temp
- updateTemperatureWarning();
+ updateTemperature();
}
private void showThermalShutdownDialog() {
@@ -426,38 +474,110 @@
}
}
+ /**
+ * Update temperature depend on config, there are type types of messages by design
+ * TEMPERATURE_OVERHEAT_WARNING Send generic notification to notify user
+ * TEMPERATURE_OVERHEAT_ALARM popup emergency Dialog for user
+ */
@VisibleForTesting
- protected void updateTemperatureWarning() {
+ protected void updateTemperature() {
+ if (!mEnableTemperatureWarning && !mEnableTemperatureAlarm) {
+ return;
+ }
+
float[] temps = mHardwarePropertiesManager.getDeviceTemperatures(
HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
HardwarePropertiesManager.TEMPERATURE_CURRENT);
+ if (temps == null) {
+ Log.e(TAG, "Can't query current temperature value from HardProps SKIN type");
+ return;
+ }
+
+ final float[] temps_compat;
+ if (temps.length < TEMPERATURE_OVERHEAT_ALARM + 1) {
+ temps_compat = new float[] { temps[0], temps[0] };
+ } else {
+ temps_compat = temps;
+ }
+
+ if (mEnableTemperatureWarning) {
+ updateTemperatureWarning(temps_compat);
+ logTemperatureStats(TEMPERATURE_OVERHEAT_WARNING);
+ }
+
+ if (mEnableTemperatureAlarm) {
+ updateTemperatureAlarm(temps_compat);
+ logTemperatureStats(TEMPERATURE_OVERHEAT_ALARM);
+ }
+
+ mHandler.postDelayed(mUpdateTempCallback, TEMPERATURE_INTERVAL);
+ }
+
+ /**
+ * Update legacy overheat warning notification from skin temperatures
+ *
+ * @param temps the array include two types of value from DEVICE_TEMPERATURE_SKIN
+ * this function only obtain the value of temps[TEMPERATURE_OVERHEAT_WARNING]
+ */
+ @VisibleForTesting
+ protected void updateTemperatureWarning(float[] temps) {
if (temps.length != 0) {
- float temp = temps[0];
- mRecentTemps[mNumTemps++] = temp;
+ float temp = temps[TEMPERATURE_OVERHEAT_WARNING];
+ mRecentSkinTemps[mWarningNumTemps++] = temp;
StatusBar statusBar = getComponent(StatusBar.class);
if (statusBar != null && !statusBar.isDeviceInVrMode()
- && temp >= mThresholdTemp) {
- logAtTemperatureThreshold(temp);
+ && temp >= mThresholdWarningTemp) {
+ logAtTemperatureThreshold(TEMPERATURE_OVERHEAT_WARNING, temp,
+ mThresholdWarningTemp);
mWarnings.showHighTemperatureWarning();
} else {
mWarnings.dismissHighTemperatureWarning();
}
}
-
- logTemperatureStats();
-
- mHandler.postDelayed(mUpdateTempCallback, TEMPERATURE_INTERVAL);
}
- private void logAtTemperatureThreshold(float temp) {
+ /**
+ * Update overheat alarm from skin temperatures
+ * OEM can config alarm with beep sound by config_alarmTemperatureBeepSound
+ *
+ * @param temps the array include two types of value from DEVICE_TEMPERATURE_SKIN
+ * this function only obtain the value of temps[TEMPERATURE_OVERHEAT_ALARM]
+ */
+ @VisibleForTesting
+ protected void updateTemperatureAlarm(float[] temps) {
+ if (temps.length != 0) {
+ final float temp = temps[TEMPERATURE_OVERHEAT_ALARM];
+ final boolean shouldBeepSound = mContext.getResources().getBoolean(
+ R.bool.config_alarmTemperatureBeepSound);
+ mRecentAlarmTemps[mAlarmNumTemps++] = temp;
+ if (temp >= mThresholdAlarmTemp && !mIsOverheatAlarming) {
+ mWarnings.notifyHighTemperatureAlarm(true /* overheat */, shouldBeepSound);
+ mIsOverheatAlarming = true;
+ } else if (temp <= mThresholdAlarmTempTolerance && mIsOverheatAlarming) {
+ mWarnings.notifyHighTemperatureAlarm(false /* overheat */, false /* beepSound */);
+ mIsOverheatAlarming = false;
+ }
+ logAtTemperatureThreshold(TEMPERATURE_OVERHEAT_ALARM, temp, mThresholdAlarmTemp);
+ }
+ }
+
+ private void logAtTemperatureThreshold(int type, float temp, float thresholdTemp) {
StringBuilder sb = new StringBuilder();
sb.append("currentTemp=").append(temp)
- .append(",thresholdTemp=").append(mThresholdTemp)
+ .append(",overheatType=").append(type)
+ .append(",isOverheatAlarm=").append(mIsOverheatAlarming)
+ .append(",thresholdTemp=").append(thresholdTemp)
.append(",batteryStatus=").append(mBatteryStatus)
.append(",recentTemps=");
- for (int i = 0; i < mNumTemps; i++) {
- sb.append(mRecentTemps[i]).append(',');
+ if (type == TEMPERATURE_OVERHEAT_WARNING) {
+ for (int i = 0; i < mWarningNumTemps; i++) {
+ sb.append(mRecentSkinTemps[i]).append(',');
+ }
+ } else {
+ for (int i = 0; i < mAlarmNumTemps; i++) {
+ sb.append(mRecentAlarmTemps[i]).append(',');
+ }
}
Slog.i(TAG, sb.toString());
}
@@ -466,16 +586,20 @@
* Calculates and logs min, max, and average
* {@link HardwarePropertiesManager#DEVICE_TEMPERATURE_SKIN} over the past
* {@link #TEMPERATURE_LOGGING_INTERVAL}.
+ * @param type TEMPERATURE_OVERHEAT_WARNING Send generic notification to notify user
+ * TEMPERATURE_OVERHEAT_ALARM Popup emergency Dialog for user
*/
- private void logTemperatureStats() {
- if (mNextLogTime > System.currentTimeMillis() && mNumTemps != MAX_RECENT_TEMPS) {
+ private void logTemperatureStats(int type) {
+ int numTemp = type == TEMPERATURE_OVERHEAT_ALARM ? mAlarmNumTemps : mWarningNumTemps;
+ if (mNextLogTime > System.currentTimeMillis() && numTemp != MAX_RECENT_TEMPS) {
return;
}
-
- if (mNumTemps > 0) {
- float sum = mRecentTemps[0], min = mRecentTemps[0], max = mRecentTemps[0];
- for (int i = 1; i < mNumTemps; i++) {
- float temp = mRecentTemps[i];
+ float[] recentTemps =
+ type == TEMPERATURE_OVERHEAT_ALARM ? mRecentAlarmTemps : mRecentSkinTemps;
+ if (numTemp > 0) {
+ float sum = recentTemps[0], min = recentTemps[0], max = recentTemps[0];
+ for (int i = 1; i < numTemp; i++) {
+ float temp = recentTemps[i];
sum += temp;
if (temp > max) {
max = temp;
@@ -485,14 +609,22 @@
}
}
- float avg = sum / mNumTemps;
- Slog.i(TAG, "avg=" + avg + ",min=" + min + ",max=" + max);
- MetricsLogger.histogram(mContext, "device_skin_temp_avg", (int) avg);
- MetricsLogger.histogram(mContext, "device_skin_temp_min", (int) min);
- MetricsLogger.histogram(mContext, "device_skin_temp_max", (int) max);
+ float avg = sum / numTemp;
+ Slog.i(TAG, "Type=" + type + ",avg=" + avg + ",min=" + min + ",max=" + max);
+ String t = type == TEMPERATURE_OVERHEAT_WARNING ? "skin" : "alarm";
+ MetricsLogger.histogram(mContext,
+ String.format(Locale.ENGLISH, "device_%1$s_temp_avg", t), (int) avg);
+ MetricsLogger.histogram(mContext,
+ String.format(Locale.ENGLISH, "device_%1$s_temp_min", t), (int) min);
+ MetricsLogger.histogram(mContext,
+ String.format(Locale.ENGLISH, "device_%1$s_temp_max", t), (int) max);
}
setNextLogTime();
- mNumTemps = 0;
+ if (type == TEMPERATURE_OVERHEAT_ALARM) {
+ mAlarmNumTemps = 0;
+ } else {
+ mWarningNumTemps = 0;
+ }
}
private void setNextLogTime() {
@@ -525,8 +657,10 @@
Settings.Global.LOW_BATTERY_SOUND_TIMEOUT, 0));
pw.print("bucket: ");
pw.println(Integer.toString(findBatteryLevelBucket(mBatteryLevel)));
- pw.print("mThresholdTemp=");
- pw.println(Float.toString(mThresholdTemp));
+ pw.print("mThresholdWarningTemp=");
+ pw.println(Float.toString(mThresholdWarningTemp));
+ pw.print("mThresholdAlarmTemp=");
+ pw.println(Float.toString(mThresholdAlarmTemp));
pw.print("mNextLogTime=");
pw.println(Long.toString(mNextLogTime));
mWarnings.dump(pw);
@@ -534,18 +668,41 @@
public interface WarningsUI {
void update(int batteryLevel, int bucket, long screenOffTime);
+
void updateEstimate(Estimate estimate);
+
void updateThresholds(long lowThreshold, long severeThreshold);
+
void dismissLowBatteryWarning();
+
void showLowBatteryWarning(boolean playSound);
+
void dismissInvalidChargerWarning();
+
void showInvalidChargerWarning();
+
void updateLowBatteryWarning();
+
boolean isInvalidChargerWarningShowing();
+
void dismissHighTemperatureWarning();
+
void showHighTemperatureWarning();
+
+ /**
+ * PowerUI detect thermal overheat, notify to popup alert dialog strongly.
+ * Alarm with beep sound with un-dismissible dialog until device cool down below threshold,
+ * then popup another dismissible dialog to user.
+ *
+ * @param overheat whether device temperature over threshold
+ * @param beepSound should beep sound once overheat
+ */
+ void notifyHighTemperatureAlarm(boolean overheat, boolean beepSound);
+
void showThermalShutdownWarning();
+
void dump(PrintWriter pw);
+
void userSwitched();
}
@@ -554,9 +711,9 @@
@Override public void notifyThrottling(boolean isThrottling, Temperature temp) {
// Trigger an update of the temperature warning. Only one
// callback can be enabled at a time, so remove any existing
- // callback; updateTemperatureWarning will schedule another one.
+ // callback; updateTemperature will schedule another one.
mHandler.removeCallbacks(mUpdateTempCallback);
- updateTemperatureWarning();
+ updateTemperature();
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Events.java b/packages/SystemUI/src/com/android/systemui/volume/Events.java
index ca55e1f..96e8310 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/Events.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/Events.java
@@ -53,6 +53,8 @@
public static final int EVENT_TOUCH_LEVEL_DONE = 16; // (stream|int) (level|bool)
public static final int EVENT_ZEN_CONFIG_CHANGED = 17; // (allow/disallow|string)
public static final int EVENT_RINGER_TOGGLE = 18; // (ringer_mode)
+ public static final int EVENT_SHOW_OVERHEAT_ALARM = 19; // (reason|int) (keyguard|bool)
+ public static final int EVENT_DISMISS_OVERHEAT_ALARM = 20; // (reason|int) (keyguard|bool)
private static final String[] EVENT_TAGS = {
"show_dialog",
@@ -73,7 +75,9 @@
"mute_changed",
"touch_level_done",
"zen_mode_config_changed",
- "ringer_toggle"
+ "ringer_toggle",
+ "show_overheat_alarm",
+ "dismiss_overheat_alarm"
};
public static final int DISMISS_REASON_UNKNOWN = 0;
@@ -100,10 +104,12 @@
public static final int SHOW_REASON_UNKNOWN = 0;
public static final int SHOW_REASON_VOLUME_CHANGED = 1;
public static final int SHOW_REASON_REMOTE_VOLUME_CHANGED = 2;
+ public static final int SHOW_REASON_OVERHEAD_ALARM_CHANGED = 3;
public static final String[] SHOW_REASONS = {
"unknown",
"volume_changed",
- "remote_volume_changed"
+ "remote_volume_changed",
+ "overheat_alarm_changed"
};
public static final int ICON_STATE_UNKNOWN = 0;
@@ -181,6 +187,19 @@
case EVENT_SUPPRESSOR_CHANGED:
sb.append(list[0]).append(' ').append(list[1]);
break;
+ case EVENT_SHOW_OVERHEAT_ALARM:
+ MetricsLogger.visible(context, MetricsEvent.POWER_OVERHEAT_ALARM);
+ MetricsLogger.histogram(context, "show_overheat_alarm",
+ (Boolean) list[1] ? 1 : 0);
+ sb.append(SHOW_REASONS[(Integer) list[0]]).append(" keyguard=").append(list[1]);
+ break;
+ case EVENT_DISMISS_OVERHEAT_ALARM:
+ MetricsLogger.hidden(context, MetricsEvent.POWER_OVERHEAT_ALARM);
+ MetricsLogger.histogram(context, "dismiss_overheat_alarm",
+ (Boolean) list[1] ? 1 : 0);
+ sb.append(DISMISS_REASONS[(Integer) list[0]]).append(" keyguard=").append(
+ list[1]);
+ break;
default:
sb.append(Arrays.asList(list));
break;
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 1be8322..c40d72d 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -49,6 +49,7 @@
<uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
<uses-permission android:name="android.permission.NETWORK_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.VIBRATE" />
<application android:debuggable="true">
<uses-library android:name="android.test.runner" />
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/OverheatAlarmControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/OverheatAlarmControllerTest.java
new file mode 100644
index 0000000..651d2b7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/OverheatAlarmControllerTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package com.android.systemui.power;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class OverheatAlarmControllerTest extends SysuiTestCase{
+ OverheatAlarmController mOverheatAlarmController;
+ OverheatAlarmController mSpyOverheatAlarmController;
+
+ @Before
+ public void setUp() {
+ mOverheatAlarmController = OverheatAlarmController.getInstance(mContext);
+ mSpyOverheatAlarmController = spy(mOverheatAlarmController);
+ }
+
+ @After
+ public void tearDown() {
+ mSpyOverheatAlarmController.stopAlarm();
+ }
+
+ @Test
+ public void testGetInstance() {
+ assertThat(mOverheatAlarmController).isNotNull();
+ }
+
+ @Test
+ public void testStartAlarm_PlaySound() {
+ mSpyOverheatAlarmController.startAlarm(mContext);
+ verify(mSpyOverheatAlarmController).playSound(mContext);
+ }
+
+ @Test
+ public void testStartAlarm_InitVibrate() {
+ mSpyOverheatAlarmController.startAlarm(mContext);
+ verify(mSpyOverheatAlarmController).startVibrate();
+ }
+
+ @Test
+ public void testStartAlarm_StartVibrate() {
+ mSpyOverheatAlarmController.startAlarm(mContext);
+ verify(mSpyOverheatAlarmController).performVibrate();
+ }
+
+ @Test
+ public void testStopAlarm_StopPlayer() {
+ mSpyOverheatAlarmController.stopAlarm();
+ verify(mSpyOverheatAlarmController).stopPlayer();
+ }
+
+ @Test
+ public void testStopAlarm_StopVibrate() {
+ mSpyOverheatAlarmController.stopAlarm();
+ verify(mSpyOverheatAlarmController).stopVibrate();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/OverheatAlarmDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/OverheatAlarmDialogTest.java
new file mode 100644
index 0000000..04d3163
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/OverheatAlarmDialogTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package com.android.systemui.power;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.os.SystemClock;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.WindowManager;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper(setAsMainLooper = true)
+@SmallTest
+public class OverheatAlarmDialogTest extends SysuiTestCase {
+
+ private OverheatAlarmDialog mDialog, mSpyDialog;
+
+ @Before
+ public void setup() {
+ mDialog = new OverheatAlarmDialog(mContext);
+ mSpyDialog = spy(mDialog);
+ }
+
+ @After
+ public void tearDown() {
+ mSpyDialog = mDialog = null;
+ }
+
+ @Test
+ public void testFlagShowForAllUsers() {
+ assertThat((mDialog.getWindow().getAttributes().privateFlags
+ & WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS) != 0).isTrue();
+ }
+
+ @Test
+ public void testFlagShowWhenLocked() {
+ assertThat((mDialog.getWindow().getAttributes().flags
+ & WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED) != 0).isTrue();
+ }
+
+ @Test
+ public void testFlagTurnScreenOn() {
+ assertThat((mDialog.getWindow().getAttributes().flags
+ & WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON) != 0).isTrue();
+ }
+
+ @Test
+ public void testFlagKeepScreenOn() {
+ assertThat((mDialog.getWindow().getAttributes().flags
+ & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0).isTrue();
+ }
+
+ @Test
+ public void testTouchOutsideDialog_NotifyAlarmBeepSoundIntent_ShouldStopBeepSound() {
+ final long currentTime = SystemClock.uptimeMillis();
+ mSpyDialog.show();
+ MotionEvent ev = createMotionEvent(MotionEvent.ACTION_DOWN, currentTime, 0, 0);
+ mSpyDialog.dispatchTouchEvent(ev);
+
+ verify(mSpyDialog, atLeastOnce()).notifyAlarmBeepSoundChange();
+ mSpyDialog.dismiss();
+ }
+
+ @Test
+ public void testPressBackKey_NotifyAlarmBeepSoundIntent_ShouldStopBeepSound() {
+ mSpyDialog.show();
+ KeyEvent ev = new KeyEvent(0, 0, MotionEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK, 0,
+ 0);
+ mSpyDialog.dispatchKeyEvent(ev);
+
+ verify(mSpyDialog, atLeastOnce()).notifyAlarmBeepSoundChange();
+ mSpyDialog.dismiss();
+ }
+
+ @Test
+ public void testPressVolumeUp_NotifyAlarmBeepSoundIntent_ShouldStopBeepSound() {
+ mSpyDialog.show();
+ KeyEvent ev = new KeyEvent(0, 0, MotionEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_VOLUME_UP, 0, 0);
+ mSpyDialog.dispatchKeyEvent(ev);
+
+ verify(mSpyDialog, atLeastOnce()).notifyAlarmBeepSoundChange();
+ mSpyDialog.dismiss();
+ }
+
+ @Test
+ public void testPressVolumeDown_NotifyAlarmBeepSoundIntent_ShouldStopBeepSound() {
+ mSpyDialog.show();
+ KeyEvent ev = new KeyEvent(0, 0, MotionEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_VOLUME_DOWN, 0, 0);
+ mSpyDialog.dispatchKeyEvent(ev);
+
+ verify(mSpyDialog, atLeastOnce()).notifyAlarmBeepSoundChange();
+ mSpyDialog.dismiss();
+ }
+
+ private MotionEvent createMotionEvent(int action, long eventTime, float x, float y) {
+ return MotionEvent.obtain(0, eventTime, action, x, y, 0);
+ }
+}
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 bf6cc53..d37c285 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
@@ -16,9 +16,8 @@
package com.android.systemui.power;
-import static android.test.MoreAsserts.assertNotEqual;
+import static com.google.common.truth.Truth.assertThat;
-import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
@@ -26,6 +25,8 @@
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -38,7 +39,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.util.NotificationChannels;
-import java.util.concurrent.TimeUnit;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -51,13 +52,22 @@
public static final String FORMATTED_45M = "0h 45m";
public static final String FORMATTED_HOUR = "1h 0m";
private final NotificationManager mMockNotificationManager = mock(NotificationManager.class);
- private PowerNotificationWarnings mPowerNotificationWarnings;
+ private PowerNotificationWarnings mPowerNotificationWarnings, mSpyPowerNotificationWarnings;
@Before
public void setUp() throws Exception {
// Test Instance.
mContext.addMockSystemService(NotificationManager.class, mMockNotificationManager);
mPowerNotificationWarnings = new PowerNotificationWarnings(mContext);
+ mSpyPowerNotificationWarnings = spy(mPowerNotificationWarnings);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (mSpyPowerNotificationWarnings.mOverheatAlarmDialog != null) {
+ mSpyPowerNotificationWarnings.mOverheatAlarmDialog.dismiss();
+ mSpyPowerNotificationWarnings.mOverheatAlarmDialog = null;
+ }
}
@Test
@@ -151,4 +161,146 @@
verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(),
eq(SystemMessage.NOTE_THERMAL_SHUTDOWN), any());
}
+
+ @Test
+ public void testSetOverheatAlarmDialog_Overheat_ShouldShowing() {
+ final boolean overheat = true;
+ final boolean shouldBeepSound = false;
+ mContext.getMainThreadHandler().post(
+ () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat,
+ shouldBeepSound));
+ waitForIdleSync();
+ verify(mSpyPowerNotificationWarnings, times(1)).setOverheatAlarmDialogShowing(overheat);
+ verify(mSpyPowerNotificationWarnings, times(1)).setAlarmShouldSound(shouldBeepSound);
+ }
+
+ @Test
+ public void testSetOverheatAlarmDialog_Overheat_ShouldShowingWithBeepSound() {
+ final boolean overheat = true;
+ final boolean shouldBeepSound = true;
+ mContext.getMainThreadHandler().post(
+ () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat,
+ shouldBeepSound));
+ waitForIdleSync();
+ verify(mSpyPowerNotificationWarnings, times(1)).setOverheatAlarmDialogShowing(overheat);
+ verify(mSpyPowerNotificationWarnings, times(1)).setAlarmShouldSound(shouldBeepSound);
+ }
+
+ @Test
+ public void testSetOverheatAlarmDialog_NotOverheat_ShouldNotShowing() {
+ final boolean overheat = false;
+ final boolean shouldBeepSound = false;
+ mContext.getMainThreadHandler().post(
+ () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat,
+ shouldBeepSound));
+ waitForIdleSync();
+ verify(mSpyPowerNotificationWarnings, never()).setOverheatAlarmDialogShowing(overheat);
+ verify(mSpyPowerNotificationWarnings, never()).setAlarmShouldSound(shouldBeepSound);
+ }
+
+ @Test
+ public void testSetOverheatAlarmDialog_NotOverheat_ShouldNotAlarmBeepSound() {
+ final boolean overheat = false;
+ final boolean configBeepSound = true;
+ mContext.getMainThreadHandler().post(
+ () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat,
+ configBeepSound));
+ waitForIdleSync();
+ verify(mSpyPowerNotificationWarnings, never()).setOverheatAlarmDialogShowing(overheat);
+ verify(mSpyPowerNotificationWarnings, never()).setAlarmShouldSound(configBeepSound);
+ }
+
+ @Test
+ public void testSetAlarmShouldSound_OverheatDrop_ShouldNotSound() {
+ final boolean overheat = true;
+ final boolean shouldBeepSound = true;
+ mContext.getMainThreadHandler().post(
+ () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat,
+ shouldBeepSound));
+ waitForIdleSync();
+ // First time overheat, show overheat alarm dialog with alarm beep sound
+ verify(mSpyPowerNotificationWarnings, times(1)).setOverheatAlarmDialogShowing(overheat);
+ verify(mSpyPowerNotificationWarnings, times(1)).setAlarmShouldSound(shouldBeepSound);
+
+ // After disconnected cable or temperature drop
+ mContext.getMainThreadHandler().post(
+ () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(!overheat,
+ !shouldBeepSound));
+ waitForIdleSync();
+ verify(mSpyPowerNotificationWarnings, times(1)).setOverheatAlarmDialogShowing(!overheat);
+ verify(mSpyPowerNotificationWarnings, times(1)).setAlarmShouldSound(!shouldBeepSound);
+ }
+
+ @Test
+ public void testSetAlarmShouldSound_Overheat_Twice_ShouldShowOverheatDialogAgain() {
+ final boolean overheat = true;
+ final boolean shouldBeepSound = true;
+ // First time overheat, show mAlarmDialog and alarm beep sound
+ mContext.getMainThreadHandler().post(
+ () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat,
+ shouldBeepSound));
+ waitForIdleSync();
+ verify(mSpyPowerNotificationWarnings, times(1)).setOverheatAlarmDialogShowing(overheat);
+ verify(mSpyPowerNotificationWarnings, times(1)).setAlarmShouldSound(shouldBeepSound);
+
+ // After disconnected cable or temperature drop, stop beep sound
+ mContext.getMainThreadHandler().post(
+ () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(!overheat,
+ !shouldBeepSound));
+ waitForIdleSync();
+ verify(mSpyPowerNotificationWarnings, times(1)).setOverheatAlarmDialogShowing(!overheat);
+ verify(mSpyPowerNotificationWarnings, times(1)).setAlarmShouldSound(!shouldBeepSound);
+
+ // Overheat again, ensure the previous dialog do not auto-dismiss
+ mContext.getMainThreadHandler().post(
+ () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat,
+ shouldBeepSound));
+ waitForIdleSync();
+ verify(mSpyPowerNotificationWarnings, times(1)).setOverheatAlarmDialogShowing(overheat);
+ verify(mSpyPowerNotificationWarnings, times(1)).setAlarmShouldSound(shouldBeepSound);
+ }
+
+ @Test
+ public void testOverheatAlarmDialogShowing() {
+ final boolean overheat = true;
+ final boolean shouldBeepSound = false;
+ mContext.getMainThreadHandler().post(
+ () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat,
+ shouldBeepSound));
+ waitForIdleSync();
+ assertThat(mSpyPowerNotificationWarnings.mOverheatAlarmDialog).isNotNull();
+ }
+
+ @Test
+ public void testOverheatAlarmDialogShowingWithBeepSound() {
+ final boolean overheat = true;
+ final boolean shouldBeepSound = true;
+ mContext.getMainThreadHandler().post(
+ () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat,
+ shouldBeepSound));
+ waitForIdleSync();
+ assertThat(mSpyPowerNotificationWarnings.mOverheatAlarmDialog).isNotNull();
+ }
+
+ @Test
+ public void testOverheatAlarmDialogNotShowing() {
+ final boolean overheat = false;
+ final boolean shouldBeepSound = false;
+ mContext.getMainThreadHandler().post(
+ () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat,
+ shouldBeepSound));
+ waitForIdleSync();
+ assertThat(mSpyPowerNotificationWarnings.mOverheatAlarmDialog).isNull();
+ }
+
+ @Test
+ public void testOverheatAlarmDialogNotShowingWithBeepSound() {
+ final boolean overheat = false;
+ final boolean shouldBeepSound = true;
+ mContext.getMainThreadHandler().post(
+ () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat,
+ shouldBeepSound));
+ waitForIdleSync();
+ assertThat(mSpyPowerNotificationWarnings.mOverheatAlarmDialog).isNull();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
index a9d49f9..054bdee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -17,6 +17,7 @@
import static android.os.HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN;
import static android.os.HardwarePropertiesManager.TEMPERATURE_CURRENT;
import static android.os.HardwarePropertiesManager.TEMPERATURE_SHUTDOWN;
+import static android.os.HardwarePropertiesManager.TEMPERATURE_THROTTLING;
import static android.provider.Settings.Global.SHOW_TEMPERATURE_WARNING;
import static junit.framework.Assert.assertFalse;
@@ -69,6 +70,7 @@
private static final long ABOVE_CHARGE_CYCLE_THRESHOLD = Duration.ofHours(8).toMillis();
private static final int OLD_BATTERY_LEVEL_NINE = 9;
private static final int OLD_BATTERY_LEVEL_10 = 10;
+ private static final int DEFAULT_OVERHEAT_ALARM_THRESHOLD = 58;
private HardwarePropertiesManager mHardProps;
private WarningsUI mMockWarnings;
private PowerUI mPowerUI;
@@ -86,6 +88,7 @@
mContext.addMockSystemService(Context.HARDWARE_PROPERTIES_SERVICE, mHardProps);
mContext.addMockSystemService(Context.POWER_SERVICE, mPowerManager);
+ setUnderThreshold();
createPowerUi();
}
@@ -153,11 +156,95 @@
verify(mMockWarnings, never()).showHighTemperatureWarning();
setCurrentTemp(56); // Above threshold.
- mPowerUI.updateTemperatureWarning();
+ mPowerUI.updateTemperature();
verify(mMockWarnings).showHighTemperatureWarning();
}
@Test
+ public void testNoConfig_noAlarms() {
+ setOverThreshold();
+ final Boolean overheat = false;
+ final Boolean shouldBeepSound = false;
+ TestableResources resources = mContext.getOrCreateTestableResources();
+ resources.addOverride(R.integer.config_showTemperatureWarning, 0);
+ resources.addOverride(R.integer.config_alarmTemperature, 55);
+ resources.addOverride(R.bool.config_alarmTemperatureBeepSound, shouldBeepSound);
+
+ mPowerUI.start();
+ verify(mMockWarnings, never()).notifyHighTemperatureAlarm(overheat, shouldBeepSound);
+ }
+
+ @Test
+ public void testConfig_noAlarms() {
+ setUnderThreshold();
+ final Boolean overheat = false;
+ final Boolean shouldBeepSound = false;
+ TestableResources resources = mContext.getOrCreateTestableResources();
+ resources.addOverride(R.integer.config_showTemperatureAlarm, 1);
+ resources.addOverride(R.integer.config_alarmTemperature, 58);
+ resources.addOverride(R.bool.config_alarmTemperatureBeepSound, shouldBeepSound);
+
+ mPowerUI.start();
+ verify(mMockWarnings, never()).notifyHighTemperatureAlarm(overheat, shouldBeepSound);
+ }
+
+ @Test
+ public void testConfig_alarms() {
+ setOverThreshold();
+ final Boolean overheat = true;
+ final Boolean shouldBeepSound = false;
+ TestableResources resources = mContext.getOrCreateTestableResources();
+ resources.addOverride(R.integer.config_showTemperatureAlarm, 1);
+ resources.addOverride(R.integer.config_alarmTemperature, 58);
+ resources.addOverride(R.bool.config_alarmTemperatureBeepSound, shouldBeepSound);
+
+ mPowerUI.start();
+ verify(mMockWarnings).notifyHighTemperatureAlarm(overheat, shouldBeepSound);
+ }
+
+ @Test
+ public void testConfig_alarmsWithBeepSound() {
+ setOverThreshold();
+ final Boolean overheat = true;
+ final Boolean shouldBeepSound = true;
+ TestableResources resources = mContext.getOrCreateTestableResources();
+ resources.addOverride(R.integer.config_showTemperatureAlarm, 1);
+ resources.addOverride(R.integer.config_alarmTemperature, 58);
+ resources.addOverride(R.bool.config_alarmTemperatureBeepSound, shouldBeepSound);
+
+ mPowerUI.start();
+ verify(mMockWarnings).notifyHighTemperatureAlarm(overheat, shouldBeepSound);
+ }
+
+ @Test
+ public void testHardPropsThrottlingThreshold_alarms() {
+ setThrottlingThreshold(DEFAULT_OVERHEAT_ALARM_THRESHOLD);
+ setOverThreshold();
+ final Boolean overheat = true;
+ final Boolean shouldBeepSound = false;
+ TestableResources resources = mContext.getOrCreateTestableResources();
+ resources.addOverride(R.integer.config_showTemperatureAlarm, 1);
+ resources.addOverride(R.bool.config_alarmTemperatureBeepSound, shouldBeepSound);
+
+ mPowerUI.start();
+ verify(mMockWarnings).notifyHighTemperatureAlarm(overheat, shouldBeepSound);
+ }
+
+ @Test
+ public void testHardPropsThrottlingThreshold_noAlarms() {
+ setThrottlingThreshold(DEFAULT_OVERHEAT_ALARM_THRESHOLD);
+ setUnderThreshold();
+ final Boolean overheat = false;
+ final Boolean shouldBeepSound = false;
+ TestableResources resources = mContext.getOrCreateTestableResources();
+ resources.addOverride(R.integer.config_showTemperatureAlarm, 1);
+ resources.addOverride(R.bool.config_alarmTemperatureBeepSound, shouldBeepSound);
+
+ mPowerUI.start();
+ verify(mMockWarnings, never()).notifyHighTemperatureAlarm(overheat, shouldBeepSound);
+ }
+
+ @Test
public void testShouldShowLowBatteryWarning_showHybridOnly_overrideThresholdHigh_returnsNoShow() {
when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true);
when(mEnhancedEstimates.getLowWarningThreshold())
@@ -495,7 +582,12 @@
private void setCurrentTemp(float temp) {
when(mHardProps.getDeviceTemperatures(DEVICE_TEMPERATURE_SKIN, TEMPERATURE_CURRENT))
- .thenReturn(new float[] { temp });
+ .thenReturn(new float[] { temp, temp });
+ }
+
+ private void setThrottlingThreshold(float temp) {
+ when(mHardProps.getDeviceTemperatures(DEVICE_TEMPERATURE_SKIN, TEMPERATURE_THROTTLING))
+ .thenReturn(new float[] { temp, temp });
}
private void setOverThreshold() {
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index d79d833..4ebf9aa 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -6117,6 +6117,11 @@
// OS: P
FIELD_AUTOFILL_SESSION_ID = 1456;
+ // FIELD: Device USB overheat alarm trigger.
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: P
+ POWER_OVERHEAT_ALARM = 1457;
+
// NOTIFICATION_SINCE_INTERRUPTION_MILLIS added to P
// NOTIFICATION_INTERRUPTION added to P