Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 18d2704a authored by Sherry Huang's avatar Sherry Huang
Browse files

SystemUI: overheat warning enhancements and bug fixes.

1) Add support of dynamically enabling/disabling overheat warning
   upon Settings change at runtime.
2) Rename related classes, methods, and variables to improve the
   readability.
3) Fix an issue where skin overheat warning fails to show when previous
   dismissal is triggered by intent ACTION_DISMISSED_TEMP_WARNING or
   ACTION_CLICKED_TEMP_WARNING.

Test: atest SystemUITests
Test: enable/disable overheat warning via adb command and trigger the
      warning with emulated temperature.

Bug: 126326427
Bug: 129043751
Change-Id: I844f75a042651bdd433715fedfc190b8fbff0fd4
parent b99646c3
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -353,7 +353,6 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
        if (!mHighTempWarning) {
            return;
        }
        mHighTempWarning = false;
        dismissHighTemperatureWarningInternal();
    }

@@ -364,6 +363,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
     */
    private void dismissHighTemperatureWarningInternal() {
        mNoMan.cancelAsUser(TAG_TEMPERATURE, SystemMessage.NOTE_HIGH_TEMP, UserHandle.ALL);
        mHighTempWarning = false;
    }

    @Override
+99 −43
Original line number Diff line number Diff line
@@ -23,11 +23,9 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.os.BatteryManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.IThermalEventListener;
import android.os.IThermalService;
import android.os.PowerManager;
@@ -94,6 +92,9 @@ public class PowerUI extends SystemUI {
    @VisibleForTesting int mBatteryLevel = 100;
    @VisibleForTesting int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN;

    private IThermalEventListener mSkinThermalEventListener;
    private IThermalEventListener mUsbThermalEventListener;

    public void start() {
        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
        mScreenOffTime = mPowerManager.isScreenOn() ? -1 : SystemClock.elapsedRealtime();
@@ -118,7 +119,29 @@ public class PowerUI extends SystemUI {
        // to the temperature being too high.
        showThermalShutdownDialog();

        initTemperature();
        // Register an observer to configure mEnableSkinTemperatureWarning and perform the
        // registration of skin thermal event listener upon Settings change.
        resolver.registerContentObserver(
                Settings.Global.getUriFor(Settings.Global.SHOW_TEMPERATURE_WARNING),
                false /*notifyForDescendants*/,
                new ContentObserver(mHandler) {
                    @Override
                    public void onChange(boolean selfChange) {
                        doSkinThermalEventListenerRegistration();
                    }
                });
        // Register an observer to configure mEnableUsbTemperatureAlarm and perform the
        // registration of usb thermal event listener upon Settings change.
        resolver.registerContentObserver(
                Settings.Global.getUriFor(Settings.Global.SHOW_USB_TEMPERATURE_ALARM),
                false /*notifyForDescendants*/,
                new ContentObserver(mHandler) {
                    @Override
                    public void onChange(boolean selfChange) {
                        doUsbThermalEventListenerRegistration();
                    }
                });
        initThermalEventListeners();
    }

    @Override
@@ -127,7 +150,7 @@ public class PowerUI extends SystemUI {

        // Safe to modify mLastConfiguration here as it's only updated by the main thread (here).
        if ((mLastConfiguration.updateFrom(newConfig) & mask) != 0) {
            mHandler.post(this::initTemperature);
            mHandler.post(this::initThermalEventListeners);
        }
    }

@@ -441,45 +464,78 @@ public class PowerUI extends SystemUI {
                        && currentSnapshot.getBucket() > 0);
    }

    private void initTemperature() {
        ContentResolver resolver = mContext.getContentResolver();
        Resources resources = mContext.getResources();
    private void initThermalEventListeners() {
        doSkinThermalEventListenerRegistration();
        doUsbThermalEventListenerRegistration();
    }

    @VisibleForTesting
    synchronized void doSkinThermalEventListenerRegistration() {
        final boolean oldEnableSkinTemperatureWarning = mEnableSkinTemperatureWarning;
        boolean ret = false;

        mEnableSkinTemperatureWarning = Settings.Global.getInt(resolver,
        mEnableSkinTemperatureWarning = Settings.Global.getInt(mContext.getContentResolver(),
            Settings.Global.SHOW_TEMPERATURE_WARNING,
                resources.getInteger(R.integer.config_showTemperatureWarning)) != 0;
        mEnableUsbTemperatureAlarm = Settings.Global.getInt(resolver,
                Settings.Global.SHOW_USB_TEMPERATURE_ALARM,
                resources.getInteger(R.integer.config_showUsbPortAlarm)) != 0;
            mContext.getResources().getInteger(R.integer.config_showTemperatureWarning)) != 0;

        if (mEnableSkinTemperatureWarning != oldEnableSkinTemperatureWarning) {
            try {
                if (mSkinThermalEventListener == null) {
                    mSkinThermalEventListener = new SkinThermalEventListener();
                }
                if (mThermalService == null) {
            // Enable push notifications of throttling from vendor thermal
            // management subsystem via thermalservice, in addition to our
            // usual polling, to react to temperature jumps more quickly.
            IBinder b = ServiceManager.getService(Context.THERMAL_SERVICE);

            if (b != null) {
                mThermalService = IThermalService.Stub.asInterface(b);
                registerThermalEventListener();
                    mThermalService = IThermalService.Stub.asInterface(
                        ServiceManager.getService(Context.THERMAL_SERVICE));
                }
                if (mEnableSkinTemperatureWarning) {
                    ret = mThermalService.registerThermalEventListenerWithType(
                            mSkinThermalEventListener, Temperature.TYPE_SKIN);
                } else {
                Slog.w(TAG, "cannot find thermalservice, no throttling push notifications");
                    ret = mThermalService.unregisterThermalEventListener(mSkinThermalEventListener);
                }
            } catch (RemoteException e) {
                Slog.e(TAG, "Exception while (un)registering skin thermal event listener.", e);
            }

            if (!ret) {
                mEnableSkinTemperatureWarning = !mEnableSkinTemperatureWarning;
                Slog.e(TAG, "Failed to register or unregister skin thermal event listener.");
            }
        }
    }

    @VisibleForTesting
    void registerThermalEventListener() {
    synchronized void doUsbThermalEventListenerRegistration() {
        final boolean oldEnableUsbTemperatureAlarm = mEnableUsbTemperatureAlarm;
        boolean ret = false;

        mEnableUsbTemperatureAlarm = Settings.Global.getInt(mContext.getContentResolver(),
            Settings.Global.SHOW_USB_TEMPERATURE_ALARM,
            mContext.getResources().getInteger(R.integer.config_showUsbPortAlarm)) != 0;

        if (mEnableUsbTemperatureAlarm != oldEnableUsbTemperatureAlarm) {
            try {
            if (mEnableSkinTemperatureWarning) {
                mThermalService.registerThermalEventListenerWithType(
                        new ThermalEventSkinListener(), Temperature.TYPE_SKIN);
                if (mUsbThermalEventListener == null) {
                    mUsbThermalEventListener = new UsbThermalEventListener();
                }
                if (mThermalService == null) {
                    mThermalService = IThermalService.Stub.asInterface(
                        ServiceManager.getService(Context.THERMAL_SERVICE));
                }
                if (mEnableUsbTemperatureAlarm) {
                mThermalService.registerThermalEventListenerWithType(
                        new ThermalEventUsbListener(), Temperature.TYPE_USB_PORT);
                    ret = mThermalService.registerThermalEventListenerWithType(
                            mUsbThermalEventListener, Temperature.TYPE_USB_PORT);
                } else {
                    ret = mThermalService.unregisterThermalEventListener(mUsbThermalEventListener);
                }
            } catch (RemoteException e) {
            Slog.e(TAG, "Failed to register thermal callback.", e);
                Slog.e(TAG, "Exception while (un)registering usb thermal event listener.", e);
            }

            if (!ret) {
                mEnableUsbTemperatureAlarm = !mEnableUsbTemperatureAlarm;
                Slog.e(TAG, "Failed to register or unregister usb thermal event listener.");
            }
        }
    }

@@ -555,7 +611,7 @@ public class PowerUI extends SystemUI {
        void showHighTemperatureWarning();

        /**
         * Display USB overheat alarm
         * Display USB port overheat alarm
         */
        void showUsbHighTemperatureAlarm();

@@ -572,9 +628,9 @@ public class PowerUI extends SystemUI {
        void updateSnapshot(BatteryStateSnapshot snapshot);
    }

    // Thermal event received from thermal service manager subsystem
    // Skin thermal event received from thermal service manager subsystem
    @VisibleForTesting
    final class ThermalEventSkinListener extends IThermalEventListener.Stub {
    final class SkinThermalEventListener extends IThermalEventListener.Stub {
        @Override public void notifyThrottling(Temperature temp) {
            int status = temp.getStatus();

@@ -582,7 +638,7 @@ public class PowerUI extends SystemUI {
                StatusBar statusBar = getComponent(StatusBar.class);
                if (statusBar != null && !statusBar.isDeviceInVrMode()) {
                    mWarnings.showHighTemperatureWarning();
                    Slog.d(TAG, "ThermalEventSkinListener: notifyThrottling was called "
                    Slog.d(TAG, "SkinThermalEventListener: notifyThrottling was called "
                            + ", current skin status = " + status
                            + ", temperature = " + temp.getValue());
                }
@@ -592,15 +648,15 @@ public class PowerUI extends SystemUI {
        }
    }

    // Thermal event received from thermal service manager subsystem
    // Usb thermal event received from thermal service manager subsystem
    @VisibleForTesting
    final class ThermalEventUsbListener extends IThermalEventListener.Stub {
    final class UsbThermalEventListener extends IThermalEventListener.Stub {
        @Override public void notifyThrottling(Temperature temp) {
            int status = temp.getStatus();

            if (status >= Temperature.THROTTLING_EMERGENCY) {
                mWarnings.showUsbHighTemperatureAlarm();
                Slog.d(TAG, "ThermalEventUsbListener: notifyThrottling was called "
                Slog.d(TAG, "UsbThermalEventListener: notifyThrottling was called "
                        + ", current usb port status = " + status
                        + ", temperature = " + temp.getValue());
            }
+160 −13
Original line number Diff line number Diff line
@@ -45,15 +45,15 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.power.PowerUI.WarningsUI;
import com.android.systemui.statusbar.phone.StatusBar;

import java.time.Duration;
import java.util.concurrent.TimeUnit;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.time.Duration;
import java.util.concurrent.TimeUnit;

@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@SmallTest
@@ -77,8 +77,8 @@ public class PowerUITest extends SysuiTestCase {
    private EnhancedEstimates mEnhancedEstimates;
    @Mock private PowerManager mPowerManager;
    @Mock private IThermalService mThermalServiceMock;
    private IThermalEventListener mThermalEventUsbListener;
    private IThermalEventListener mThermalEventSkinListener;
    private IThermalEventListener mUsbThermalEventListener;
    private IThermalEventListener mSkinThermalEventListener;

    @Before
    public void setup() {
@@ -90,8 +90,8 @@ public class PowerUITest extends SysuiTestCase {
        mContext.addMockSystemService(Context.POWER_SERVICE, mPowerManager);

        createPowerUi();
        mThermalEventSkinListener = mPowerUI.new ThermalEventSkinListener();
        mThermalEventUsbListener = mPowerUI.new ThermalEventUsbListener();
        mSkinThermalEventListener = mPowerUI.new SkinThermalEventListener();
        mUsbThermalEventListener = mPowerUI.new UsbThermalEventListener();
    }

    @Test
@@ -99,7 +99,7 @@ public class PowerUITest extends SysuiTestCase {
        mPowerUI.start();

        final Temperature temp = getCriticalStatusTemp(Temperature.TYPE_SKIN, "skin1");
        mThermalEventSkinListener.notifyThrottling(temp);
        mSkinThermalEventListener.notifyThrottling(temp);

        // dismiss skin high temperature warning when throttling status is critical
        TestableLooper.get(this).processAllMessages();
@@ -112,7 +112,7 @@ public class PowerUITest extends SysuiTestCase {
        mPowerUI.start();

        final Temperature temp = getEmergencyStatusTemp(Temperature.TYPE_SKIN, "skin2");
        mThermalEventSkinListener.notifyThrottling(temp);
        mSkinThermalEventListener.notifyThrottling(temp);

        // show skin high temperature warning when throttling status is emergency
        TestableLooper.get(this).processAllMessages();
@@ -125,7 +125,7 @@ public class PowerUITest extends SysuiTestCase {
        mPowerUI.start();

        final Temperature temp = getCriticalStatusTemp(Temperature.TYPE_USB_PORT, "usb1");
        mThermalEventUsbListener.notifyThrottling(temp);
        mUsbThermalEventListener.notifyThrottling(temp);

        // not show usb high temperature alarm when throttling status is critical
        TestableLooper.get(this).processAllMessages();
@@ -137,7 +137,7 @@ public class PowerUITest extends SysuiTestCase {
        mPowerUI.start();

        final Temperature temp = getEmergencyStatusTemp(Temperature.TYPE_USB_PORT, "usb2");
        mThermalEventUsbListener.notifyThrottling(temp);
        mUsbThermalEventListener.notifyThrottling(temp);

        // show usb high temperature alarm when throttling status is emergency
        TestableLooper.get(this).processAllMessages();
@@ -151,7 +151,6 @@ public class PowerUITest extends SysuiTestCase {
        resources.addOverride(R.integer.config_showTemperatureWarning, 0);

        mPowerUI.start();
        mPowerUI.registerThermalEventListener();

        TestableLooper.get(this).processAllMessages();
        verify(mThermalServiceMock, times(1))
@@ -165,13 +164,161 @@ public class PowerUITest extends SysuiTestCase {
        resources.addOverride(R.integer.config_showUsbPortAlarm, 0);

        mPowerUI.start();
        mPowerUI.registerThermalEventListener();

        TestableLooper.get(this).processAllMessages();
        verify(mThermalServiceMock, times(1))
                .registerThermalEventListenerWithType(anyObject(), eq(Temperature.TYPE_USB_PORT));
    }

    @Test
    public void testSettingOverrideConfig_disableSkinTemperatureWarning() throws Exception {
        Settings.Global.putInt(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, 0);
        TestableResources resources = mContext.getOrCreateTestableResources();
        resources.addOverride(R.integer.config_showTemperatureWarning, 1);

        mPowerUI.start();

        TestableLooper.get(this).processAllMessages();
        verify(mThermalServiceMock, times(0))
                .registerThermalEventListenerWithType(anyObject(), eq(Temperature.TYPE_SKIN));
    }

    @Test
    public void testSettingOverrideConfig_disableUsbTemperatureAlarm() throws Exception {
        Settings.Global.putInt(mContext.getContentResolver(), SHOW_USB_TEMPERATURE_ALARM, 0);
        TestableResources resources = mContext.getOrCreateTestableResources();
        resources.addOverride(R.integer.config_showUsbPortAlarm, 1);

        mPowerUI.start();

        TestableLooper.get(this).processAllMessages();
        verify(mThermalServiceMock, times(0))
                .registerThermalEventListenerWithType(anyObject(), eq(Temperature.TYPE_USB_PORT));
    }

    @Test
    public void testThermalEventListenerRegistration_success_skinType() throws Exception {
        // Settings SHOW_TEMPERATURE_WARNING is set to 1
        Settings.Global.putInt(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, 1);

        // success registering skin thermal event listener
        when(mThermalServiceMock.registerThermalEventListenerWithType(
                anyObject(), eq(Temperature.TYPE_SKIN))).thenReturn(true);

        mPowerUI.doSkinThermalEventListenerRegistration();

        // verify registering skin thermal event listener, return true (success)
        TestableLooper.get(this).processAllMessages();
        verify(mThermalServiceMock, times(1))
                .registerThermalEventListenerWithType(anyObject(), eq(Temperature.TYPE_SKIN));

        // Settings SHOW_TEMPERATURE_WARNING is set to 0
        Settings.Global.putInt(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, 0);

        mPowerUI.doSkinThermalEventListenerRegistration();

        // verify unregistering skin thermal event listener
        TestableLooper.get(this).processAllMessages();
        verify(mThermalServiceMock, times(1)).unregisterThermalEventListener(anyObject());
    }

    @Test
    public void testThermalEventListenerRegistration_fail_skinType() throws Exception {
        // Settings SHOW_TEMPERATURE_WARNING is set to 1
        Settings.Global.putInt(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, 1);

        // fail registering skin thermal event listener
        when(mThermalServiceMock.registerThermalEventListenerWithType(
                anyObject(), eq(Temperature.TYPE_SKIN))).thenReturn(false);

        mPowerUI.doSkinThermalEventListenerRegistration();

        // verify registering skin thermal event listener, return false (fail)
        TestableLooper.get(this).processAllMessages();
        verify(mThermalServiceMock, times(1))
                .registerThermalEventListenerWithType(anyObject(), eq(Temperature.TYPE_SKIN));

        // Settings SHOW_TEMPERATURE_WARNING is set to 0
        Settings.Global.putInt(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, 0);

        mPowerUI.doSkinThermalEventListenerRegistration();

        // verify that cannot unregister listener (current state is unregistered)
        TestableLooper.get(this).processAllMessages();
        verify(mThermalServiceMock, times(0)).unregisterThermalEventListener(anyObject());

        // Settings SHOW_TEMPERATURE_WARNING is set to 1
        Settings.Global.putInt(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, 1);

        mPowerUI.doSkinThermalEventListenerRegistration();

        // verify that can register listener (current state is unregistered)
        TestableLooper.get(this).processAllMessages();
        verify(mThermalServiceMock, times(2))
                .registerThermalEventListenerWithType(anyObject(), eq(Temperature.TYPE_SKIN));
    }

    @Test
    public void testThermalEventListenerRegistration_success_usbType() throws Exception {
        // Settings SHOW_USB_TEMPERATURE_ALARM is set to 1
        Settings.Global.putInt(mContext.getContentResolver(), SHOW_USB_TEMPERATURE_ALARM, 1);

        // success registering usb thermal event listener
        when(mThermalServiceMock.registerThermalEventListenerWithType(
                anyObject(), eq(Temperature.TYPE_USB_PORT))).thenReturn(true);

        mPowerUI.doUsbThermalEventListenerRegistration();

        // verify registering usb thermal event listener, return true (success)
        TestableLooper.get(this).processAllMessages();
        verify(mThermalServiceMock, times(1))
                .registerThermalEventListenerWithType(anyObject(), eq(Temperature.TYPE_USB_PORT));

        // Settings SHOW_USB_TEMPERATURE_ALARM is set to 0
        Settings.Global.putInt(mContext.getContentResolver(), SHOW_USB_TEMPERATURE_ALARM, 0);

        // verify unregistering usb thermal event listener
        mPowerUI.doUsbThermalEventListenerRegistration();
        TestableLooper.get(this).processAllMessages();
        verify(mThermalServiceMock, times(1)).unregisterThermalEventListener(anyObject());
    }

    @Test
    public void testThermalEventListenerRegistration_fail_usbType() throws Exception {
        // Settings SHOW_USB_TEMPERATURE_ALARM is set to 1
        Settings.Global.putInt(mContext.getContentResolver(), SHOW_USB_TEMPERATURE_ALARM, 1);

        // fail registering usb thermal event listener
        when(mThermalServiceMock.registerThermalEventListenerWithType(
                anyObject(), eq(Temperature.TYPE_USB_PORT))).thenReturn(false);

        mPowerUI.doUsbThermalEventListenerRegistration();

        // verify registering usb thermal event listener, return false (fail)
        TestableLooper.get(this).processAllMessages();
        verify(mThermalServiceMock, times(1))
                .registerThermalEventListenerWithType(anyObject(), eq(Temperature.TYPE_USB_PORT));

        // Settings SHOW_USB_TEMPERATURE_ALARM is set to 0
        Settings.Global.putInt(mContext.getContentResolver(), SHOW_USB_TEMPERATURE_ALARM, 0);

        mPowerUI.doUsbThermalEventListenerRegistration();

        // verify that cannot unregister listener (current state is unregistered)
        TestableLooper.get(this).processAllMessages();
        verify(mThermalServiceMock, times(0)).unregisterThermalEventListener(anyObject());

        // Settings SHOW_USB_TEMPERATURE_ALARM is set to 1
        Settings.Global.putInt(mContext.getContentResolver(), SHOW_USB_TEMPERATURE_ALARM, 1);

        mPowerUI.doUsbThermalEventListenerRegistration();

        // verify that can register listener (current state is unregistered)
        TestableLooper.get(this).processAllMessages();
        verify(mThermalServiceMock, times(2)).registerThermalEventListenerWithType(
                anyObject(), eq(Temperature.TYPE_USB_PORT));
    }

    @Test
    public void testMaybeShowHybridWarning() {
        mPowerUI.start();