summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/Android.bp1
-rw-r--r--core/java/android/hardware/display/DisplayManagerInternal.java5
-rw-r--r--core/java/android/os/IPowerManager.aidl5
-rw-r--r--core/java/android/os/IScreenTimeoutPolicyListener.aidl29
-rw-r--r--core/java/android/os/PowerManager.java113
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java9
-rw-r--r--services/core/java/com/android/server/power/Notifier.java149
-rw-r--r--services/core/java/com/android/server/power/PowerGroup.java9
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java87
-rw-r--r--services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java201
-rw-r--r--services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java117
11 files changed, 722 insertions, 3 deletions
diff --git a/core/java/Android.bp b/core/java/Android.bp
index ce767f46dd50..1e97d4f12836 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -223,6 +223,7 @@ filegroup {
"android/os/IThermalService.aidl",
"android/os/IPowerManager.aidl",
"android/os/IWakeLockCallback.aidl",
+ "android/os/IScreenTimeoutPolicyListener.aidl",
],
}
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 68b6cfc012fc..d273ddb15cc4 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -449,6 +449,11 @@ public abstract class DisplayManagerInternal {
public abstract IntArray getDisplayIds();
/**
+ * Get group id for given display id
+ */
+ public abstract int getGroupIdForDisplay(int displayId);
+
+ /**
* Called upon presentation started/ended on the display.
* @param displayId the id of the display where presentation started.
* @param isShown whether presentation is shown.
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 4cac4dee0bea..17697e67c757 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -22,6 +22,7 @@ import android.os.ParcelDuration;
import android.os.PowerSaveState;
import android.os.WorkSource;
import android.os.IWakeLockCallback;
+import android.os.IScreenTimeoutPolicyListener;
/** @hide */
@@ -45,6 +46,10 @@ interface IPowerManager
@UnsupportedAppUsage
boolean isWakeLockLevelSupported(int level);
boolean isWakeLockLevelSupportedWithDisplayId(int level, int displayId);
+ oneway void addScreenTimeoutPolicyListener(int displayId,
+ IScreenTimeoutPolicyListener listener);
+ oneway void removeScreenTimeoutPolicyListener(int displayId,
+ IScreenTimeoutPolicyListener listener);
void userActivity(int displayId, long time, int event, int flags);
void wakeUp(long time, int reason, String details, String opPackageName);
diff --git a/core/java/android/os/IScreenTimeoutPolicyListener.aidl b/core/java/android/os/IScreenTimeoutPolicyListener.aidl
new file mode 100644
index 000000000000..62811a0cb436
--- /dev/null
+++ b/core/java/android/os/IScreenTimeoutPolicyListener.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 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 android.os;
+
+/**
+ * Listener for screen timeout policy changes
+ * @see PowerManager#addScreenTimeoutPolicyListener(int, IScreenTimeoutPolicyListener)
+ * @hide
+ */
+oneway interface IScreenTimeoutPolicyListener {
+ /**
+ * @see PowerManager#addScreenTimeoutPolicyListener
+ */
+ oneway void onScreenTimeoutPolicyChanged(int screenTimeoutPolicy);
+}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index cd48f0847f8d..1801df048b3e 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -34,6 +34,7 @@ import android.annotation.TestApi;
import android.app.PropertyInvalidatedCache;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
+import android.os.IScreenTimeoutPolicyListener;
import android.service.dreams.Sandman;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -1049,6 +1050,29 @@ public final class PowerManager {
}
/**
+ * Screen timeout policy type: the screen turns off after a timeout
+ * @hide
+ */
+ public static final int SCREEN_TIMEOUT_ACTIVE = 0;
+
+ /**
+ * Screen timeout policy type: the screen is kept 'on' (no timeout)
+ * @hide
+ */
+ public static final int SCREEN_TIMEOUT_KEEP_DISPLAY_ON = 1;
+
+ /**
+ * @hide
+ */
+ @IntDef(prefix = { "SCREEN_TIMEOUT_" }, value = {
+ SCREEN_TIMEOUT_ACTIVE,
+ SCREEN_TIMEOUT_KEEP_DISPLAY_ON
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ScreenTimeoutPolicy{}
+
+
+ /**
* Either the location providers shouldn't be affected by battery saver,
* or battery saver is off.
*/
@@ -1208,6 +1232,9 @@ public final class PowerManager {
private final ArrayMap<OnThermalHeadroomChangedListener, IThermalHeadroomListener>
mThermalHeadroomListenerMap = new ArrayMap<>();
+ private final ArrayMap<ScreenTimeoutPolicyListener, IScreenTimeoutPolicyListener>
+ mScreenTimeoutPolicyListeners = new ArrayMap<>();
+
/**
* {@hide}
*/
@@ -1749,6 +1776,77 @@ public final class PowerManager {
}
}
+ /**
+ * Adds a listener to be notified about changes in screen timeout policy.
+ *
+ * <p>The screen timeout policy determines the behavior of the device's screen
+ * after a period of inactivity. It can be used to understand if the display is going
+ * to be turned off after a timeout to conserve power, or if it will be kept on indefinitely.
+ * For example, it might be useful for adjusting display switch conditions on foldable
+ * devices based on the current timeout policy.
+ *
+ * <p>See {@link ScreenTimeoutPolicy} for possible values.
+ *
+ * <p>The listener will be fired with the initial state upon subscribing.
+ *
+ * <p>IScreenTimeoutPolicyListener is called on either system server's main thread or
+ * on a binder thread if subscribed outside the system service process.
+ *
+ * @param displayId display id for which to be notified about screen timeout policy changes
+ * @param executor executor on which to execute ScreenTimeoutPolicyListener methods
+ * @param listener listener that will be fired on screem timeout policy updates
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
+ public void addScreenTimeoutPolicyListener(int displayId,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull ScreenTimeoutPolicyListener listener) {
+ Objects.requireNonNull(listener, "listener cannot be null");
+ Objects.requireNonNull(executor, "executor cannot be null");
+ Preconditions.checkArgument(!mScreenTimeoutPolicyListeners.containsKey(listener),
+ "Listener already registered: %s", listener);
+
+ final IScreenTimeoutPolicyListener stub = new IScreenTimeoutPolicyListener.Stub() {
+ public void onScreenTimeoutPolicyChanged(int screenTimeoutPolicy) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() ->
+ listener.onScreenTimeoutPolicyChanged(screenTimeoutPolicy));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ };
+
+ try {
+ mService.addScreenTimeoutPolicyListener(displayId, stub);
+ mScreenTimeoutPolicyListeners.put(listener, stub);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Removes a listener that is used to listen for screen timeout policy changes.
+ * @see PowerManager#addScreenTimeoutPolicyListener(int, ScreenTimeoutPolicyListener)
+ * @param displayId display id for which to be notified about screen timeout changes
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
+ public void removeScreenTimeoutPolicyListener(int displayId,
+ @NonNull ScreenTimeoutPolicyListener listener) {
+ Objects.requireNonNull(listener, "listener cannot be null");
+ IScreenTimeoutPolicyListener internalListener = mScreenTimeoutPolicyListeners.get(listener);
+ Preconditions.checkArgument(internalListener != null, "Listener was not added");
+
+ try {
+ mService.removeScreenTimeoutPolicyListener(displayId, internalListener);
+ mScreenTimeoutPolicyListeners.remove(listener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Returns true if the specified wake lock level is supported.
*
@@ -3825,6 +3923,21 @@ public final class PowerManager {
}
/**
+ * Listener for screen timeout policy changes
+ * @see PowerManager#addScreenTimeoutPolicyListener(int, ScreenTimeoutPolicyListener)
+ * @hide
+ */
+ public interface ScreenTimeoutPolicyListener {
+ /**
+ * Invoked on changes in screen timeout policy.
+ *
+ * @param screenTimeoutPolicy Screen timeout policy, one of {@link ScreenTimeoutPolicy}
+ * @see PowerManager#addScreenTimeoutPolicyListener
+ */
+ void onScreenTimeoutPolicyChanged(@ScreenTimeoutPolicy int screenTimeoutPolicy);
+ }
+
+ /**
* A wake lock is a mechanism to indicate that your application needs
* to have the device stay on.
* <p>
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index f145a47eb935..c8192e534f5c 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -5845,6 +5845,15 @@ public final class DisplayManagerService extends SystemService {
}
@Override
+ public int getGroupIdForDisplay(int displayId) {
+ synchronized (mSyncRoot) {
+ final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
+ if (display == null) return Display.INVALID_DISPLAY_GROUP;
+ return display.getDisplayInfoLocked().displayGroupId;
+ }
+ }
+
+ @Override
public DisplayManagerInternal.DisplayOffloadSession registerDisplayOffloader(
int displayId, @NonNull DisplayManagerInternal.DisplayOffloader displayOffloader) {
if (!mFlags.isDisplayOffloadEnabled()) {
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 7f88e7463208..102dc071c7b6 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -37,11 +37,14 @@ import android.os.BatteryStatsInternal;
import android.os.Bundle;
import android.os.Handler;
import android.os.IWakeLockCallback;
+import android.os.IScreenTimeoutPolicyListener;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
+import android.os.PowerManager.ScreenTimeoutPolicy;
import android.os.PowerManagerInternal;
import android.os.Process;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -52,6 +55,7 @@ import android.os.WorkSource;
import android.os.WorkSource.WorkChain;
import android.provider.Settings;
import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
import android.util.EventLog;
import android.util.Slog;
import android.util.SparseArray;
@@ -152,6 +156,11 @@ public class Notifier {
private final Intent mScreenOffIntent;
private final Bundle mScreenOnOffOptions;
+ // Display id -> ScreenTimeoutPolicyListenersContainer that contains list of screen
+ // wake lock listeners
+ private final SparseArray<ScreenTimeoutPolicyListenersContainer> mScreenTimeoutPolicyListeners
+ = new SparseArray<>();
+
// True if the device should suspend when the screen is off due to proximity.
private final boolean mSuspendWhenScreenOffDueToProximityConfig;
@@ -1270,6 +1279,146 @@ public class Notifier {
}
}
+ /**
+ * Adds a listener for the screen timeout policy
+ * @param displayId display ID
+ * @param screenTimeoutPolicy initial state of the timeout policy
+ * @param listener callback to receive screen timeout policy updates
+ */
+ void addScreenTimeoutPolicyListener(int displayId, @ScreenTimeoutPolicy int screenTimeoutPolicy,
+ IScreenTimeoutPolicyListener listener) {
+ synchronized (mLock) {
+ ScreenTimeoutPolicyListenersContainer listenersContainer =
+ mScreenTimeoutPolicyListeners.get(displayId);
+ if (listenersContainer == null) {
+ listenersContainer = new ScreenTimeoutPolicyListenersContainer(
+ screenTimeoutPolicy);
+ mScreenTimeoutPolicyListeners.set(displayId, listenersContainer);
+ }
+
+ listenersContainer.addListener(listener);
+ }
+ }
+
+ /**
+ * Removes a listener for the screen timeout policy
+ * @param displayId display id from which the listener should be removed
+ * @param listener the instance of the listener
+ */
+ void removeScreenTimeoutPolicyListener(int displayId,
+ IScreenTimeoutPolicyListener listener) {
+ synchronized (mLock) {
+ ScreenTimeoutPolicyListenersContainer listenersContainer =
+ mScreenTimeoutPolicyListeners.get(displayId);
+ if (listenersContainer == null) {
+ return;
+ }
+
+ listenersContainer.removeListener(listener);
+
+ if (listenersContainer.isEmpty()) {
+ mScreenTimeoutPolicyListeners.remove(displayId);
+ }
+ }
+ }
+
+ /**
+ * Clears all screen timeout policy listeners for the specified display id
+ * @param displayId display id from which the listeners should be cleared
+ */
+ void clearScreenTimeoutPolicyListeners(int displayId) {
+ synchronized (mLock) {
+ mScreenTimeoutPolicyListeners.remove(displayId);
+ }
+ }
+
+ /**
+ * Notifies about screen timeout policy changes of the corresponding display group if
+ * it has changed
+ * @param displayGroupId the id of the display group to report
+ * @param screenTimeoutPolicy screen timeout policy
+ */
+ void notifyScreenTimeoutPolicyChanges(int displayGroupId,
+ @ScreenTimeoutPolicy int screenTimeoutPolicy) {
+ synchronized (mLock) {
+ for (int idx = 0; idx < mScreenTimeoutPolicyListeners.size(); idx++) {
+ final int displayId = mScreenTimeoutPolicyListeners.keyAt(idx);
+ if (mDisplayManagerInternal.getGroupIdForDisplay(displayId) == displayGroupId) {
+ final ScreenTimeoutPolicyListenersContainer container =
+ mScreenTimeoutPolicyListeners.valueAt(idx);
+ container.updateScreenTimeoutPolicyAndNotifyIfNeeded(screenTimeoutPolicy);
+ }
+ }
+ }
+ }
+
+ private final class ScreenTimeoutPolicyListenersContainer {
+ private final RemoteCallbackList<IScreenTimeoutPolicyListener> mListeners;
+ private final ArrayMap<IScreenTimeoutPolicyListener, Integer> mLastReportedState =
+ new ArrayMap<>();
+
+ @ScreenTimeoutPolicy
+ private volatile int mScreenTimeoutPolicy;
+
+ ScreenTimeoutPolicyListenersContainer(int screenTimeoutPolicy) {
+ mScreenTimeoutPolicy = screenTimeoutPolicy;
+ mListeners = new RemoteCallbackList<IScreenTimeoutPolicyListener>() {
+ @Override
+ public void onCallbackDied(IScreenTimeoutPolicyListener callbackInterface) {
+ mLastReportedState.remove(callbackInterface);
+ }
+ };
+ }
+
+ void updateScreenTimeoutPolicyAndNotifyIfNeeded(
+ @ScreenTimeoutPolicy int screenTimeoutPolicy) {
+ mScreenTimeoutPolicy = screenTimeoutPolicy;
+
+ mHandler.post(() -> {
+ for (int i = mListeners.beginBroadcast() - 1; i >= 0; i--) {
+ final IScreenTimeoutPolicyListener listener = mListeners.getBroadcastItem(i);
+ notifyListenerIfNeeded(listener);
+ }
+ mListeners.finishBroadcast();
+ });
+ }
+
+ void addListener(IScreenTimeoutPolicyListener listener) {
+ mListeners.register(listener);
+ mHandler.post(() -> notifyListenerIfNeeded(listener));
+ }
+
+ void removeListener(IScreenTimeoutPolicyListener listener) {
+ mListeners.unregister(listener);
+ mLastReportedState.remove(listener);
+ }
+
+ boolean isEmpty() {
+ return mListeners.getRegisteredCallbackCount() == 0;
+ }
+
+ private void notifyListenerIfNeeded(IScreenTimeoutPolicyListener listener) {
+ final int currentScreenTimeoutPolicy = mScreenTimeoutPolicy;
+ final Integer reportedScreenTimeoutPolicy = mLastReportedState.get(listener);
+ final boolean needsReporting = reportedScreenTimeoutPolicy == null
+ || !reportedScreenTimeoutPolicy.equals(currentScreenTimeoutPolicy);
+
+ if (!needsReporting) return;
+
+ try {
+ listener.onScreenTimeoutPolicyChanged(currentScreenTimeoutPolicy);
+ mLastReportedState.put(listener, currentScreenTimeoutPolicy);
+ } catch (RemoteException e) {
+ // The RemoteCallbackList will take care of removing
+ // the dead object for us.
+ Slog.e(TAG, "Remote exception when notifying screen timeout policy change", e);
+ } catch (Throwable e) {
+ Slog.e(TAG, "Exception when notifying screen timeout policy change", e);
+ removeListener(listener);
+ }
+ }
+ }
+
private final class NotifierHandler extends Handler {
public NotifierHandler(Looper looper) {
diff --git a/services/core/java/com/android/server/power/PowerGroup.java b/services/core/java/com/android/server/power/PowerGroup.java
index 01a2045df426..86eb34cead15 100644
--- a/services/core/java/com/android/server/power/PowerGroup.java
+++ b/services/core/java/com/android/server/power/PowerGroup.java
@@ -16,6 +16,8 @@
package com.android.server.power;
+import static android.os.PowerManager.SCREEN_TIMEOUT_KEEP_DISPLAY_ON;
+import static android.os.PowerManager.SCREEN_TIMEOUT_ACTIVE;
import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING;
@@ -34,6 +36,7 @@ import static com.android.server.power.PowerManagerService.WAKE_LOCK_STAY_AWAKE;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
import android.os.PowerManager;
+import android.os.PowerManager.ScreenTimeoutPolicy;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.Trace;
@@ -415,6 +418,12 @@ public class PowerGroup {
return (mWakeLockSummary & (screenOnWakeLockMask)) != 0;
}
+ @ScreenTimeoutPolicy
+ public int getScreenTimeoutPolicy() {
+ return hasWakeLockKeepingScreenOnLocked() ? SCREEN_TIMEOUT_KEEP_DISPLAY_ON
+ : SCREEN_TIMEOUT_ACTIVE;
+ }
+
public void setWakeLockSummaryLocked(int summary) {
mWakeLockSummary = summary;
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index ce8dc69e4b26..23383a9c55c0 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -63,6 +63,7 @@ import android.hardware.SystemSensorManager;
import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.display.AmbientDisplayConfiguration;
+import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.power.Boost;
import android.hardware.power.Mode;
@@ -76,6 +77,7 @@ import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.IPowerManager;
+import android.os.IScreenTimeoutPolicyListener;
import android.os.IWakeLockCallback;
import android.os.Looper;
import android.os.Message;
@@ -341,6 +343,7 @@ public final class PowerManagerService extends SystemService
private LightsManager mLightsManager;
private BatteryManagerInternal mBatteryManagerInternal;
private DisplayManagerInternal mDisplayManagerInternal;
+ private DisplayManager mDisplayManager;
private IBatteryStats mBatteryStats;
private WindowManagerPolicy mPolicy;
private Notifier mNotifier;
@@ -758,6 +761,24 @@ public final class PowerManagerService extends SystemService
}
}
+ private final class DisplayListener implements DisplayManager.DisplayListener {
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ mNotifier.clearScreenTimeoutPolicyListeners(displayId);
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+
+ }
+ }
+
private final class DisplayGroupPowerChangeListener implements
DisplayManagerInternal.DisplayGroupListener {
@@ -1354,6 +1375,7 @@ public final class PowerManagerService extends SystemService
mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class);
mPolicy = getLocalService(WindowManagerPolicy.class);
mBatteryManagerInternal = getLocalService(BatteryManagerInternal.class);
+ mDisplayManager = mContext.getSystemService(DisplayManager.class);
mAttentionDetector.systemReady(mContext);
SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper());
@@ -1373,6 +1395,7 @@ public final class PowerManagerService extends SystemService
DisplayGroupPowerChangeListener displayGroupPowerChangeListener =
new DisplayGroupPowerChangeListener();
mDisplayManagerInternal.registerDisplayGroupListener(displayGroupPowerChangeListener);
+ mDisplayManager.registerDisplayListener(new DisplayListener(), mHandler);
if(mDreamManager != null){
// This DreamManager method does not acquire a lock, so it should be safe to call.
@@ -2571,7 +2594,10 @@ public final class PowerManagerService extends SystemService
// Phase 5: Send notifications, if needed.
finishWakefulnessChangeIfNeededLocked();
- // Phase 6: Update suspend blocker.
+ // Phase 6: Notify screen timeout policy changes if needed
+ notifyScreenTimeoutPolicyChangesLocked();
+
+ // Phase 7: Update suspend blocker.
// Because we might release the last suspend blocker here, we need to make sure
// we finished everything else first!
updateSuspendBlockerLocked();
@@ -3824,6 +3850,16 @@ public final class PowerManagerService extends SystemService
& WAKE_LOCK_PROXIMITY_SCREEN_OFF) != 0;
}
+ @GuardedBy("mLock")
+ private void notifyScreenTimeoutPolicyChangesLocked() {
+ for (int idx = 0; idx < mPowerGroups.size(); idx++) {
+ final int powerGroupId = mPowerGroups.keyAt(idx);
+ final PowerGroup powerGroup = mPowerGroups.valueAt(idx);
+ final int screenTimeoutPolicy = powerGroup.getScreenTimeoutPolicy();
+ mNotifier.notifyScreenTimeoutPolicyChanges(powerGroupId, screenTimeoutPolicy);
+ }
+ }
+
/**
* Updates the suspend blocker that keeps the CPU alive.
*
@@ -5973,6 +6009,55 @@ public final class PowerManagerService extends SystemService
}
@Override // Binder call
+ public void addScreenTimeoutPolicyListener(int displayId,
+ IScreenTimeoutPolicyListener listener) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
+ null);
+
+ if (displayId == Display.INVALID_DISPLAY) {
+ throw new IllegalArgumentException("Valid display id is expected");
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ int initialTimeoutPolicy;
+ final int displayGroupId = mDisplayManagerInternal.getGroupIdForDisplay(displayId);
+ synchronized (mLock) {
+ final PowerGroup powerGroup = mPowerGroups.get(displayGroupId);
+ if (powerGroup != null) {
+ initialTimeoutPolicy = powerGroup.getScreenTimeoutPolicy();
+ } else {
+ throw new IllegalArgumentException("No display found for the specified "
+ + "display id " + displayId);
+ }
+ }
+
+ mNotifier.addScreenTimeoutPolicyListener(displayId, initialTimeoutPolicy,
+ listener);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ public void removeScreenTimeoutPolicyListener(int displayId,
+ IScreenTimeoutPolicyListener listener) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
+ null);
+
+ if (displayId == Display.INVALID_DISPLAY) {
+ throw new IllegalArgumentException("Valid display id is expected");
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mNotifier.removeScreenTimeoutPolicyListener(displayId, listener);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
public void userActivity(int displayId, long eventTime,
@PowerManager.UserActivityEvent int event, int flags) {
final long now = mClock.uptimeMillis();
diff --git a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
index 469bd66b7e7b..83a390d7f70b 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
@@ -16,6 +16,8 @@
package com.android.server.power;
+import static android.os.PowerManager.SCREEN_TIMEOUT_KEEP_DISPLAY_ON;
+import static android.os.PowerManager.SCREEN_TIMEOUT_ACTIVE;
import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
@@ -30,6 +32,7 @@ import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -49,7 +52,9 @@ import android.hardware.display.DisplayManagerInternal;
import android.os.BatteryStats;
import android.os.BatteryStatsInternal;
import android.os.Handler;
+import android.os.IBinder;
import android.os.IWakeLockCallback;
+import android.os.IScreenTimeoutPolicyListener;
import android.os.Looper;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -84,6 +89,7 @@ import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.concurrent.Executor;
@@ -916,6 +922,201 @@ public class NotifierTest {
PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK), -1);
}
+ @Test
+ public void testScreenTimeoutListener_reportsScreenTimeoutPolicyChange() throws Exception {
+ createNotifier();
+ final IScreenTimeoutPolicyListener listener = Mockito.mock(
+ IScreenTimeoutPolicyListener.class);
+ final IBinder listenerBinder = Mockito.mock(IBinder.class);
+ when(listener.asBinder()).thenReturn(listenerBinder);
+ mNotifier.addScreenTimeoutPolicyListener(Display.DEFAULT_DISPLAY,
+ SCREEN_TIMEOUT_ACTIVE, listener);
+ mTestLooper.dispatchAll();
+ clearInvocations(listener);
+
+ mNotifier.notifyScreenTimeoutPolicyChanges(Display.DEFAULT_DISPLAY_GROUP,
+ /* hasScreenWakeLock= */ SCREEN_TIMEOUT_KEEP_DISPLAY_ON);
+
+ // Verify that the event is sent asynchronously on a handler
+ verify(listener, never()).onScreenTimeoutPolicyChanged(anyInt());
+ mTestLooper.dispatchAll();
+ verify(listener).onScreenTimeoutPolicyChanged(SCREEN_TIMEOUT_KEEP_DISPLAY_ON);
+ }
+
+ @Test
+ public void testScreenTimeoutListener_addAndRemoveListener_doesNotInvokeListener()
+ throws Exception {
+ createNotifier();
+ final IScreenTimeoutPolicyListener listener = Mockito.mock(
+ IScreenTimeoutPolicyListener.class);
+ final IBinder listenerBinder = Mockito.mock(IBinder.class);
+ when(listener.asBinder()).thenReturn(listenerBinder);
+ mNotifier.addScreenTimeoutPolicyListener(Display.DEFAULT_DISPLAY,
+ SCREEN_TIMEOUT_ACTIVE, listener);
+ mTestLooper.dispatchAll();
+ clearInvocations(listener);
+ mNotifier.removeScreenTimeoutPolicyListener(Display.DEFAULT_DISPLAY, listener);
+
+ mNotifier.notifyScreenTimeoutPolicyChanges(Display.DEFAULT_DISPLAY_GROUP,
+ SCREEN_TIMEOUT_KEEP_DISPLAY_ON);
+ mTestLooper.dispatchAll();
+
+ // Callback should not be fired as listener is removed
+ verify(listener, never()).onScreenTimeoutPolicyChanged(anyInt());
+ }
+
+ @Test
+ public void testScreenTimeoutListener_addAndClearListeners_doesNotInvokeListener()
+ throws Exception {
+ createNotifier();
+ final IScreenTimeoutPolicyListener listener = Mockito.mock(
+ IScreenTimeoutPolicyListener.class);
+ final IBinder listenerBinder = Mockito.mock(IBinder.class);
+ when(listener.asBinder()).thenReturn(listenerBinder);
+ mNotifier.addScreenTimeoutPolicyListener(Display.DEFAULT_DISPLAY,
+ SCREEN_TIMEOUT_ACTIVE, listener);
+ mTestLooper.dispatchAll();
+ clearInvocations(listener);
+ mNotifier.clearScreenTimeoutPolicyListeners(Display.DEFAULT_DISPLAY);
+
+ mNotifier.notifyScreenTimeoutPolicyChanges(Display.DEFAULT_DISPLAY_GROUP,
+ SCREEN_TIMEOUT_KEEP_DISPLAY_ON);
+ mTestLooper.dispatchAll();
+
+ // Callback should not be fired as listener is removed
+ verify(listener, never()).onScreenTimeoutPolicyChanged(anyInt());
+ }
+
+ @Test
+ public void testScreenTimeoutListener_subscribedToAnotherDisplay_listenerNotFired()
+ throws Exception {
+ createNotifier();
+
+ final IScreenTimeoutPolicyListener listener = Mockito.mock(
+ IScreenTimeoutPolicyListener.class);
+ final IBinder listenerBinder = Mockito.mock(IBinder.class);
+ when(listener.asBinder()).thenReturn(listenerBinder);
+ mNotifier.addScreenTimeoutPolicyListener(Display.DEFAULT_DISPLAY,
+ SCREEN_TIMEOUT_ACTIVE, listener);
+ mTestLooper.dispatchAll();
+ clearInvocations(listener);
+
+ mNotifier.notifyScreenTimeoutPolicyChanges(/* displayGroupId= */ 123,
+ SCREEN_TIMEOUT_KEEP_DISPLAY_ON);
+ mTestLooper.dispatchAll();
+
+ // Callback should not be fired as we subscribed only to the DEFAULT_DISPLAY
+ verify(listener, never()).onScreenTimeoutPolicyChanged(anyInt());
+ }
+
+ @Test
+ public void testScreenTimeoutListener_listenerDied_listenerNotFired()
+ throws Exception {
+ createNotifier();
+
+ final IScreenTimeoutPolicyListener listener = Mockito.mock(
+ IScreenTimeoutPolicyListener.class);
+ final IBinder listenerBinder = Mockito.mock(IBinder.class);
+ when(listener.asBinder()).thenReturn(listenerBinder);
+
+ mNotifier.addScreenTimeoutPolicyListener(Display.DEFAULT_DISPLAY,
+ SCREEN_TIMEOUT_ACTIVE, listener);
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor<IBinder.DeathRecipient> captor =
+ ArgumentCaptor.forClass(IBinder.DeathRecipient.class);
+ verify(listenerBinder).linkToDeath(captor.capture(), anyInt());
+ mTestLooper.dispatchAll();
+ captor.getValue().binderDied();
+ clearInvocations(listener);
+
+ mNotifier.notifyScreenTimeoutPolicyChanges(Display.DEFAULT_DISPLAY,
+ SCREEN_TIMEOUT_KEEP_DISPLAY_ON);
+ mTestLooper.dispatchAll();
+
+ // Callback should not be fired as binder died
+ verify(listener, never()).onScreenTimeoutPolicyChanged(anyInt());
+ }
+
+ @Test
+ public void testScreenTimeoutListener_listenerThrowsException_listenerNotFiredSecondTime()
+ throws Exception {
+ createNotifier();
+
+ final IScreenTimeoutPolicyListener listener = Mockito.mock(
+ IScreenTimeoutPolicyListener.class);
+ final IBinder listenerBinder = Mockito.mock(IBinder.class);
+ when(listener.asBinder()).thenReturn(listenerBinder);
+ doThrow(RuntimeException.class).when(listener).onScreenTimeoutPolicyChanged(anyInt());
+ mNotifier.addScreenTimeoutPolicyListener(Display.DEFAULT_DISPLAY_GROUP,
+ SCREEN_TIMEOUT_ACTIVE, listener);
+ mTestLooper.dispatchAll();
+ clearInvocations(listener);
+
+ mNotifier.notifyScreenTimeoutPolicyChanges(Display.DEFAULT_DISPLAY,
+ SCREEN_TIMEOUT_KEEP_DISPLAY_ON);
+ mTestLooper.dispatchAll();
+
+ // Callback should not be fired as it has thrown an exception once
+ verify(listener, never()).onScreenTimeoutPolicyChanged(anyInt());
+ }
+
+ @Test
+ public void testScreenTimeoutListener_nonDefaultDisplay_stillReportsPolicyCorrectly()
+ throws Exception {
+ createNotifier();
+ final int otherDisplayId = 123;
+ final int otherDisplayGroupId = 123_00;
+ when(mDisplayManagerInternal.getGroupIdForDisplay(otherDisplayId)).thenReturn(
+ otherDisplayGroupId);
+ final IScreenTimeoutPolicyListener listener = Mockito.mock(
+ IScreenTimeoutPolicyListener.class);
+ final IBinder listenerBinder = Mockito.mock(IBinder.class);
+ when(listener.asBinder()).thenReturn(listenerBinder);
+ mNotifier.addScreenTimeoutPolicyListener(otherDisplayId,
+ SCREEN_TIMEOUT_ACTIVE, listener);
+ mTestLooper.dispatchAll();
+ clearInvocations(listener);
+
+ mNotifier.notifyScreenTimeoutPolicyChanges(otherDisplayGroupId,
+ SCREEN_TIMEOUT_KEEP_DISPLAY_ON);
+ mTestLooper.dispatchAll();
+
+ verify(listener).onScreenTimeoutPolicyChanged(SCREEN_TIMEOUT_KEEP_DISPLAY_ON);
+ }
+
+ @Test
+ public void testScreenTimeoutListener_timeoutPolicyTimeout_reportsTimeoutOnSubscription()
+ throws Exception {
+ createNotifier();
+ final IScreenTimeoutPolicyListener listener = Mockito.mock(
+ IScreenTimeoutPolicyListener.class);
+ final IBinder listenerBinder = Mockito.mock(IBinder.class);
+ when(listener.asBinder()).thenReturn(listenerBinder);
+
+ mNotifier.addScreenTimeoutPolicyListener(Display.DEFAULT_DISPLAY,
+ SCREEN_TIMEOUT_ACTIVE, listener);
+ mTestLooper.dispatchAll();
+
+ verify(listener).onScreenTimeoutPolicyChanged(SCREEN_TIMEOUT_ACTIVE);
+ }
+
+ @Test
+ public void testScreenTimeoutListener_policyHeld_reportsHeldOnSubscription()
+ throws Exception {
+ createNotifier();
+ final IScreenTimeoutPolicyListener listener = Mockito.mock(
+ IScreenTimeoutPolicyListener.class);
+ final IBinder listenerBinder = Mockito.mock(IBinder.class);
+ when(listener.asBinder()).thenReturn(listenerBinder);
+
+ mNotifier.addScreenTimeoutPolicyListener(Display.DEFAULT_DISPLAY,
+ SCREEN_TIMEOUT_KEEP_DISPLAY_ON, listener);
+ mTestLooper.dispatchAll();
+
+ verify(listener).onScreenTimeoutPolicyChanged(SCREEN_TIMEOUT_KEEP_DISPLAY_ON);
+ }
+
private final PowerManagerService.Injector mInjector = new PowerManagerService.Injector() {
@Override
Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
diff --git a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
index 376091e4a241..3cb27451bd57 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -20,6 +20,8 @@ import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_RECEIVER;
import static android.app.ActivityManager.PROCESS_STATE_TOP_SLEEPING;
+import static android.os.PowerManager.SCREEN_TIMEOUT_KEEP_DISPLAY_ON;
+import static android.os.PowerManager.SCREEN_TIMEOUT_ACTIVE;
import static android.os.PowerManager.USER_ACTIVITY_EVENT_BUTTON;
import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
@@ -69,6 +71,7 @@ import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback;
import android.hardware.display.AmbientDisplayConfiguration;
+import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.power.Boost;
import android.hardware.power.Mode;
@@ -79,6 +82,7 @@ import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.IWakeLockCallback;
+import android.os.IScreenTimeoutPolicyListener;
import android.os.Looper;
import android.os.PowerManager;
import android.os.PowerManagerInternal;
@@ -132,6 +136,7 @@ import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@@ -166,6 +171,7 @@ public class PowerManagerServiceTest {
@Mock private BatterySaverStateMachine mBatterySaverStateMachineMock;
@Mock private LightsManager mLightsManagerMock;
@Mock private DisplayManagerInternal mDisplayManagerInternalMock;
+ @Mock private DisplayManager mDisplayManagerMock;
@Mock private BatteryManagerInternal mBatteryManagerInternalMock;
@Mock private ActivityManagerInternal mActivityManagerInternalMock;
@Mock private AttentionManagerInternal mAttentionManagerInternalMock;
@@ -185,6 +191,8 @@ public class PowerManagerServiceTest {
@Mock private DeviceStateManager mDeviceStateManagerMock;
@Mock private DeviceConfigParameterProvider mDeviceParameterProvider;
+ @Captor private ArgumentCaptor<DisplayManager.DisplayListener> mDisplayListenerArgumentCaptor;
+
@Rule public TestRule compatChangeRule = new PlatformCompatChangeRule();
@Rule public SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@@ -254,6 +262,7 @@ public class PowerManagerServiceTest {
mContextSpy = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
mResourcesSpy = spy(mContextSpy.getResources());
when(mContextSpy.getResources()).thenReturn(mResourcesSpy);
+ when(mContextSpy.getSystemService(DisplayManager.class)).thenReturn(mDisplayManagerMock);
setBatterySaverSupported();
MockContentResolver cr = new MockContentResolver(mContextSpy);
@@ -2947,15 +2956,19 @@ public class PowerManagerServiceTest {
assertThat(mService.getPowerGroupSize()).isEqualTo(4);
}
- private WakeLock acquireWakeLock(String tag, int flags) {
+ private WakeLock acquireWakeLock(String tag, int flags, int displayId) {
IBinder token = new Binder();
String packageName = "pkg.name";
mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
- null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY,
+ null /* workSource */, null /* historyTag */, displayId,
null /* callback */);
return mService.findWakeLockLocked(token);
}
+ private WakeLock acquireWakeLock(String tag, int flags) {
+ return acquireWakeLock(tag, flags, Display.INVALID_DISPLAY);
+ }
+
/**
* Test IPowerManager.acquireWakeLock() with a IWakeLockCallback.
*/
@@ -3443,6 +3456,106 @@ public class PowerManagerServiceTest {
}
@Test
+ public void testAddWakeLockKeepingScreenOn_addsToNotifierAndReportsTimeoutPolicyChange() {
+ IntArray displayGroupIds = IntArray.wrap(new int[]{Display.DEFAULT_DISPLAY_GROUP});
+ when(mDisplayManagerInternalMock.getDisplayGroupIds()).thenReturn(displayGroupIds);
+
+ final DisplayInfo displayInfo = new DisplayInfo();
+ displayInfo.displayGroupId = Display.DEFAULT_DISPLAY_GROUP;
+ when(mDisplayManagerInternalMock.getDisplayInfo(Display.DEFAULT_DISPLAY))
+ .thenReturn(displayInfo);
+
+ createService();
+ startSystem();
+
+ final IScreenTimeoutPolicyListener listener = Mockito.mock(
+ IScreenTimeoutPolicyListener.class);
+ mService.getBinderServiceInstance().addScreenTimeoutPolicyListener(
+ Display.DEFAULT_DISPLAY_GROUP, listener);
+ verify(mNotifierMock).addScreenTimeoutPolicyListener(Display.DEFAULT_DISPLAY_GROUP,
+ SCREEN_TIMEOUT_ACTIVE, listener);
+ clearInvocations(mNotifierMock);
+
+ acquireWakeLock("screenBright", PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
+ Display.DEFAULT_DISPLAY);
+ verify(mNotifierMock).notifyScreenTimeoutPolicyChanges(Display.DEFAULT_DISPLAY_GROUP,
+ SCREEN_TIMEOUT_KEEP_DISPLAY_ON);
+ }
+
+ @Test
+ public void test_addAndRemoveScreenTimeoutListener_propagatesToNotifier()
+ throws Exception {
+ IntArray displayGroupIds = IntArray.wrap(new int[]{Display.DEFAULT_DISPLAY_GROUP});
+ when(mDisplayManagerInternalMock.getDisplayGroupIds()).thenReturn(displayGroupIds);
+
+ final DisplayInfo displayInfo = new DisplayInfo();
+ displayInfo.displayGroupId = Display.DEFAULT_DISPLAY_GROUP;
+ when(mDisplayManagerInternalMock.getDisplayInfo(Display.DEFAULT_DISPLAY))
+ .thenReturn(displayInfo);
+
+ createService();
+ startSystem();
+
+ final IScreenTimeoutPolicyListener listener = Mockito.mock(
+ IScreenTimeoutPolicyListener.class);
+ mService.getBinderServiceInstance().addScreenTimeoutPolicyListener(
+ Display.DEFAULT_DISPLAY, listener);
+
+ clearInvocations(mNotifierMock);
+ mService.getBinderServiceInstance().removeScreenTimeoutPolicyListener(
+ Display.DEFAULT_DISPLAY, listener);
+ verify(mNotifierMock).removeScreenTimeoutPolicyListener(Display.DEFAULT_DISPLAY,
+ listener);
+ }
+
+ @Test
+ public void test_displayIsRemoved_clearsScreenTimeoutListeners()
+ throws Exception {
+ IntArray displayGroupIds = IntArray.wrap(new int[]{Display.DEFAULT_DISPLAY_GROUP});
+ when(mDisplayManagerInternalMock.getDisplayGroupIds()).thenReturn(displayGroupIds);
+
+ final DisplayInfo displayInfo = new DisplayInfo();
+ displayInfo.displayGroupId = Display.DEFAULT_DISPLAY_GROUP;
+ when(mDisplayManagerInternalMock.getDisplayInfo(Display.DEFAULT_DISPLAY))
+ .thenReturn(displayInfo);
+
+ createService();
+ startSystem();
+ verify(mDisplayManagerMock).registerDisplayListener(
+ mDisplayListenerArgumentCaptor.capture(), any());
+ clearInvocations(mNotifierMock);
+
+ mDisplayListenerArgumentCaptor.getValue().onDisplayRemoved(Display.DEFAULT_DISPLAY);
+
+ verify(mNotifierMock).clearScreenTimeoutPolicyListeners(Display.DEFAULT_DISPLAY);
+ }
+
+ @Test
+ public void testScreenWakeLockListener_screenHasWakelocks_addsWithHeldTimeoutPolicyToNotifier()
+ throws Exception {
+ IntArray displayGroupIds = IntArray.wrap(new int[]{Display.DEFAULT_DISPLAY_GROUP});
+ when(mDisplayManagerInternalMock.getDisplayGroupIds()).thenReturn(displayGroupIds);
+
+ final DisplayInfo displayInfo = new DisplayInfo();
+ displayInfo.displayGroupId = Display.DEFAULT_DISPLAY_GROUP;
+ when(mDisplayManagerInternalMock.getDisplayInfo(Display.DEFAULT_DISPLAY))
+ .thenReturn(displayInfo);
+
+ createService();
+ startSystem();
+
+ acquireWakeLock("screenBright", PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
+ Display.DEFAULT_DISPLAY);
+
+ final IScreenTimeoutPolicyListener listener = Mockito.mock(
+ IScreenTimeoutPolicyListener.class);
+ mService.getBinderServiceInstance().addScreenTimeoutPolicyListener(
+ Display.DEFAULT_DISPLAY_GROUP, listener);
+ verify(mNotifierMock).notifyScreenTimeoutPolicyChanges(Display.DEFAULT_DISPLAY_GROUP,
+ SCREEN_TIMEOUT_KEEP_DISPLAY_ON);
+ }
+
+ @Test
public void testHalAutoSuspendMode_enabledByConfiguration() {
AtomicReference<DisplayManagerInternal.DisplayPowerCallbacks> callback =
new AtomicReference<>();