Merge "Introduce FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE" into udc-dev
This commit is contained in:
@@ -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. -->
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user