Merge "Introduce FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE" into udc-dev

This commit is contained in:
Jiaming Liu
2023-03-15 21:03:48 +00:00
committed by Android (Google) Code Review
11 changed files with 313 additions and 44 deletions

View File

@@ -227,6 +227,12 @@
<string-array name="device_state_notification_thermal_contents">
<item>@string/concurrent_display_notification_thermal_content</item>
</string-array>
<string-array name="device_state_notification_power_save_titles">
<item>@string/concurrent_display_notification_power_save_title</item>
</string-array>
<string-array name="device_state_notification_power_save_contents">
<item>@string/concurrent_display_notification_power_save_content</item>
</string-array>
<!-- Certificate digests for trusted apps that will be allowed to obtain the knownSigner of the
demo device provisioning permissions. -->

View File

@@ -6267,6 +6267,12 @@ ul.</string>
<string name="concurrent_display_notification_thermal_title">Device is too warm</string>
<!-- Content of concurrent display thermal notification. [CHAR LIMIT=NONE] -->
<string name="concurrent_display_notification_thermal_content">Dual Screen is unavailable because your phone is getting too warm</string>
<!-- Title of concurrent display power saver notification. [CHAR LIMIT=NONE] -->
<string name="concurrent_display_notification_power_save_title">Dual Screen is unavailable</string>
<!-- Content of concurrent display power saver notification. [CHAR LIMIT=NONE] -->
<string name="concurrent_display_notification_power_save_content">Dual Screen is unavailable because Battery Saver is on. You can turn this off in Settings.</string>
<!-- Text of power saver notification settings button. [CHAR LIMIT=NONE] -->
<string name="device_state_notification_settings_button">Go to Settings</string>
<!-- Text of device state notification turn off button. [CHAR LIMIT=NONE] -->
<string name="device_state_notification_turn_off_button">Turn off</string>

View File

@@ -4931,12 +4931,17 @@
<java-symbol type="array" name="device_state_notification_active_contents"/>
<java-symbol type="array" name="device_state_notification_thermal_titles"/>
<java-symbol type="array" name="device_state_notification_thermal_contents"/>
<java-symbol type="array" name="device_state_notification_power_save_titles"/>
<java-symbol type="array" name="device_state_notification_power_save_contents"/>
<java-symbol type="string" name="concurrent_display_notification_name"/>
<java-symbol type="string" name="concurrent_display_notification_active_title"/>
<java-symbol type="string" name="concurrent_display_notification_active_content"/>
<java-symbol type="string" name="concurrent_display_notification_thermal_title"/>
<java-symbol type="string" name="concurrent_display_notification_thermal_content"/>
<java-symbol type="string" name="concurrent_display_notification_power_save_title"/>
<java-symbol type="string" name="concurrent_display_notification_power_save_content"/>
<java-symbol type="string" name="device_state_notification_turn_off_button"/>
<java-symbol type="string" name="device_state_notification_settings_button"/>
<java-symbol type="bool" name="config_independentLockscreenLiveWallpaper"/>
<java-symbol type="integer" name="config_deviceStateConcurrentRearDisplay" />
<java-symbol type="string" name="config_rearDisplayPhysicalAddress" />

View File

