diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl index f1e3ab07686b7..12cf12c14d084 100644 --- a/core/java/android/os/IPowerManager.aidl +++ b/core/java/android/os/IPowerManager.aidl @@ -48,6 +48,8 @@ interface IPowerManager void wakeUp(long time, int reason, String details, String opPackageName); @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) void goToSleep(long time, int reason, int flags); + @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) + void goToSleepWithDisplayId(int displayId, long time, int reason, int flags); @UnsupportedAppUsage(maxTargetSdk = 28) void nap(long time); float getBrightnessConstraint(int constraint); diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 90502af40eb88..d1ef8d6c8c17d 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -1501,6 +1501,43 @@ public final class PowerManager { } } + /** + * Forces the {@link com.android.server.display.DisplayGroup} of the provided {@code displayId} + * to turn off. + * + *
If the {@link com.android.server.display.DisplayGroup} of the provided {@code displayId} + * is turned on it will be turned off. If all displays are off as a result of this action the + * device will be put to sleep. If the {@link com.android.server.display.DisplayGroup} of + * the provided {@code displayId} is already off then nothing will happen. + * + *
Overrides all the wake locks that are held. + * This is what happens when the power key is pressed to turn off the screen. + * + *
Requires the {@link android.Manifest.permission#DEVICE_POWER} permission. + * + * @param displayId The display ID to turn off. If {@code displayId} is + * {@link Display#INVALID_DISPLAY}, then all displays are turned off. + * @param time The time when the request to go to sleep was issued, in the + * {@link SystemClock#uptimeMillis()} time base. This timestamp is used to correctly + * order the go to sleep request with other power management functions. It should be set + * to the timestamp of the input event that caused the request to go to sleep. + * @param reason The reason the device is going to sleep. + * @param flags Optional flags to apply when going to sleep. + * + * @see #userActivity + * @see #wakeUp + * + * @hide Requires signature permission. + */ + @RequiresPermission(android.Manifest.permission.DEVICE_POWER) + public void goToSleep(int displayId, long time, @GoToSleepReason int reason, int flags) { + try { + mService.goToSleepWithDisplayId(displayId, time, reason, flags); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Forces the {@link android.view.Display#DEFAULT_DISPLAY_GROUP default display group} * to turn on. diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 6fa7920ab4d7e..52f82b2f6b5dc 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -283,6 +283,10 @@ public final class PowerManagerService extends SystemService private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS"); + /** Display group IDs representing only DEFAULT_DISPLAY_GROUP. */ + private static final IntArray DEFAULT_DISPLAY_GROUP_IDS = + IntArray.wrap(new int[]{Display.DEFAULT_DISPLAY_GROUP}); + private final Context mContext; private final ServiceThread mHandlerThread; private final Handler mHandler; @@ -5731,33 +5735,29 @@ public final class PowerManagerService extends SystemService } @Override // Binder call + @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void goToSleep(long eventTime, int reason, int flags) { - if (eventTime > mClock.uptimeMillis()) { - throw new IllegalArgumentException("event time must not be in the future"); - } + goToSleepInternal(DEFAULT_DISPLAY_GROUP_IDS, eventTime, reason, flags); + } - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.DEVICE_POWER, null); + @Override // Binder call + @RequiresPermission(android.Manifest.permission.DEVICE_POWER) + public void goToSleepWithDisplayId(int displayId, long eventTime, int reason, int flags) { + IntArray groupIds; - final int uid = Binder.getCallingUid(); - final long ident = Binder.clearCallingIdentity(); - try { - synchronized (mLock) { - PowerGroup defaultPowerGroup = mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP); - if ((flags & PowerManager.GO_TO_SLEEP_FLAG_SOFT_SLEEP) != 0) { - if (defaultPowerGroup.hasWakeLockKeepingScreenOnLocked()) { - return; - } - } - if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) { - sleepPowerGroupLocked(defaultPowerGroup, eventTime, reason, uid); - } else { - dozePowerGroupLocked(defaultPowerGroup, eventTime, reason, uid); - } + if (displayId == Display.INVALID_DISPLAY) { + groupIds = mDisplayManagerInternal.getDisplayGroupIds(); + } else { + DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(displayId); + Preconditions.checkArgument(displayInfo != null, "display ID(%d) doesn't exist", + displayId); + int groupId = displayInfo.displayGroupId; + if (groupId == Display.INVALID_DISPLAY_GROUP) { + throw new IllegalArgumentException("invalid display group ID"); } - } finally { - Binder.restoreCallingIdentity(ident); + groupIds = IntArray.wrap(new int[]{groupId}); } + goToSleepInternal(groupIds, eventTime, reason, flags); } @Override // Binder call @@ -6553,6 +6553,44 @@ public final class PowerManagerService extends SystemService return false; } + @RequiresPermission(android.Manifest.permission.DEVICE_POWER) + private void goToSleepInternal(IntArray groupIds, long eventTime, int reason, int flags) { + if (eventTime > mClock.uptimeMillis()) { + throw new IllegalArgumentException("event time must not be in the future"); + } + + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, + /* message= */ null); + + boolean isNoDoze = (flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0; + int uid = Binder.getCallingUid(); + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + for (int i = 0; i < groupIds.size(); i++) { + int groupId = groupIds.get(i); + PowerGroup powerGroup = mPowerGroups.get(groupId); + if (powerGroup == null) { + throw new IllegalArgumentException("power group(" + groupId + + ") doesn't exist"); + } + if ((flags & PowerManager.GO_TO_SLEEP_FLAG_SOFT_SLEEP) != 0) { + if (powerGroup.hasWakeLockKeepingScreenOnLocked()) { + continue; + } + } + if (isNoDoze) { + sleepPowerGroupLocked(powerGroup, eventTime, reason, uid); + } else { + dozePowerGroupLocked(powerGroup, eventTime, reason, uid); + } + } + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + @VisibleForTesting final class LocalService extends PowerManagerInternal { @Override