Merge "Update supported states when device has critical thermal status"
This commit is contained in:
@@ -72,12 +72,19 @@ public final class DeviceState {
|
||||
*/
|
||||
public static final int FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP = 1 << 3;
|
||||
|
||||
/**
|
||||
* This flag indicates that the corresponding state should be disabled when the device is
|
||||
* overheating and reaching the critical status.
|
||||
*/
|
||||
public static final int FLAG_DISABLE_WHEN_THERMAL_STATUS_CRITICAL = 1 << 4;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(prefix = {"FLAG_"}, flag = true, value = {
|
||||
FLAG_CANCEL_OVERRIDE_REQUESTS,
|
||||
FLAG_APP_INACCESSIBLE,
|
||||
FLAG_EMULATED_ONLY,
|
||||
FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP
|
||||
FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP,
|
||||
FLAG_DISABLE_WHEN_THERMAL_STATUS_CRITICAL
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface DeviceStateFlags {}
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.os.Environment;
|
||||
import android.os.PowerManager;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Slog;
|
||||
@@ -80,7 +81,8 @@ import javax.xml.datatype.DatatypeConfigurationException;
|
||||
* provided.
|
||||
*/
|
||||
public final class DeviceStateProviderImpl implements DeviceStateProvider,
|
||||
InputManagerInternal.LidSwitchCallback, SensorEventListener {
|
||||
InputManagerInternal.LidSwitchCallback, SensorEventListener,
|
||||
PowerManager.OnThermalStatusChangedListener {
|
||||
private static final String TAG = "DeviceStateProviderImpl";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
@@ -99,6 +101,8 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider,
|
||||
private static final String FLAG_EMULATED_ONLY = "FLAG_EMULATED_ONLY";
|
||||
private static final String FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP =
|
||||
"FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP";
|
||||
private static final String FLAG_DISABLE_WHEN_THERMAL_STATUS_CRITICAL =
|
||||
"FLAG_DISABLE_WHEN_THERMAL_STATUS_CRITICAL";
|
||||
|
||||
/** Interface that allows reading the device state configuration. */
|
||||
interface ReadableConfig {
|
||||
@@ -158,6 +162,9 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider,
|
||||
case FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP:
|
||||
flags |= DeviceState.FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP;
|
||||
break;
|
||||
case FLAG_DISABLE_WHEN_THERMAL_STATUS_CRITICAL:
|
||||
flags |= DeviceState.FLAG_DISABLE_WHEN_THERMAL_STATUS_CRITICAL;
|
||||
break;
|
||||
default:
|
||||
Slog.w(TAG, "Parsed unknown flag with name: "
|
||||
+ configFlagString);
|
||||
@@ -200,6 +207,8 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider,
|
||||
private Boolean mIsLidOpen;
|
||||
@GuardedBy("mLock")
|
||||
private final Map<Sensor, SensorEvent> mLatestSensorEvent = new ArrayMap<>();
|
||||
@GuardedBy("mLock")
|
||||
private @PowerManager.ThermalStatus int mThermalStatus = PowerManager.THERMAL_STATUS_NONE;
|
||||
|
||||
private DeviceStateProviderImpl(@NonNull Context context,
|
||||
@NonNull List<DeviceState> deviceStates,
|
||||
@@ -214,6 +223,16 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider,
|
||||
mOrderedStates = orderedStates;
|
||||
|
||||
setStateConditions(deviceStates, stateConditions);
|
||||
|
||||
// If any of the device states are thermal sensitive, i.e. it should be disabled when the
|
||||
// device is overheating, then we will update the list of supported states when thermal
|
||||
// status changes.
|
||||
if (hasThermalSensitiveState(deviceStates)) {
|
||||
PowerManager powerManager = context.getSystemService(PowerManager.class);
|
||||
if (powerManager != null) {
|
||||
powerManager.addThermalStatusListener(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setStateConditions(@NonNull List<DeviceState> deviceStates,
|
||||
@@ -353,16 +372,25 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider,
|
||||
|
||||
/** Notifies the listener that the set of supported device states has changed. */
|
||||
private void notifySupportedStatesChanged() {
|
||||
DeviceState[] supportedStates;
|
||||
List<DeviceState> supportedStates = new ArrayList<>();
|
||||
Listener listener;
|
||||
synchronized (mLock) {
|
||||
if (mListener == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
supportedStates = Arrays.copyOf(mOrderedStates, mOrderedStates.length);
|
||||
listener = mListener;
|
||||
for (DeviceState deviceState : mOrderedStates) {
|
||||
if (isThermalStatusCriticalOrAbove(mThermalStatus)
|
||||
&& deviceState.hasFlag(
|
||||
DeviceState.FLAG_DISABLE_WHEN_THERMAL_STATUS_CRITICAL)) {
|
||||
continue;
|
||||
}
|
||||
supportedStates.add(deviceState);
|
||||
}
|
||||
}
|
||||
|
||||
mListener.onSupportedDeviceStatesChanged(supportedStates);
|
||||
listener.onSupportedDeviceStatesChanged(
|
||||
supportedStates.toArray(new DeviceState[supportedStates.size()]));
|
||||
}
|
||||
|
||||
/** Computes the current device state and notifies the listener of a change, if needed. */
|
||||
@@ -645,4 +673,43 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider,
|
||||
return new FileInputStream(mFile);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onThermalStatusChanged(@PowerManager.ThermalStatus int thermalStatus) {
|
||||
int previousThermalStatus;
|
||||
synchronized (mLock) {
|
||||
previousThermalStatus = mThermalStatus;
|
||||
mThermalStatus = thermalStatus;
|
||||
}
|
||||
|
||||
boolean isThermalStatusCriticalOrAbove = isThermalStatusCriticalOrAbove(thermalStatus);
|
||||
boolean isPreviousThermalStatusCriticalOrAbove =
|
||||
isThermalStatusCriticalOrAbove(previousThermalStatus);
|
||||
if (isThermalStatusCriticalOrAbove != isPreviousThermalStatusCriticalOrAbove) {
|
||||
Slog.i(TAG, "Updating supported device states due to thermal status change."
|
||||
+ " isThermalStatusCriticalOrAbove: " + isThermalStatusCriticalOrAbove);
|
||||
notifySupportedStatesChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isThermalStatusCriticalOrAbove(
|
||||
@PowerManager.ThermalStatus int thermalStatus) {
|
||||
switch (thermalStatus) {
|
||||
case PowerManager.THERMAL_STATUS_CRITICAL:
|
||||
case PowerManager.THERMAL_STATUS_EMERGENCY:
|
||||
case PowerManager.THERMAL_STATUS_SHUTDOWN:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasThermalSensitiveState(List<DeviceState> deviceStates) {
|
||||
for (DeviceState state : deviceStates) {
|
||||
if (state.hasFlag(DeviceState.FLAG_DISABLE_WHEN_THERMAL_STATUS_CRITICAL)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import android.content.Context;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorManager;
|
||||
import android.os.PowerManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
@@ -312,6 +313,14 @@ public final class DeviceStateProviderImplTest {
|
||||
+ " </sensor>\n"
|
||||
+ " </conditions>\n"
|
||||
+ " </device-state>\n"
|
||||
+ " <device-state>\n"
|
||||
+ " <identifier>4</identifier>\n"
|
||||
+ " <name>THERMAL_TEST</name>\n"
|
||||
+ " <flags>\n"
|
||||
+ " <flag>FLAG_EMULATED_ONLY</flag>\n"
|
||||
+ " <flag>FLAG_DISABLE_WHEN_THERMAL_STATUS_CRITICAL</flag>\n"
|
||||
+ " </flags>\n"
|
||||
+ " </device-state>\n"
|
||||
+ "</device-state-config>\n";
|
||||
DeviceStateProviderImpl.ReadableConfig config = new TestReadableConfig(configString);
|
||||
return DeviceStateProviderImpl.createFromConfig(mContext,
|
||||
@@ -332,7 +341,10 @@ public final class DeviceStateProviderImplTest {
|
||||
new DeviceState[]{
|
||||
new DeviceState(1, "CLOSED", 0 /* flags */),
|
||||
new DeviceState(2, "HALF_OPENED", 0 /* flags */),
|
||||
new DeviceState(3, "OPENED", 0 /* flags */) },
|
||||
new DeviceState(3, "OPENED", 0 /* flags */),
|
||||
new DeviceState(4, "THERMAL_TEST",
|
||||
DeviceState.FLAG_EMULATED_ONLY
|
||||
| DeviceState.FLAG_DISABLE_WHEN_THERMAL_STATUS_CRITICAL) },
|
||||
mDeviceStateArrayCaptor.getValue());
|
||||
// onStateChanged() should not be called because the provider has not yet been notified of
|
||||
// the initial sensor state.
|
||||
@@ -375,6 +387,57 @@ public final class DeviceStateProviderImplTest {
|
||||
assertEquals(1, mIntegerCaptor.getValue().intValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_flagDisableWhenThermalStatusCritical() throws Exception {
|
||||
Sensor sensor = newSensor("sensor", Sensor.STRING_TYPE_HINGE_ANGLE);
|
||||
when(mSensorManager.getSensorList(anyInt())).thenReturn(List.of(sensor));
|
||||
DeviceStateProviderImpl provider = create_sensorBasedProvider(sensor);
|
||||
|
||||
provider.onThermalStatusChanged(PowerManager.THERMAL_STATUS_LIGHT);
|
||||
DeviceStateProvider.Listener listener = mock(DeviceStateProvider.Listener.class);
|
||||
provider.setListener(listener);
|
||||
|
||||
verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
|
||||
assertArrayEquals(
|
||||
new DeviceState[]{
|
||||
new DeviceState(1, "CLOSED", 0 /* flags */),
|
||||
new DeviceState(2, "HALF_OPENED", 0 /* flags */),
|
||||
new DeviceState(3, "OPENED", 0 /* flags */),
|
||||
new DeviceState(4, "THERMAL_TEST",
|
||||
DeviceState.FLAG_EMULATED_ONLY
|
||||
| DeviceState.FLAG_DISABLE_WHEN_THERMAL_STATUS_CRITICAL) },
|
||||
mDeviceStateArrayCaptor.getValue());
|
||||
Mockito.clearInvocations(listener);
|
||||
|
||||
provider.onThermalStatusChanged(PowerManager.THERMAL_STATUS_MODERATE);
|
||||
verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
|
||||
Mockito.clearInvocations(listener);
|
||||
|
||||
// The THERMAL_TEST state should be disabled.
|
||||
provider.onThermalStatusChanged(PowerManager.THERMAL_STATUS_CRITICAL);
|
||||
verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
|
||||
assertArrayEquals(
|
||||
new DeviceState[]{
|
||||
new DeviceState(1, "CLOSED", 0 /* flags */),
|
||||
new DeviceState(2, "HALF_OPENED", 0 /* flags */),
|
||||
new DeviceState(3, "OPENED", 0 /* flags */) },
|
||||
mDeviceStateArrayCaptor.getValue());
|
||||
Mockito.clearInvocations(listener);
|
||||
|
||||
// The THERMAL_TEST state should be re-enabled.
|
||||
provider.onThermalStatusChanged(PowerManager.THERMAL_STATUS_LIGHT);
|
||||
verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
|
||||
assertArrayEquals(
|
||||
new DeviceState[]{
|
||||
new DeviceState(1, "CLOSED", 0 /* flags */),
|
||||
new DeviceState(2, "HALF_OPENED", 0 /* flags */),
|
||||
new DeviceState(3, "OPENED", 0 /* flags */),
|
||||
new DeviceState(4, "THERMAL_TEST",
|
||||
DeviceState.FLAG_EMULATED_ONLY
|
||||
| DeviceState.FLAG_DISABLE_WHEN_THERMAL_STATUS_CRITICAL) },
|
||||
mDeviceStateArrayCaptor.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_invalidSensorValues() throws Exception {
|
||||
// onStateChanged() should not be triggered by invalid sensor values.
|
||||
|
||||
Reference in New Issue
Block a user