Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fd8b5efc authored by Oleg Blinnikov's avatar Oleg Blinnikov
Browse files

API and adb command to power display off

Change-Id: I52a3900263e85f85731114695ab61aedc649e1bf
Test: atest DisplayManagerServiceTest
Test: adb shell cmd display power-off 0
Test: adb shell cmd display power-on 0
Bug: 292300981
parent 52ad3e2a
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -548,6 +548,20 @@ public final class DisplayManagerGlobal {
        }
    }

    /**
     * Request to power a display ON or OFF.
     * @hide
     */
    @RequiresPermission("android.permission.MANAGE_DISPLAYS")
    public boolean requestDisplayPower(int displayId, boolean on) {
        try {
            return mDm.requestDisplayPower(displayId, on);
        } catch (RemoteException ex) {
            Log.e(TAG, "Error trying to request display power " + on, ex);
            return false;
        }
    }

    public void startWifiDisplayScan() {
        synchronized (mLock) {
            if (mWifiDisplayScanNestCount++ == 0) {
+4 −0
Original line number Diff line number Diff line
@@ -236,6 +236,10 @@ interface IDisplayManager {
    @EnforcePermission("MANAGE_DISPLAYS")
    void disableConnectedDisplay(int displayId);

    // Request to power display ON or OFF.
    @EnforcePermission("MANAGE_DISPLAYS")
    boolean requestDisplayPower(int displayId, boolean on);

    // Restricts display modes to specified modeIds.
    @EnforcePermission("RESTRICT_DISPLAY_MODES")
    void requestDisplayModes(in IBinder token, int displayId, in @nullable int[] modeIds);
+31 −0
Original line number Diff line number Diff line
@@ -3404,6 +3404,31 @@ public final class DisplayManagerService extends SystemService {
        }
    }

    boolean requestDisplayPower(int displayId, boolean on) {
        synchronized (mSyncRoot) {
            final var display = mLogicalDisplayMapper.getDisplayLocked(displayId);
            if (display == null) {
                Slog.w(TAG, "requestDisplayPower: Cannot find a display with displayId="
                        + displayId);
                return false;
            }
            final BrightnessPair brightnessPair = mDisplayBrightnesses.get(displayId);
            var runnable = display.getPrimaryDisplayDeviceLocked().requestDisplayStateLocked(
                    on ? Display.STATE_ON : Display.STATE_OFF,
                    on ? brightnessPair.brightness : PowerManager.BRIGHTNESS_OFF_FLOAT,
                    brightnessPair.sdrBrightness,
                    display.getDisplayOffloadSessionLocked());
            if (runnable == null) {
                Slog.w(TAG, "requestDisplayPower: Cannot update the power state to ON=" + on
                        + " for a display with displayId=" + displayId + ", runnable is null");
                return false;
            }
            runnable.run();
            Slog.i(TAG, "requestDisplayPower(displayId=" + displayId + ", on=" + on + ")");
        }
        return true;
    }

    /**
     * This is the object that everything in the display manager locks on.
     * We make it an inner class within the {@link DisplayManagerService} to so that it is
@@ -4627,6 +4652,12 @@ public final class DisplayManagerService extends SystemService {
            DisplayManagerService.this.enableConnectedDisplay(displayId, false);
        }

        @EnforcePermission(MANAGE_DISPLAYS)
        public boolean requestDisplayPower(int displayId, boolean on) {
            requestDisplayPower_enforcePermission();
            return DisplayManagerService.this.requestDisplayPower(displayId, on);
        }

        @EnforcePermission(RESTRICT_DISPLAY_MODES)
        @Override // Binder call
        public void requestDisplayModes(IBinder token, int displayId, @Nullable int[] modeIds) {
+21 −0
Original line number Diff line number Diff line
@@ -106,6 +106,10 @@ class DisplayManagerShellCommand extends ShellCommand {
                return setDisplayEnabled(true);
            case "disable-display":
                return setDisplayEnabled(false);
            case "power-on":
                return requestDisplayPower(true);
            case "power-off":
                return requestDisplayPower(false);
            default:
                return handleDefaultCommands(cmd);
        }
@@ -592,4 +596,21 @@ class DisplayManagerShellCommand extends ShellCommand {
        mService.enableConnectedDisplay(displayId, enable);
        return 0;
    }

    private int requestDisplayPower(boolean enable) {
        final String displayIdText = getNextArg();
        if (displayIdText == null) {
            getErrPrintWriter().println("Error: no displayId specified");
            return 1;
        }
        final int displayId;
        try {
            displayId = Integer.parseInt(displayIdText);
        } catch (NumberFormatException e) {
            getErrPrintWriter().println("Error: invalid displayId: '" + displayIdText + "'");
            return 1;
        }
        mService.requestDisplayPower(displayId, enable);
        return 0;
    }
}
+67 −0
Original line number Diff line number Diff line
@@ -2568,6 +2568,63 @@ public class DisplayManagerServiceTest {
                EVENT_DISPLAY_ADDED).inOrder();
    }

    @Test
    public void testPowerOnAndOffInternalDisplay() {
        manageDisplaysPermission(/* granted= */ true);
        DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
        DisplayManagerService.BinderService bs = displayManager.new BinderService();
        LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
        FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
        bs.registerCallbackWithEventMask(callback, STANDARD_AND_CONNECTION_DISPLAY_EVENTS);

        callback.expectsEvent(EVENT_DISPLAY_ADDED);
        FakeDisplayDevice displayDevice =
                createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
        callback.waitForExpectedEvent();

        LogicalDisplay display =
                logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);

        assertThat(displayDevice.getDisplayDeviceInfoLocked().committedState)
                .isEqualTo(Display.STATE_ON);

        assertThat(displayManager.requestDisplayPower(display.getDisplayIdLocked(), false))
                .isTrue();

        assertThat(displayDevice.getDisplayDeviceInfoLocked().committedState)
                .isEqualTo(Display.STATE_OFF);

        assertThat(displayManager.requestDisplayPower(display.getDisplayIdLocked(), true))
                .isTrue();

        assertThat(displayDevice.getDisplayDeviceInfoLocked().committedState)
                .isEqualTo(Display.STATE_ON);
    }

    @Test
    public void testPowerOnAndOffInternalDisplay_withoutPermission_shouldThrowException() {
        DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
        DisplayManagerService.BinderService bs = displayManager.new BinderService();
        LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
        FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
        bs.registerCallbackWithEventMask(callback, STANDARD_AND_CONNECTION_DISPLAY_EVENTS);

        callback.expectsEvent(EVENT_DISPLAY_ADDED);
        FakeDisplayDevice displayDevice =
                createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
        callback.waitForExpectedEvent();

        LogicalDisplay display =
                logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
        var displayId = display.getDisplayIdLocked();

        assertThat(displayDevice.getDisplayDeviceInfoLocked().committedState)
                .isEqualTo(Display.STATE_ON);

        assertThrows(SecurityException.class, () -> bs.requestDisplayPower(displayId, true));
        assertThrows(SecurityException.class, () -> bs.requestDisplayPower(displayId, false));
    }

    @Test
    public void testEnableExternalDisplay_withDisplayManagement_shouldSignalDisplayAdded() {
        when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true);
@@ -3529,6 +3586,7 @@ public class DisplayManagerServiceTest {

        public void setDisplayDeviceInfo(DisplayDeviceInfo displayDeviceInfo) {
            mDisplayDeviceInfo = displayDeviceInfo;
            mDisplayDeviceInfo.committedState = Display.STATE_ON;
        }

        @Override
@@ -3558,5 +3616,14 @@ public class DisplayManagerServiceTest {
        public Display.Mode getUserPreferredDisplayModeLocked() {
            return mPreferredMode;
        }

        @Override
        public Runnable requestDisplayStateLocked(
                final int state,
                final float brightnessState,
                final float sdrBrightnessState,
                @Nullable DisplayOffloadSessionImpl displayOffloadSession) {
            return () -> mDisplayDeviceInfo.committedState = state;
        }
    }
}