@@ -76,7 +76,13 @@ public final class DeviceState {
* 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;
public static final int FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL = 1 << 4;
/**
* This flag indicates that the corresponding state should be disabled when power save mode
* is enabled.
*/
public static final int FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE = 1 << 5;
/** @hide */
@IntDef(prefix = {"FLAG_"}, flag = true, value = {
@@ -84,7 +90,8 @@ public final class DeviceState {
FLAG_APP_INACCESSIBLE,
FLAG_EMULATED_ONLY,
FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP,
FLAG_DISABLE_WHEN_THERMAL_STATUS_CRITICAL
FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL,
FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE
})
@Retention(RetentionPolicy.SOURCE)
public @interface DeviceStateFlags {}

View File

@@ -25,6 +25,7 @@ import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STA
import static com.android.server.devicestate.DeviceState.FLAG_CANCEL_OVERRIDE_REQUESTS;
import static com.android.server.devicestate.OverrideRequest.OVERRIDE_REQUEST_TYPE_BASE_STATE;
import static com.android.server.devicestate.OverrideRequest.OVERRIDE_REQUEST_TYPE_EMULATED_STATE;
import static com.android.server.devicestate.OverrideRequestController.FLAG_POWER_SAVE_ENABLED;
import static com.android.server.devicestate.OverrideRequestController.FLAG_THERMAL_CRITICAL;
import static com.android.server.devicestate.OverrideRequestController.STATUS_ACTIVE;
import static com.android.server.devicestate.OverrideRequestController.STATUS_CANCELED;
@@ -609,7 +610,8 @@ public final class DeviceStateManagerService extends SystemService {
@GuardedBy("mLock")
private void onOverrideRequestStatusChangedLocked(@NonNull OverrideRequest request,
@OverrideRequestController.RequestStatus int status, int flags) {
@OverrideRequestController.RequestStatus int status,
@OverrideRequestController.StatusChangedFlag int flags) {
if (request.getRequestType() == OVERRIDE_REQUEST_TYPE_BASE_STATE) {
switch (status) {
case STATUS_ACTIVE:
@@ -641,6 +643,10 @@ public final class DeviceStateManagerService extends SystemService {
mDeviceStateNotificationController
.showThermalCriticalNotificationIfNeeded(
request.getRequestedState());
} else if ((flags & FLAG_POWER_SAVE_ENABLED) == FLAG_POWER_SAVE_ENABLED) {
mDeviceStateNotificationController
.showPowerSaveNotificationIfNeeded(
request.getRequestedState());
}
}
break;

View File

@@ -16,6 +16,8 @@
package com.android.server.devicestate;
import static android.provider.Settings.ACTION_BATTERY_SAVER_SETTINGS;
import android.annotation.DrawableRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -101,10 +103,16 @@ class DeviceStateNotificationController extends BroadcastReceiver {
}
String requesterApplicationLabel = getApplicationLabel(requestingAppUid);
if (requesterApplicationLabel != null) {
final Intent intent = new Intent(INTENT_ACTION_CANCEL_STATE)
.setPackage(mContext.getPackageName());
final PendingIntent pendingIntent = PendingIntent.getBroadcast(
mContext, 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE);
showNotification(
info.name, info.activeNotificationTitle,
String.format(info.activeNotificationContent, requesterApplicationLabel),
true /* ongoing */, R.drawable.ic_dual_screen
true /* ongoing */, R.drawable.ic_dual_screen,
pendingIntent,
mContext.getString(R.string.device_state_notification_turn_off_button)
);
} else {
Slog.e(TAG, "Cannot determine the requesting app name when showing state active "
@@ -126,7 +134,33 @@ class DeviceStateNotificationController extends BroadcastReceiver {
showNotification(
info.name, info.thermalCriticalNotificationTitle,
info.thermalCriticalNotificationContent, false /* ongoing */,
R.drawable.ic_thermostat
R.drawable.ic_thermostat,
null /* pendingIntent */,
null /* actionText */
);
}
/**
* Displays the notification indicating that the device state is canceled due to power
* save mode being enabled. Does nothing if the state does not have a power save mode
* notification.
*
* @param state the identifier of the device state being canceled.
*/
void showPowerSaveNotificationIfNeeded(int state) {
NotificationInfo info = mNotificationInfos.get(state);
if (info == null || !info.hasPowerSaveModeNotification()) {
return;
}
final Intent intent = new Intent(ACTION_BATTERY_SAVER_SETTINGS);
final PendingIntent pendingIntent = PendingIntent.getActivity(
mContext, 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE);
showNotification(
info.name, info.powerSaveModeNotificationTitle,
info.powerSaveModeNotificationContent, false /* ongoing */,
R.drawable.ic_thermostat,
pendingIntent,
mContext.getString(R.string.device_state_notification_settings_button)
);
}
@@ -161,7 +195,8 @@ class DeviceStateNotificationController extends BroadcastReceiver {
*/
private void showNotification(
@NonNull String name, @NonNull String title, @NonNull String content, boolean ongoing,
@DrawableRes int iconRes) {
@DrawableRes int iconRes,
@Nullable PendingIntent pendingIntent, @Nullable String actionText) {
final NotificationChannel channel = new NotificationChannel(
CHANNEL_ID, name, NotificationManager.IMPORTANCE_HIGH);
final Notification.Builder builder = new Notification.Builder(mContext, CHANNEL_ID)
@@ -173,14 +208,10 @@ class DeviceStateNotificationController extends BroadcastReceiver {
.setOngoing(ongoing)
.setCategory(Notification.CATEGORY_SYSTEM);
if (ongoing) {
final Intent intent = new Intent(INTENT_ACTION_CANCEL_STATE)
.setPackage(mContext.getPackageName());
final PendingIntent pendingIntent = PendingIntent.getBroadcast(
mContext, 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE);
if (pendingIntent != null && actionText != null) {
final Notification.Action action = new Notification.Action.Builder(
null /* icon */,
mContext.getString(R.string.device_state_notification_turn_off_button),
actionText,
pendingIntent)
.build();
builder.addAction(action);
@@ -215,12 +246,21 @@ class DeviceStateNotificationController extends BroadcastReceiver {
final String[] thermalCriticalNotificationContents =
context.getResources().getStringArray(
R.array.device_state_notification_thermal_contents);
final String[] powerSaveModeNotificationTitles =
context.getResources().getStringArray(
R.array.device_state_notification_power_save_titles);
final String[] powerSaveModeNotificationContents =
context.getResources().getStringArray(
R.array.device_state_notification_power_save_contents);
if (stateIdentifiers.length != names.length
|| stateIdentifiers.length != activeNotificationTitles.length
|| stateIdentifiers.length != activeNotificationContents.length
|| stateIdentifiers.length != thermalCriticalNotificationTitles.length
|| stateIdentifiers.length != thermalCriticalNotificationContents.length
|| stateIdentifiers.length != powerSaveModeNotificationTitles.length
|| stateIdentifiers.length != powerSaveModeNotificationContents.length
) {
throw new IllegalStateException(
"The length of state identifiers and notification texts must match!");
@@ -237,7 +277,9 @@ class DeviceStateNotificationController extends BroadcastReceiver {
new NotificationInfo(
names[i], activeNotificationTitles[i], activeNotificationContents[i],
thermalCriticalNotificationTitles[i],
thermalCriticalNotificationContents[i])
thermalCriticalNotificationContents[i],
powerSaveModeNotificationTitles[i],
powerSaveModeNotificationContents[i])
);
}
@@ -272,16 +314,21 @@ class DeviceStateNotificationController extends BroadcastReceiver {
public final String activeNotificationContent;
public final String thermalCriticalNotificationTitle;
public final String thermalCriticalNotificationContent;
public final String powerSaveModeNotificationTitle;
public final String powerSaveModeNotificationContent;
NotificationInfo(String name, String activeNotificationTitle,
String activeNotificationContent, String thermalCriticalNotificationTitle,
String thermalCriticalNotificationContent) {
String thermalCriticalNotificationContent, String powerSaveModeNotificationTitle,
String powerSaveModeNotificationContent) {
this.name = name;
this.activeNotificationTitle = activeNotificationTitle;
this.activeNotificationContent = activeNotificationContent;
this.thermalCriticalNotificationTitle = thermalCriticalNotificationTitle;
this.thermalCriticalNotificationContent = thermalCriticalNotificationContent;
this.powerSaveModeNotificationTitle = powerSaveModeNotificationTitle;
this.powerSaveModeNotificationContent = powerSaveModeNotificationContent;
}
boolean hasActiveNotification() {
@@ -292,5 +339,10 @@ class DeviceStateNotificationController extends BroadcastReceiver {
return thermalCriticalNotificationTitle != null
&& thermalCriticalNotificationTitle.length() > 0;
}
boolean hasPowerSaveModeNotification() {
return powerSaveModeNotificationTitle != null
&& powerSaveModeNotificationTitle.length() > 0;
}
}
}

View File

@@ -52,11 +52,24 @@ public interface DeviceStateProvider {
*/
int SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_CRITICAL = 3;
/**
* Indicating that the supported device states have changed because power save mode was enabled.
*/
int SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_ENABLED = 4;
/**
* Indicating that the supported device states have changed because power save mode was
* disabled.
*/
int SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_DISABLED = 5;
@IntDef(prefix = { "SUPPORTED_DEVICE_STATES_CHANGED_" }, value = {
SUPPORTED_DEVICE_STATES_CHANGED_DEFAULT,
SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED,
SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_NORMAL,
SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_CRITICAL
SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_CRITICAL,
SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_ENABLED,
SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_DISABLED
})
@Retention(RetentionPolicy.SOURCE)
@interface SupportedStatesUpdatedReason {}

View File

@@ -64,6 +64,18 @@ final class OverrideRequestController {
*/
static final int FLAG_THERMAL_CRITICAL = 1 << 0;
/**
* A flag indicating that the status change was triggered by power save mode.
*/
static final int FLAG_POWER_SAVE_ENABLED = 1 << 1;
@IntDef(flag = true, prefix = {"FLAG_"}, value = {
FLAG_THERMAL_CRITICAL,
FLAG_POWER_SAVE_ENABLED
})
@Retention(RetentionPolicy.SOURCE)
@interface StatusChangedFlag {}
static String statusToString(@RequestStatus int status) {
switch (status) {
case STATUS_ACTIVE:
@@ -228,13 +240,18 @@ final class OverrideRequestController {
@DeviceStateProvider.SupportedStatesUpdatedReason int reason) {
boolean isThermalCritical =
reason == DeviceStateProvider.SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_CRITICAL;
boolean isPowerSaveEnabled =
reason == DeviceStateProvider.SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_ENABLED;
@StatusChangedFlag int flags = 0;
flags |= isThermalCritical ? FLAG_THERMAL_CRITICAL : 0;
flags |= isPowerSaveEnabled ? FLAG_POWER_SAVE_ENABLED : 0;
if (mBaseStateRequest != null && !contains(newSupportedStates,
mBaseStateRequest.getRequestedState())) {
cancelCurrentBaseStateRequestLocked(isThermalCritical ? FLAG_THERMAL_CRITICAL : 0);
cancelCurrentBaseStateRequestLocked(flags);
}
if (mRequest != null && !contains(newSupportedStates, mRequest.getRequestedState())) {
cancelCurrentRequestLocked(isThermalCritical ? FLAG_THERMAL_CRITICAL : 0);
cancelCurrentRequestLocked(flags);
}
}
@@ -255,7 +272,8 @@ final class OverrideRequestController {
cancelRequestLocked(requestToCancel, 0 /* flags */);
}
private void cancelRequestLocked(@NonNull OverrideRequest requestToCancel, int flags) {
private void cancelRequestLocked(@NonNull OverrideRequest requestToCancel,
@StatusChangedFlag int flags) {
mListener.onStatusChanged(requestToCancel, STATUS_CANCELED, flags);
}
@@ -267,7 +285,7 @@ final class OverrideRequestController {
cancelCurrentRequestLocked(0 /* flags */);
}
private void cancelCurrentRequestLocked(int flags) {
private void cancelCurrentRequestLocked(@StatusChangedFlag int flags) {
if (mRequest == null) {
Slog.w(TAG, "Attempted to cancel a null OverrideRequest");
return;
@@ -285,7 +303,7 @@ final class OverrideRequestController {
cancelCurrentBaseStateRequestLocked(0 /* flags */);
}
private void cancelCurrentBaseStateRequestLocked(int flags) {
private void cancelCurrentBaseStateRequestLocked(@StatusChangedFlag int flags) {
if (mBaseStateRequest == null) {
Slog.w(TAG, "Attempted to cancel a null OverrideRequest");
return;
@@ -312,6 +330,6 @@ final class OverrideRequestController {
* cancelled request.
*/
void onStatusChanged(@NonNull OverrideRequest request, @RequestStatus int newStatus,
int flags);
@StatusChangedFlag int flags);
}
}

View File

@@ -21,7 +21,10 @@ import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STA
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
@@ -101,8 +104,10 @@ 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";
private static final String FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL =
"FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL";
private static final String FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE =
"FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE";
/** Interface that allows reading the device state configuration. */
interface ReadableConfig {
@@ -162,9 +167,12 @@ 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;
case FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL:
flags |= DeviceState
.FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL;
break;
case FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE:
flags |= DeviceState.FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE;
default:
Slog.w(TAG, "Parsed unknown flag with name: "
+ configFlagString);
@@ -210,6 +218,9 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider,
@GuardedBy("mLock")
private @PowerManager.ThermalStatus int mThermalStatus = PowerManager.THERMAL_STATUS_NONE;
@GuardedBy("mLock")
private boolean mPowerSaveModeEnabled;
private DeviceStateProviderImpl(@NonNull Context context,
@NonNull List<DeviceState> deviceStates,
@NonNull List<Conditions> stateConditions) {
@@ -224,14 +235,32 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider,
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 powerManager = context.getSystemService(PowerManager.class);
if (powerManager != null) {
// 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.addThermalStatusListener(this);
}
// If any of the device states are power sensitive, i.e. it should be disabled when
// power save mode is enabled, then we will update the list of supported states when
// power save mode is toggled.
if (hasPowerSaveSensitiveState(deviceStates)) {
IntentFilter filter = new IntentFilter(
PowerManager.ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL);
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL.equals(
intent.getAction())) {
onPowerSaveModeChanged(powerManager.isPowerSaveMode());
}
}
};
mContext.registerReceiver(receiver, filter);
}
}
}
@@ -382,7 +411,11 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider,
for (DeviceState deviceState : mOrderedStates) {
if (isThermalStatusCriticalOrAbove(mThermalStatus)
&& deviceState.hasFlag(
DeviceState.FLAG_DISABLE_WHEN_THERMAL_STATUS_CRITICAL)) {
DeviceState.FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL)) {
continue;
}
if (mPowerSaveModeEnabled && deviceState.hasFlag(
DeviceState.FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE)) {
continue;
}
supportedStates.add(deviceState);
@@ -674,6 +707,18 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider,
}
}
@VisibleForTesting
void onPowerSaveModeChanged(boolean isPowerSaveModeEnabled) {
synchronized (mLock) {
if (mPowerSaveModeEnabled != isPowerSaveModeEnabled) {
mPowerSaveModeEnabled = isPowerSaveModeEnabled;
notifySupportedStatesChanged(
isPowerSaveModeEnabled ? SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_ENABLED
: SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_DISABLED);
}
}
}
@Override
public void onThermalStatusChanged(@PowerManager.ThermalStatus int thermalStatus) {
int previousThermalStatus;
@@ -709,7 +754,16 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider,
private static boolean hasThermalSensitiveState(List<DeviceState> deviceStates) {
for (DeviceState state : deviceStates) {
if (state.hasFlag(DeviceState.FLAG_DISABLE_WHEN_THERMAL_STATUS_CRITICAL)) {
if (state.hasFlag(DeviceState.FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL)) {
return true;
}
}
return false;
}
private static boolean hasPowerSaveSensitiveState(List<DeviceState> deviceStates) {
for (int i = 0; i < deviceStates.size(); i++) {
if (deviceStates.get(i).hasFlag(DeviceState.FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE)) {
return true;
}
}

View File

@@ -52,7 +52,7 @@ public class DeviceStateNotificationControllerTest {
private static final int STATE_WITHOUT_NOTIFICATION = 1;
private static final int STATE_WITH_ACTIVE_NOTIFICATION = 2;
private static final int STATE_WITH_ACTIVE_AND_THERMAL_NOTIFICATION = 3;
private static final int STATE_WITH_ALL_NOTIFICATION = 3;
private static final int VALID_APP_UID = 1000;
private static final int INVALID_APP_UID = 2000;
@@ -68,6 +68,8 @@ public class DeviceStateNotificationControllerTest {
private static final String CONTENT_2 = "content2:%1$s";
private static final String THERMAL_TITLE_2 = "thermal_title2";
private static final String THERMAL_CONTENT_2 = "thermal_content2";
private static final String POWER_SAVE_TITLE_2 = "power_save_title2";
private static final String POWER_SAVE_CONTENT_2 = "power_save_content2";
private DeviceStateNotificationController mController;
@@ -88,11 +90,12 @@ public class DeviceStateNotificationControllerTest {
notificationInfos.put(STATE_WITH_ACTIVE_NOTIFICATION,
new DeviceStateNotificationController.NotificationInfo(
NAME_1, TITLE_1, CONTENT_1,
"", ""));
notificationInfos.put(STATE_WITH_ACTIVE_AND_THERMAL_NOTIFICATION,
"", "", "", ""));
notificationInfos.put(STATE_WITH_ALL_NOTIFICATION,
new DeviceStateNotificationController.NotificationInfo(
NAME_2, TITLE_2, CONTENT_2,
THERMAL_TITLE_2, THERMAL_CONTENT_2));
THERMAL_TITLE_2, THERMAL_CONTENT_2,
POWER_SAVE_TITLE_2, POWER_SAVE_CONTENT_2));
when(packageManager.getNameForUid(VALID_APP_UID)).thenReturn(VALID_APP_NAME);
when(packageManager.getNameForUid(INVALID_APP_UID)).thenReturn(INVALID_APP_NAME);
@@ -138,11 +141,47 @@ public class DeviceStateNotificationControllerTest {
DeviceStateNotificationController.NOTIFICATION_ID);
}
@Test
public void test_powerSaveNotification() {
// Verify that the active notification is created.
mController.showStateActiveNotificationIfNeeded(
STATE_WITH_ALL_NOTIFICATION, VALID_APP_UID);
verify(mNotificationManager).notify(
eq(DeviceStateNotificationController.NOTIFICATION_TAG),
eq(DeviceStateNotificationController.NOTIFICATION_ID),
mNotificationCaptor.capture());
Notification notification = mNotificationCaptor.getValue();
assertEquals(TITLE_2, notification.extras.getString(Notification.EXTRA_TITLE));
assertEquals(String.format(CONTENT_2, VALID_APP_LABEL),
notification.extras.getString(Notification.EXTRA_TEXT));
assertEquals(Notification.FLAG_ONGOING_EVENT,
notification.flags & Notification.FLAG_ONGOING_EVENT);
Mockito.clearInvocations(mNotificationManager);
// Verify that the thermal critical notification is created.
mController.showPowerSaveNotificationIfNeeded(
STATE_WITH_ALL_NOTIFICATION);
verify(mNotificationManager).notify(
eq(DeviceStateNotificationController.NOTIFICATION_TAG),
eq(DeviceStateNotificationController.NOTIFICATION_ID),
mNotificationCaptor.capture());
notification = mNotificationCaptor.getValue();
assertEquals(POWER_SAVE_TITLE_2, notification.extras.getString(Notification.EXTRA_TITLE));
assertEquals(POWER_SAVE_CONTENT_2, notification.extras.getString(Notification.EXTRA_TEXT));
assertEquals(0, notification.flags & Notification.FLAG_ONGOING_EVENT);
// Verify that the notification is canceled.
mController.cancelNotification(STATE_WITH_ALL_NOTIFICATION);
verify(mNotificationManager).cancel(
DeviceStateNotificationController.NOTIFICATION_TAG,
DeviceStateNotificationController.NOTIFICATION_ID);
}
@Test
public void test_thermalNotification() {
// Verify that the active notification is created.
mController.showStateActiveNotificationIfNeeded(
STATE_WITH_ACTIVE_AND_THERMAL_NOTIFICATION, VALID_APP_UID);
STATE_WITH_ALL_NOTIFICATION, VALID_APP_UID);
verify(mNotificationManager).notify(
eq(DeviceStateNotificationController.NOTIFICATION_TAG),
eq(DeviceStateNotificationController.NOTIFICATION_ID),
@@ -157,7 +196,7 @@ public class DeviceStateNotificationControllerTest {
// Verify that the thermal critical notification is created.
mController.showThermalCriticalNotificationIfNeeded(
STATE_WITH_ACTIVE_AND_THERMAL_NOTIFICATION);
STATE_WITH_ALL_NOTIFICATION);
verify(mNotificationManager).notify(
eq(DeviceStateNotificationController.NOTIFICATION_TAG),
eq(DeviceStateNotificationController.NOTIFICATION_ID),
@@ -168,7 +207,7 @@ public class DeviceStateNotificationControllerTest {
assertEquals(0, notification.flags & Notification.FLAG_ONGOING_EVENT);
// Verify that the notification is canceled.
mController.cancelNotification(STATE_WITH_ACTIVE_NOTIFICATION);
mController.cancelNotification(STATE_WITH_ALL_NOTIFICATION);
verify(mNotificationManager).cancel(
DeviceStateNotificationController.NOTIFICATION_TAG,
DeviceStateNotificationController.NOTIFICATION_ID);

View File

@@ -20,6 +20,8 @@ package com.android.server.policy;
import static android.content.Context.SENSOR_SERVICE;
import static com.android.server.devicestate.DeviceStateProvider.SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED;
import static com.android.server.devicestate.DeviceStateProvider.SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_DISABLED;
import static com.android.server.devicestate.DeviceStateProvider.SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_ENABLED;
import static com.android.server.devicestate.DeviceStateProvider.SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_CRITICAL;
import static com.android.server.devicestate.DeviceStateProvider.SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_NORMAL;
import static com.android.server.policy.DeviceStateProviderImpl.DEFAULT_DEVICE_STATE;
@@ -327,7 +329,8 @@ public final class DeviceStateProviderImplTest {
+ " <name>THERMAL_TEST</name>\n"
+ " <flags>\n"
+ " <flag>FLAG_EMULATED_ONLY</flag>\n"
+ " <flag>FLAG_DISABLE_WHEN_THERMAL_STATUS_CRITICAL</flag>\n"
+ " <flag>FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL</flag>\n"
+ " <flag>FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE</flag>\n"
+ " </flags>\n"
+ " </device-state>\n"
+ "</device-state-config>\n";
@@ -354,7 +357,8 @@ public final class DeviceStateProviderImplTest {
new DeviceState(3, "OPENED", 0 /* flags */),
new DeviceState(4, "THERMAL_TEST",
DeviceState.FLAG_EMULATED_ONLY
| DeviceState.FLAG_DISABLE_WHEN_THERMAL_STATUS_CRITICAL) },
| DeviceState.FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL
| DeviceState.FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE) },
mDeviceStateArrayCaptor.getValue());
// onStateChanged() should not be called because the provider has not yet been notified of
// the initial sensor state.
@@ -419,7 +423,8 @@ public final class DeviceStateProviderImplTest {
new DeviceState(3, "OPENED", 0 /* flags */),
new DeviceState(4, "THERMAL_TEST",
DeviceState.FLAG_EMULATED_ONLY
| DeviceState.FLAG_DISABLE_WHEN_THERMAL_STATUS_CRITICAL) },
| DeviceState.FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL
| DeviceState.FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE) },
mDeviceStateArrayCaptor.getValue());
Mockito.clearInvocations(listener);
@@ -451,7 +456,65 @@ public final class DeviceStateProviderImplTest {
new DeviceState(3, "OPENED", 0 /* flags */),
new DeviceState(4, "THERMAL_TEST",
DeviceState.FLAG_EMULATED_ONLY
| DeviceState.FLAG_DISABLE_WHEN_THERMAL_STATUS_CRITICAL) },
| DeviceState.FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL
| DeviceState.FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE) },
mDeviceStateArrayCaptor.getValue());
}
@Test
public void test_flagDisableWhenPowerSaveEnabled() 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.onPowerSaveModeChanged(false /* isPowerSaveModeEnabled */);
DeviceStateProvider.Listener listener = mock(DeviceStateProvider.Listener.class);
provider.setListener(listener);
verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED));
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_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL
| DeviceState.FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE) },
mDeviceStateArrayCaptor.getValue());
Mockito.clearInvocations(listener);
provider.onPowerSaveModeChanged(false /* isPowerSaveModeEnabled */);
verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED));
Mockito.clearInvocations(listener);
// The THERMAL_TEST state should be disabled due to power save being enabled.
provider.onPowerSaveModeChanged(true /* isPowerSaveModeEnabled */);
verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
eq(SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_ENABLED));
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.onPowerSaveModeChanged(false /* isPowerSaveModeEnabled */);
verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
eq(SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_DISABLED));
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_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL
| DeviceState.FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE) },
mDeviceStateArrayCaptor.getValue());
}