notificationInfos = new SparseArray<>();
+
+ final int[] stateIdentifiers =
+ context.getResources().getIntArray(
+ R.array.device_state_notification_state_identifiers);
+ final String[] names =
+ context.getResources().getStringArray(R.array.device_state_notification_names);
+ final String[] activeNotificationTitles =
+ context.getResources().getStringArray(
+ R.array.device_state_notification_active_titles);
+ final String[] activeNotificationContents =
+ context.getResources().getStringArray(
+ R.array.device_state_notification_active_contents);
+ final String[] thermalCriticalNotificationTitles =
+ context.getResources().getStringArray(
+ R.array.device_state_notification_thermal_titles);
+ final String[] thermalCriticalNotificationContents =
+ context.getResources().getStringArray(
+ R.array.device_state_notification_thermal_contents);
+
+ if (stateIdentifiers.length != names.length
+ || stateIdentifiers.length != activeNotificationTitles.length
+ || stateIdentifiers.length != activeNotificationContents.length
+ || stateIdentifiers.length != thermalCriticalNotificationTitles.length
+ || stateIdentifiers.length != thermalCriticalNotificationContents.length
+ ) {
+ throw new IllegalStateException(
+ "The length of state identifiers and notification texts must match!");
+ }
+
+ for (int i = 0; i < stateIdentifiers.length; i++) {
+ int identifier = stateIdentifiers[i];
+ if (identifier == DeviceStateManager.INVALID_DEVICE_STATE) {
+ continue;
+ }
+
+ notificationInfos.put(
+ identifier,
+ new NotificationInfo(
+ names[i], activeNotificationTitles[i], activeNotificationContents[i],
+ thermalCriticalNotificationTitles[i],
+ thermalCriticalNotificationContents[i])
+ );
+ }
+
+ return notificationInfos;
+ }
+
+ /**
+ * A helper function to get app name (label) using the app uid.
+ *
+ * @param uid the uid of the app.
+ * @return app name (label) if found, or null otherwise.
+ */
+ @Nullable
+ private String getApplicationLabel(int uid) {
+ String packageName = mPackageManager.getNameForUid(uid);
+ try {
+ ApplicationInfo appInfo = mPackageManager.getApplicationInfo(
+ packageName, PackageManager.ApplicationInfoFlags.of(0));
+ return appInfo.loadLabel(mPackageManager).toString();
+ } catch (PackageManager.NameNotFoundException e) {
+ return null;
+ }
+ }
+
+ /**
+ * A data class storing string resources of the notification of a device state.
+ */
+ @VisibleForTesting
+ static class NotificationInfo {
+ public final String name;
+ public final String activeNotificationTitle;
+ public final String activeNotificationContent;
+ public final String thermalCriticalNotificationTitle;
+ public final String thermalCriticalNotificationContent;
+
+ NotificationInfo(String name, String activeNotificationTitle,
+ String activeNotificationContent, String thermalCriticalNotificationTitle,
+ String thermalCriticalNotificationContent) {
+
+ this.name = name;
+ this.activeNotificationTitle = activeNotificationTitle;
+ this.activeNotificationContent = activeNotificationContent;
+ this.thermalCriticalNotificationTitle = thermalCriticalNotificationTitle;
+ this.thermalCriticalNotificationContent = thermalCriticalNotificationContent;
+ }
+
+ boolean hasActiveNotification() {
+ return activeNotificationTitle != null && activeNotificationTitle.length() > 0;
+ }
+
+ boolean hasThermalCriticalNotification() {
+ return thermalCriticalNotificationTitle != null
+ && thermalCriticalNotificationTitle.length() > 0;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateProvider.java b/services/core/java/com/android/server/devicestate/DeviceStateProvider.java
index 109bf6358e8bc..fecc13fd0d034 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateProvider.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateProvider.java
@@ -19,8 +19,12 @@ package com.android.server.devicestate;
import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE;
import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE;
+import android.annotation.IntDef;
import android.annotation.IntRange;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Responsible for providing the set of supported {@link DeviceState device states} as well as the
* current device state.
@@ -28,12 +32,42 @@ import android.annotation.IntRange;
* @see DeviceStatePolicy
*/
public interface DeviceStateProvider {
+ int SUPPORTED_DEVICE_STATES_CHANGED_DEFAULT = 0;
+
+ /**
+ * Indicating that the supported device states changed callback is trigger for initial listener
+ * registration.
+ */
+ int SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED = 1;
+
+ /**
+ * Indicating that the supported device states have changed because the thermal condition
+ * returned to normal status from critical status.
+ */
+ int SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_NORMAL = 2;
+
+ /**
+ * Indicating that the supported device states have changed because of thermal critical
+ * condition.
+ */
+ int SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_CRITICAL = 3;
+
+ @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
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface SupportedStatesUpdatedReason {}
+
/**
* Registers a listener for changes in provider state.
*
- * It is required that {@link Listener#onSupportedDeviceStatesChanged(DeviceState[])} be
- * called followed by {@link Listener#onStateChanged(int)} with the initial values on successful
- * registration of the listener.
+ * It is required that
+ * {@link Listener#onSupportedDeviceStatesChanged(DeviceState[], int)} be called followed by
+ * {@link Listener#onStateChanged(int)} with the initial values on successful registration of
+ * the listener.
*/
void setListener(Listener listener);
@@ -53,18 +87,20 @@ public interface DeviceStateProvider {
* to zero and there must always be at least one supported device state.
*
* @param newDeviceStates array of supported device states.
+ * @param reason the reason for the supported device states change.
*
* @throws IllegalArgumentException if the list of device states is empty or if one of the
* provided states contains an invalid identifier.
*/
- void onSupportedDeviceStatesChanged(DeviceState[] newDeviceStates);
+ void onSupportedDeviceStatesChanged(DeviceState[] newDeviceStates,
+ @SupportedStatesUpdatedReason int reason);
/**
* Called to notify the listener of a change in current device state. Required to be called
* once on successful registration of the listener and then once on every subsequent change
* in device state. Value must have been included in the set of supported device states
* provided in the most recent call to
- * {@link #onSupportedDeviceStatesChanged(DeviceState[])}.
+ * {@link #onSupportedDeviceStatesChanged(DeviceState[], int)}.
*
* @param identifier the identifier of the new device state.
*
diff --git a/services/core/java/com/android/server/devicestate/OverrideRequest.java b/services/core/java/com/android/server/devicestate/OverrideRequest.java
index 325e384cb8ad9..74cf184e826e4 100644
--- a/services/core/java/com/android/server/devicestate/OverrideRequest.java
+++ b/services/core/java/com/android/server/devicestate/OverrideRequest.java
@@ -31,6 +31,7 @@ import java.lang.annotation.RetentionPolicy;
final class OverrideRequest {
private final IBinder mToken;
private final int mPid;
+ private final int mUid;
private final int mRequestedState;
@DeviceStateRequest.RequestFlags
private final int mFlags;
@@ -68,10 +69,11 @@ final class OverrideRequest {
@Retention(RetentionPolicy.SOURCE)
public @interface OverrideRequestType {}
- OverrideRequest(IBinder token, int pid, int requestedState,
+ OverrideRequest(IBinder token, int pid, int uid, int requestedState,
@DeviceStateRequest.RequestFlags int flags, @OverrideRequestType int requestType) {
mToken = token;
mPid = pid;
+ mUid = uid;
mRequestedState = requestedState;
mFlags = flags;
mRequestType = requestType;
@@ -85,6 +87,10 @@ final class OverrideRequest {
return mPid;
}
+ int getUid() {
+ return mUid;
+ }
+
int getRequestedState() {
return mRequestedState;
}
diff --git a/services/core/java/com/android/server/devicestate/OverrideRequestController.java b/services/core/java/com/android/server/devicestate/OverrideRequestController.java
index e39c7324d7bda..2ed4765874f79 100644
--- a/services/core/java/com/android/server/devicestate/OverrideRequestController.java
+++ b/services/core/java/com/android/server/devicestate/OverrideRequestController.java
@@ -59,6 +59,11 @@ final class OverrideRequestController {
@Retention(RetentionPolicy.SOURCE)
@interface RequestStatus {}
+ /**
+ * A flag indicating that the status change was triggered by thermal critical status.
+ */
+ static final int FLAG_THERMAL_CRITICAL = 1 << 0;
+
static String statusToString(@RequestStatus int status) {
switch (status) {
case STATUS_ACTIVE:
@@ -106,7 +111,7 @@ final class OverrideRequestController {
void addRequest(@NonNull OverrideRequest request) {
OverrideRequest previousRequest = mRequest;
mRequest = request;
- mListener.onStatusChanged(request, STATUS_ACTIVE);
+ mListener.onStatusChanged(request, STATUS_ACTIVE, 0 /* flags */);
if (previousRequest != null) {
cancelRequestLocked(previousRequest);
@@ -116,7 +121,7 @@ final class OverrideRequestController {
void addBaseStateRequest(@NonNull OverrideRequest request) {
OverrideRequest previousRequest = mBaseStateRequest;
mBaseStateRequest = request;
- mListener.onStatusChanged(request, STATUS_ACTIVE);
+ mListener.onStatusChanged(request, STATUS_ACTIVE, 0 /* flags */);
if (previousRequest != null) {
cancelRequestLocked(previousRequest);
@@ -219,14 +224,17 @@ final class OverrideRequestController {
* Notifies the controller that the set of supported states has changed. The controller will
* notify the listener of all changes to request status as a result of this change.
*/
- void handleNewSupportedStates(int[] newSupportedStates) {
+ void handleNewSupportedStates(int[] newSupportedStates,
+ @DeviceStateProvider.SupportedStatesUpdatedReason int reason) {
+ boolean isThermalCritical =
+ reason == DeviceStateProvider.SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_CRITICAL;
if (mBaseStateRequest != null && !contains(newSupportedStates,
mBaseStateRequest.getRequestedState())) {
- cancelCurrentBaseStateRequestLocked();
+ cancelCurrentBaseStateRequestLocked(isThermalCritical ? FLAG_THERMAL_CRITICAL : 0);
}
if (mRequest != null && !contains(newSupportedStates, mRequest.getRequestedState())) {
- cancelCurrentRequestLocked();
+ cancelCurrentRequestLocked(isThermalCritical ? FLAG_THERMAL_CRITICAL : 0);
}
}
@@ -244,7 +252,11 @@ final class OverrideRequestController {
}
private void cancelRequestLocked(@NonNull OverrideRequest requestToCancel) {
- mListener.onStatusChanged(requestToCancel, STATUS_CANCELED);
+ cancelRequestLocked(requestToCancel, 0 /* flags */);
+ }
+
+ private void cancelRequestLocked(@NonNull OverrideRequest requestToCancel, int flags) {
+ mListener.onStatusChanged(requestToCancel, STATUS_CANCELED, flags);
}
/**
@@ -252,12 +264,16 @@ final class OverrideRequestController {
* Notifies the listener of the canceled status as well.
*/
private void cancelCurrentRequestLocked() {
+ cancelCurrentRequestLocked(0 /* flags */);
+ }
+
+ private void cancelCurrentRequestLocked(int flags) {
if (mRequest == null) {
Slog.w(TAG, "Attempted to cancel a null OverrideRequest");
return;
}
mStickyRequest = false;
- cancelRequestLocked(mRequest);
+ cancelRequestLocked(mRequest, flags);
mRequest = null;
}
@@ -266,11 +282,15 @@ final class OverrideRequestController {
* Notifies the listener of the canceled status as well.
*/
private void cancelCurrentBaseStateRequestLocked() {
+ cancelCurrentBaseStateRequestLocked(0 /* flags */);
+ }
+
+ private void cancelCurrentBaseStateRequestLocked(int flags) {
if (mBaseStateRequest == null) {
Slog.w(TAG, "Attempted to cancel a null OverrideRequest");
return;
}
- cancelRequestLocked(mBaseStateRequest);
+ cancelRequestLocked(mBaseStateRequest, flags);
mBaseStateRequest = null;
}
@@ -284,12 +304,14 @@ final class OverrideRequestController {
}
public interface StatusChangeListener {
+
/**
* Notifies the listener of a change in request status. If a change within the controller
* causes one request to become active and one to become either suspended or cancelled, this
* method is guaranteed to be called with the active request first before the suspended or
* cancelled request.
*/
- void onStatusChanged(@NonNull OverrideRequest request, @RequestStatus int newStatus);
+ void onStatusChanged(@NonNull OverrideRequest request, @RequestStatus int newStatus,
+ int flags);
}
}
diff --git a/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java b/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
index 7f733efef8a23..8d7f78209a4e7 100644
--- a/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
+++ b/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
@@ -366,12 +366,12 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider,
}
mListener = listener;
}
- notifySupportedStatesChanged();
+ notifySupportedStatesChanged(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED);
notifyDeviceStateChangedIfNeeded();
}
/** Notifies the listener that the set of supported device states has changed. */
- private void notifySupportedStatesChanged() {
+ private void notifySupportedStatesChanged(@SupportedStatesUpdatedReason int reason) {
List supportedStates = new ArrayList<>();
Listener listener;
synchronized (mLock) {
@@ -390,7 +390,7 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider,
}
listener.onSupportedDeviceStatesChanged(
- supportedStates.toArray(new DeviceState[supportedStates.size()]));
+ supportedStates.toArray(new DeviceState[supportedStates.size()]), reason);
}
/** Computes the current device state and notifies the listener of a change, if needed. */
@@ -688,7 +688,10 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider,
if (isThermalStatusCriticalOrAbove != isPreviousThermalStatusCriticalOrAbove) {
Slog.i(TAG, "Updating supported device states due to thermal status change."
+ " isThermalStatusCriticalOrAbove: " + isThermalStatusCriticalOrAbove);
- notifySupportedStatesChanged();
+ notifySupportedStatesChanged(
+ isThermalStatusCriticalOrAbove
+ ? SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_CRITICAL
+ : SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_NORMAL);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
index 82f64933c2826..c952609a8da4b 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
@@ -945,13 +945,15 @@ public final class DeviceStateManagerServiceTest {
}
mListener = listener;
- mListener.onSupportedDeviceStatesChanged(mSupportedDeviceStates);
+ mListener.onSupportedDeviceStatesChanged(mSupportedDeviceStates,
+ SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED);
mListener.onStateChanged(mSupportedDeviceStates[0].getIdentifier());
}
public void notifySupportedDeviceStates(DeviceState[] supportedDeviceStates) {
mSupportedDeviceStates = supportedDeviceStates;
- mListener.onSupportedDeviceStatesChanged(supportedDeviceStates);
+ mListener.onSupportedDeviceStatesChanged(supportedDeviceStates,
+ SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED);
}
public void setState(int identifier) {
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateNotificationControllerTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateNotificationControllerTest.java
new file mode 100644
index 0000000000000..8196d6a35cbd6
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateNotificationControllerTest.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.devicestate;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.platform.test.annotations.Presubmit;
+import android.util.SparseArray;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Mockito;
+
+/**
+ * Unit tests for {@link DeviceStateNotificationController}.
+ *
+ * Run with atest com.android.server.devicestate.DeviceStateNotificationControllerTest.
+ */
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+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 VALID_APP_UID = 1000;
+ private static final int INVALID_APP_UID = 2000;
+ private static final String VALID_APP_NAME = "Valid app name";
+ private static final String INVALID_APP_NAME = "Invalid app name";
+ private static final String VALID_APP_LABEL = "Valid app label";
+
+ private static final String NAME_1 = "name1";
+ private static final String TITLE_1 = "title1";
+ private static final String CONTENT_1 = "content1:%1$s";
+ private static final String NAME_2 = "name2";
+ private static final String TITLE_2 = "title2";
+ 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 DeviceStateNotificationController mController;
+
+ private final ArgumentCaptor mNotificationCaptor = ArgumentCaptor.forClass(
+ Notification.class);
+ private final NotificationManager mNotificationManager = mock(NotificationManager.class);
+
+ @Before
+ public void setup() throws Exception {
+ Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ Handler handler = mock(Handler.class);
+ PackageManager packageManager = mock(PackageManager.class);
+ Runnable cancelStateRunnable = mock(Runnable.class);
+ ApplicationInfo applicationInfo = mock(ApplicationInfo.class);
+
+ final SparseArray notificationInfos =
+ new SparseArray<>();
+ notificationInfos.put(STATE_WITH_ACTIVE_NOTIFICATION,
+ new DeviceStateNotificationController.NotificationInfo(
+ NAME_1, TITLE_1, CONTENT_1,
+ "", ""));
+ notificationInfos.put(STATE_WITH_ACTIVE_AND_THERMAL_NOTIFICATION,
+ new DeviceStateNotificationController.NotificationInfo(
+ NAME_2, TITLE_2, CONTENT_2,
+ THERMAL_TITLE_2, THERMAL_CONTENT_2));
+
+ when(packageManager.getNameForUid(VALID_APP_UID)).thenReturn(VALID_APP_NAME);
+ when(packageManager.getNameForUid(INVALID_APP_UID)).thenReturn(INVALID_APP_NAME);
+ when(packageManager.getApplicationInfo(eq(VALID_APP_NAME), ArgumentMatchers.any()))
+ .thenReturn(applicationInfo);
+ when(packageManager.getApplicationInfo(eq(INVALID_APP_NAME), ArgumentMatchers.any()))
+ .thenThrow(new PackageManager.NameNotFoundException());
+ when(applicationInfo.loadLabel(eq(packageManager))).thenReturn(VALID_APP_LABEL);
+
+ mController = new DeviceStateNotificationController(
+ context, handler, cancelStateRunnable, notificationInfos,
+ packageManager, mNotificationManager);
+ }
+
+ @Test
+ public void test_activeNotification() {
+ mController.showStateActiveNotificationIfNeeded(
+ STATE_WITH_ACTIVE_NOTIFICATION, VALID_APP_UID);
+
+ // Verify that the notification manager is called with correct notification information.
+ verify(mNotificationManager).notify(
+ eq(DeviceStateNotificationController.NOTIFICATION_TAG),
+ eq(DeviceStateNotificationController.NOTIFICATION_ID),
+ mNotificationCaptor.capture());
+ Notification notification = mNotificationCaptor.getValue();
+ assertEquals(TITLE_1, notification.extras.getString(Notification.EXTRA_TITLE));
+ assertEquals(String.format(CONTENT_1, VALID_APP_LABEL),
+ notification.extras.getString(Notification.EXTRA_TEXT));
+ assertEquals(Notification.FLAG_ONGOING_EVENT,
+ notification.flags & Notification.FLAG_ONGOING_EVENT);
+
+ // Verify that the notification action is as expected.
+ Notification.Action[] actions = notification.actions;
+ assertEquals(1, actions.length);
+ Notification.Action action = actions[0];
+ assertEquals(DeviceStateNotificationController.INTENT_ACTION_CANCEL_STATE,
+ action.actionIntent.getIntent().getAction());
+
+ // Verify that the notification is properly canceled.
+ mController.cancelNotification(STATE_WITH_ACTIVE_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);
+ 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.showThermalCriticalNotificationIfNeeded(
+ STATE_WITH_ACTIVE_AND_THERMAL_NOTIFICATION);
+ verify(mNotificationManager).notify(
+ eq(DeviceStateNotificationController.NOTIFICATION_TAG),
+ eq(DeviceStateNotificationController.NOTIFICATION_ID),
+ mNotificationCaptor.capture());
+ notification = mNotificationCaptor.getValue();
+ assertEquals(THERMAL_TITLE_2, notification.extras.getString(Notification.EXTRA_TITLE));
+ assertEquals(THERMAL_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_ACTIVE_NOTIFICATION);
+ verify(mNotificationManager).cancel(
+ DeviceStateNotificationController.NOTIFICATION_TAG,
+ DeviceStateNotificationController.NOTIFICATION_ID);
+ }
+
+ @Test
+ public void test_deviceStateWithoutNotification() {
+ // Verify that no notification is created.
+ mController.showStateActiveNotificationIfNeeded(
+ STATE_WITHOUT_NOTIFICATION, VALID_APP_UID);
+ verify(mNotificationManager, Mockito.never()).notify(
+ eq(DeviceStateNotificationController.NOTIFICATION_TAG),
+ eq(DeviceStateNotificationController.NOTIFICATION_ID),
+ mNotificationCaptor.capture());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/OverrideRequestControllerTest.java b/services/tests/servicestests/src/com/android/server/devicestate/OverrideRequestControllerTest.java
index 430504ca24284..fe37f4241d8e5 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/OverrideRequestControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/OverrideRequestControllerTest.java
@@ -58,7 +58,7 @@ public final class OverrideRequestControllerTest {
@Test
public void addRequest() {
- OverrideRequest request = new OverrideRequest(new Binder(), 0 /* pid */,
+ OverrideRequest request = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
assertNull(mStatusListener.getLastStatus(request));
@@ -68,14 +68,14 @@ public final class OverrideRequestControllerTest {
@Test
public void addRequest_cancelExistingRequestThroughNewRequest() {
- OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+ OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
assertNull(mStatusListener.getLastStatus(firstRequest));
mController.addRequest(firstRequest);
assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_ACTIVE);
- OverrideRequest secondRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+ OverrideRequest secondRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
1 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
assertNull(mStatusListener.getLastStatus(secondRequest));
@@ -86,7 +86,7 @@ public final class OverrideRequestControllerTest {
@Test
public void addRequest_cancelActiveRequest() {
- OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+ OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
mController.addRequest(firstRequest);
@@ -100,7 +100,7 @@ public final class OverrideRequestControllerTest {
@Test
public void addBaseStateRequest() {
- OverrideRequest request = new OverrideRequest(new Binder(), 0 /* pid */,
+ OverrideRequest request = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
assertNull(mStatusListener.getLastStatus(request));
@@ -110,14 +110,14 @@ public final class OverrideRequestControllerTest {
@Test
public void addBaseStateRequest_cancelExistingBaseStateRequestThroughNewRequest() {
- OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+ OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
assertNull(mStatusListener.getLastStatus(firstRequest));
mController.addBaseStateRequest(firstRequest);
assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_ACTIVE);
- OverrideRequest secondRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+ OverrideRequest secondRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
1 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
assertNull(mStatusListener.getLastStatus(secondRequest));
@@ -128,7 +128,7 @@ public final class OverrideRequestControllerTest {
@Test
public void addBaseStateRequest_cancelActiveBaseStateRequest() {
- OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+ OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
mController.addBaseStateRequest(firstRequest);
@@ -142,12 +142,13 @@ public final class OverrideRequestControllerTest {
@Test
public void handleBaseStateChanged() {
- OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+ OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
0 /* requestedState */,
DeviceStateRequest.FLAG_CANCEL_WHEN_BASE_CHANGES /* flags */,
OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
OverrideRequest baseStateRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+ 0 /* uid */,
0 /* requestedState */,
0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
@@ -167,10 +168,11 @@ public final class OverrideRequestControllerTest {
@Test
public void handleProcessDied() {
- OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+ OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
OverrideRequest baseStateRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+ 0 /* uid */,
1 /* requestedState */,
0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
@@ -189,10 +191,11 @@ public final class OverrideRequestControllerTest {
public void handleProcessDied_stickyRequests() {
mController.setStickyRequestsAllowed(true);
- OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+ OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
OverrideRequest baseStateRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+ 0 /* uid */,
1 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
mController.addRequest(firstRequest);
@@ -211,10 +214,11 @@ public final class OverrideRequestControllerTest {
@Test
public void handleNewSupportedStates() {
- OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+ OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
1 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
OverrideRequest baseStateRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+ 0 /* uid */,
1 /* requestedState */,
0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
@@ -224,18 +228,20 @@ public final class OverrideRequestControllerTest {
mController.addBaseStateRequest(baseStateRequest);
assertEquals(mStatusListener.getLastStatus(baseStateRequest).intValue(), STATUS_ACTIVE);
- mController.handleNewSupportedStates(new int[]{0, 1});
+ mController.handleNewSupportedStates(new int[]{0, 1},
+ DeviceStateProvider.SUPPORTED_DEVICE_STATES_CHANGED_DEFAULT);
assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_ACTIVE);
assertEquals(mStatusListener.getLastStatus(baseStateRequest).intValue(), STATUS_ACTIVE);
- mController.handleNewSupportedStates(new int[]{0});
+ mController.handleNewSupportedStates(new int[]{0},
+ DeviceStateProvider.SUPPORTED_DEVICE_STATES_CHANGED_DEFAULT);
assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_CANCELED);
assertEquals(mStatusListener.getLastStatus(baseStateRequest).intValue(), STATUS_CANCELED);
}
@Test
public void cancelOverrideRequestsTest() {
- OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+ OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
1 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
mController.addRequest(firstRequest);
@@ -250,7 +256,7 @@ public final class OverrideRequestControllerTest {
private Map mLastStatusMap = new HashMap<>();
@Override
- public void onStatusChanged(@NonNull OverrideRequest request, int newStatus) {
+ public void onStatusChanged(@NonNull OverrideRequest request, int newStatus, int flags) {
mLastStatusMap.put(request, newStatus);
}
diff --git a/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java b/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java
index 7fac9b6081141..7125796e7b986 100644
--- a/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java
@@ -19,6 +19,9 @@ 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_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;
import static org.junit.Assert.assertArrayEquals;
@@ -124,7 +127,8 @@ public final class DeviceStateProviderImplTest {
DeviceStateProvider.Listener listener = mock(DeviceStateProvider.Listener.class);
provider.setListener(listener);
- verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
+ verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED));
assertArrayEquals(new DeviceState[]{DEFAULT_DEVICE_STATE},
mDeviceStateArrayCaptor.getValue());
@@ -151,7 +155,8 @@ public final class DeviceStateProviderImplTest {
DeviceStateProvider.Listener listener = mock(DeviceStateProvider.Listener.class);
provider.setListener(listener);
- verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
+ verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED));
final DeviceState[] expectedStates = new DeviceState[]{
new DeviceState(1, "", 0 /* flags */),
new DeviceState(2, "", 0 /* flags */) };
@@ -183,7 +188,8 @@ public final class DeviceStateProviderImplTest {
DeviceStateProvider.Listener listener = mock(DeviceStateProvider.Listener.class);
provider.setListener(listener);
- verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
+ verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED));
final DeviceState[] expectedStates = new DeviceState[]{
new DeviceState(1, "", DeviceState.FLAG_CANCEL_OVERRIDE_REQUESTS),
new DeviceState(2, "", 0 /* flags */) };
@@ -212,7 +218,8 @@ public final class DeviceStateProviderImplTest {
DeviceStateProvider.Listener listener = mock(DeviceStateProvider.Listener.class);
provider.setListener(listener);
- verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
+ verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED));
final DeviceState[] expectedStates = new DeviceState[]{
new DeviceState(1, "", 0 /* flags */),
new DeviceState(2, "", 0 /* flags */) };
@@ -247,7 +254,8 @@ public final class DeviceStateProviderImplTest {
DeviceStateProvider.Listener listener = mock(DeviceStateProvider.Listener.class);
provider.setListener(listener);
- verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
+ verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED));
final DeviceState[] expectedStates = new DeviceState[]{
new DeviceState(1, "", 0 /* flags */),
new DeviceState(2, "CLOSED", 0 /* flags */) };
@@ -265,7 +273,8 @@ public final class DeviceStateProviderImplTest {
Mockito.clearInvocations(listener);
provider.notifyLidSwitchChanged(1, true /* lidOpen */);
- verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
+ verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED));
verify(listener).onStateChanged(mIntegerCaptor.capture());
assertEquals(1, mIntegerCaptor.getValue().intValue());
}
@@ -336,7 +345,8 @@ public final class DeviceStateProviderImplTest {
DeviceStateProvider.Listener listener = mock(DeviceStateProvider.Listener.class);
provider.setListener(listener);
- verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
+ verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED));
assertArrayEquals(
new DeviceState[]{
new DeviceState(1, "CLOSED", 0 /* flags */),
@@ -358,7 +368,8 @@ public final class DeviceStateProviderImplTest {
provider.onSensorChanged(event0);
- verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
+ verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED));
verify(listener).onStateChanged(mIntegerCaptor.capture());
assertEquals(3, mIntegerCaptor.getValue().intValue());
@@ -370,7 +381,8 @@ public final class DeviceStateProviderImplTest {
provider.onSensorChanged(event1);
- verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
+ verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED));
verify(listener).onStateChanged(mIntegerCaptor.capture());
assertEquals(2, mIntegerCaptor.getValue().intValue());
@@ -382,7 +394,8 @@ public final class DeviceStateProviderImplTest {
provider.onSensorChanged(event2);
- verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
+ verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED));
verify(listener).onStateChanged(mIntegerCaptor.capture());
assertEquals(1, mIntegerCaptor.getValue().intValue());
}
@@ -397,7 +410,8 @@ public final class DeviceStateProviderImplTest {
DeviceStateProvider.Listener listener = mock(DeviceStateProvider.Listener.class);
provider.setListener(listener);
- verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
+ verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED));
assertArrayEquals(
new DeviceState[]{
new DeviceState(1, "CLOSED", 0 /* flags */),
@@ -410,12 +424,14 @@ public final class DeviceStateProviderImplTest {
Mockito.clearInvocations(listener);
provider.onThermalStatusChanged(PowerManager.THERMAL_STATUS_MODERATE);
- verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
+ verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED));
Mockito.clearInvocations(listener);
// The THERMAL_TEST state should be disabled.
provider.onThermalStatusChanged(PowerManager.THERMAL_STATUS_CRITICAL);
- verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
+ verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_CRITICAL));
assertArrayEquals(
new DeviceState[]{
new DeviceState(1, "CLOSED", 0 /* flags */),
@@ -426,7 +442,8 @@ public final class DeviceStateProviderImplTest {
// The THERMAL_TEST state should be re-enabled.
provider.onThermalStatusChanged(PowerManager.THERMAL_STATUS_LIGHT);
- verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
+ verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_NORMAL));
assertArrayEquals(
new DeviceState[]{
new DeviceState(1, "CLOSED", 0 /* flags */),
@@ -468,7 +485,8 @@ public final class DeviceStateProviderImplTest {
provider.onSensorChanged(event2);
- verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
+ verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED));
verify(listener, never()).onStateChanged(mIntegerCaptor.capture());
}
@@ -513,7 +531,8 @@ public final class DeviceStateProviderImplTest {
DeviceStateProvider.Listener listener = mock(DeviceStateProvider.Listener.class);
provider.setListener(listener);
- verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
+ verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED));
assertArrayEquals(
new DeviceState[]{
new DeviceState(1, "CLOSED", 0 /* flags */),