diff options
4 files changed, 272 insertions, 39 deletions
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java index 84b6da8ef17e..111caefa34da 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController2.java +++ b/services/core/java/com/android/server/display/DisplayPowerController2.java @@ -71,6 +71,7 @@ import com.android.server.display.brightness.BrightnessReason;  import com.android.server.display.brightness.DisplayBrightnessController;  import com.android.server.display.color.ColorDisplayService.ColorDisplayServiceInternal;  import com.android.server.display.color.ColorDisplayService.ReduceBrightColorsListener; +import com.android.server.display.state.DisplayStateController;  import com.android.server.display.utils.SensorUtils;  import com.android.server.display.whitebalance.DisplayWhiteBalanceController;  import com.android.server.display.whitebalance.DisplayWhiteBalanceFactory; @@ -346,6 +347,9 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal      // Tracks and manages the proximity state of the associated display.      private final DisplayPowerProximityStateController mDisplayPowerProximityStateController; +    // Tracks and manages the display state of the associated display. +    private final DisplayStateController mDisplayStateController; +      // A record of state for skipping brightness ramps.      private int mSkipRampState = RAMP_STATE_SKIP_NONE; @@ -436,6 +440,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal          mDisplayPowerProximityStateController = mInjector.getDisplayPowerProximityStateController(                  mWakelockController, mDisplayDeviceConfig, mHandler.getLooper(),                  () -> updatePowerState(), mDisplayId, mSensorManager); +        mDisplayStateController = new DisplayStateController(mDisplayPowerProximityStateController);          mTag = "DisplayPowerController2[" + mDisplayId + "]";          mDisplayDevice = mLogicalDisplay.getPrimaryDisplayDeviceLocked(); @@ -1128,39 +1133,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal              mustNotify = !mDisplayReadyLocked;          } -        // Compute the basic display state using the policy. -        // We might override this below based on other factors. -        // Initialise brightness as invalid. -        int state; -        boolean performScreenOffTransition = false; -        switch (mPowerRequest.policy) { -            case DisplayPowerRequest.POLICY_OFF: -                state = Display.STATE_OFF; -                performScreenOffTransition = true; -                break; -            case DisplayPowerRequest.POLICY_DOZE: -                if (mPowerRequest.dozeScreenState != Display.STATE_UNKNOWN) { -                    state = mPowerRequest.dozeScreenState; -                } else { -                    state = Display.STATE_DOZE; -                } -                break; -            case DisplayPowerRequest.POLICY_DIM: -            case DisplayPowerRequest.POLICY_BRIGHT: -            default: -                state = Display.STATE_ON; -                break; -        } -        assert (state != Display.STATE_UNKNOWN); - -        mDisplayPowerProximityStateController.updateProximityState(mPowerRequest, state); - -        if (!mIsEnabled -                || mIsInTransition -                || mDisplayPowerProximityStateController.isScreenOffBecauseOfProximity()) { -            state = Display.STATE_OFF; -        } - +        int state = mDisplayStateController +                .updateDisplayState(mPowerRequest, mIsEnabled, mIsInTransition);          // Initialize things the first time the power state is changed.          if (mustInitialize) {              initialize(state); @@ -1170,7 +1144,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal          // The transition may be deferred, so after this point we will use the          // actual state instead of the desired one.          final int oldState = mPowerState.getScreenState(); -        animateScreenStateChange(state, performScreenOffTransition); +        animateScreenStateChange(state, mDisplayStateController.shouldPerformScreenOffTransition());          state = mPowerState.getScreenState();          DisplayBrightnessState displayBrightnessState = mDisplayBrightnessController @@ -2293,10 +2267,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal          if (mDisplayBrightnessController != null) {              mDisplayBrightnessController.dump(pw);          } - -        if (mDisplayPowerProximityStateController != null) { -            mDisplayPowerProximityStateController.dumpLocal(pw); -        }      } diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index c7b27deb420d..ad426b5e00a2 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -66,7 +66,6 @@ import java.util.Objects;   */  final class LogicalDisplay {      private static final String TAG = "LogicalDisplay"; -      // The layer stack we use when the display has been blanked to prevent any      // of its content from appearing.      private static final int BLANK_LAYER_STACK = -1; diff --git a/services/core/java/com/android/server/display/state/DisplayStateController.java b/services/core/java/com/android/server/display/state/DisplayStateController.java new file mode 100644 index 000000000000..546478e480e0 --- /dev/null +++ b/services/core/java/com/android/server/display/state/DisplayStateController.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2022 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.display.state; + +import android.hardware.display.DisplayManagerInternal; +import android.util.IndentingPrintWriter; +import android.view.Display; + +import com.android.server.display.DisplayPowerProximityStateController; + +import java.io.PrintWriter; + +/** + * Maintains the DisplayState of the system. + * Internally, this accounts for the proximity changes, and notifying the system + * clients about the changes + */ +public class DisplayStateController { +    private DisplayPowerProximityStateController mDisplayPowerProximityStateController; +    private boolean mPerformScreenOffTransition = false; + +    public DisplayStateController(DisplayPowerProximityStateController +            displayPowerProximityStateController) { +        this.mDisplayPowerProximityStateController = displayPowerProximityStateController; +    } + +    /** +     * Updates the DisplayState and notifies the system. Also accounts for the +     * events being emitted by the proximity sensors +     * +     * @param displayPowerRequest   The request to update the display state +     * @param isDisplayEnabled      A boolean flag representing if the display is enabled +     * @param isDisplayInTransition A boolean flag representing if the display is undergoing the +     *                              transition phase +     */ +    public int updateDisplayState(DisplayManagerInternal.DisplayPowerRequest displayPowerRequest, +            boolean isDisplayEnabled, boolean isDisplayInTransition) { +        mPerformScreenOffTransition = false; +        // Compute the basic display state using the policy. +        // We might override this below based on other factors. +        // Initialise brightness as invalid. +        int state; +        switch (displayPowerRequest.policy) { +            case DisplayManagerInternal.DisplayPowerRequest.POLICY_OFF: +                state = Display.STATE_OFF; +                mPerformScreenOffTransition = true; +                break; +            case DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE: +                if (displayPowerRequest.dozeScreenState != Display.STATE_UNKNOWN) { +                    state = displayPowerRequest.dozeScreenState; +                } else { +                    state = Display.STATE_DOZE; +                } +                break; +            case DisplayManagerInternal.DisplayPowerRequest.POLICY_DIM: +            case DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT: +            default: +                state = Display.STATE_ON; +                break; +        } +        assert (state != Display.STATE_UNKNOWN); + +        mDisplayPowerProximityStateController.updateProximityState(displayPowerRequest, state); + +        if (!isDisplayEnabled || isDisplayInTransition +                || mDisplayPowerProximityStateController.isScreenOffBecauseOfProximity()) { +            state = Display.STATE_OFF; +        } + +        return state; +    } + +    /** +     * Checks if the screen off transition is to be performed or not. +     */ +    public boolean shouldPerformScreenOffTransition() { +        return mPerformScreenOffTransition; +    } + +    /** +     * Used to dump the state. +     * +     * @param pw The PrintWriter used to dump the state. +     */ +    public void dumpsys(PrintWriter pw) { +        pw.println(); +        pw.println("DisplayPowerProximityStateController:"); +        pw.println("  mPerformScreenOffTransition:" + mPerformScreenOffTransition); +        IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); +        if (mDisplayPowerProximityStateController != null) { +            mDisplayPowerProximityStateController.dumpLocal(ipw); +        } +    } +} diff --git a/services/tests/mockingservicestests/src/com/android/server/display/state/DisplayStateControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/state/DisplayStateControllerTest.java new file mode 100644 index 000000000000..880501f39ac2 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/display/state/DisplayStateControllerTest.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2022 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.display.state; + + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.hardware.display.DisplayManagerInternal; +import android.view.Display; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.server.display.DisplayPowerProximityStateController; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public final class DisplayStateControllerTest { +    private static final boolean DISPLAY_ENABLED = true; +    private static final boolean DISPLAY_IN_TRANSITION = true; + +    private DisplayStateController mDisplayStateController; + +    @Mock +    private DisplayPowerProximityStateController mDisplayPowerProximityStateController; + +    @Before +    public void before() { +        MockitoAnnotations.initMocks(this); +        mDisplayStateController = new DisplayStateController(mDisplayPowerProximityStateController); +    } + +    @Test +    public void updateProximityStateEvaluatesStateOffPolicyAsExpected() { +        when(mDisplayPowerProximityStateController.isScreenOffBecauseOfProximity()).thenReturn( +                false); +        DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock( +                DisplayManagerInternal.DisplayPowerRequest.class); + +        displayPowerRequest.policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_OFF; +        int state = mDisplayStateController.updateDisplayState(displayPowerRequest, DISPLAY_ENABLED, +                !DISPLAY_IN_TRANSITION); +        assertEquals(Display.STATE_OFF, state); +        verify(mDisplayPowerProximityStateController).updateProximityState(displayPowerRequest, +                Display.STATE_OFF); +        assertEquals(true, mDisplayStateController.shouldPerformScreenOffTransition()); +    } + +    @Test +    public void updateProximityStateEvaluatesDozePolicyAsExpected() { +        when(mDisplayPowerProximityStateController.isScreenOffBecauseOfProximity()).thenReturn( +                false); +        validDisplayState(DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE, +                Display.STATE_DOZE, DISPLAY_ENABLED, !DISPLAY_IN_TRANSITION); +    } + +    @Test +    public void updateProximityStateEvaluatesDimPolicyAsExpected() { +        when(mDisplayPowerProximityStateController.isScreenOffBecauseOfProximity()).thenReturn( +                false); +        validDisplayState(DisplayManagerInternal.DisplayPowerRequest.POLICY_DIM, +                Display.STATE_ON, DISPLAY_ENABLED, !DISPLAY_IN_TRANSITION); +    } + +    @Test +    public void updateProximityStateEvaluatesDimBrightAsExpected() { +        when(mDisplayPowerProximityStateController.isScreenOffBecauseOfProximity()).thenReturn( +                false); +        validDisplayState(DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT, +                Display.STATE_ON, DISPLAY_ENABLED, !DISPLAY_IN_TRANSITION); +    } + +    @Test +    public void updateProximityStateWorksAsExpectedWhenDisplayDisabled() { +        when(mDisplayPowerProximityStateController.isScreenOffBecauseOfProximity()).thenReturn( +                false); +        DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock( +                DisplayManagerInternal.DisplayPowerRequest.class); + +        displayPowerRequest.policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT; +        int state = mDisplayStateController.updateDisplayState(displayPowerRequest, +                !DISPLAY_ENABLED, !DISPLAY_IN_TRANSITION); +        assertEquals(Display.STATE_OFF, state); +        verify(mDisplayPowerProximityStateController).updateProximityState(displayPowerRequest, +                Display.STATE_ON); +        assertEquals(false, mDisplayStateController.shouldPerformScreenOffTransition()); +    } + +    @Test +    public void updateProximityStateWorksAsExpectedWhenTransitionPhase() { +        when(mDisplayPowerProximityStateController.isScreenOffBecauseOfProximity()).thenReturn( +                false); +        DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock( +                DisplayManagerInternal.DisplayPowerRequest.class); + +        displayPowerRequest.policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT; +        int state = mDisplayStateController.updateDisplayState(displayPowerRequest, DISPLAY_ENABLED, +                DISPLAY_IN_TRANSITION); +        assertEquals(Display.STATE_OFF, state); +        verify(mDisplayPowerProximityStateController).updateProximityState(displayPowerRequest, +                Display.STATE_ON); +        assertEquals(false, mDisplayStateController.shouldPerformScreenOffTransition()); +    } + +    @Test +    public void updateProximityStateWorksAsExpectedWhenScreenOffBecauseOfProximity() { +        when(mDisplayPowerProximityStateController.isScreenOffBecauseOfProximity()).thenReturn( +                true); +        DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock( +                DisplayManagerInternal.DisplayPowerRequest.class); + +        displayPowerRequest.policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT; +        int state = mDisplayStateController.updateDisplayState(displayPowerRequest, DISPLAY_ENABLED, +                !DISPLAY_IN_TRANSITION); +        assertEquals(Display.STATE_OFF, state); +        verify(mDisplayPowerProximityStateController).updateProximityState(displayPowerRequest, +                Display.STATE_ON); +        assertEquals(false, mDisplayStateController.shouldPerformScreenOffTransition()); +    } + +    private void validDisplayState(int policy, int displayState, boolean isEnabled, +            boolean isInTransition) { +        DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock( +                DisplayManagerInternal.DisplayPowerRequest.class); +        displayPowerRequest.policy = policy; +        int state = mDisplayStateController.updateDisplayState(displayPowerRequest, isEnabled, +                isInTransition); +        assertEquals(displayState, state); +        verify(mDisplayPowerProximityStateController).updateProximityState(displayPowerRequest, +                displayState); +        assertEquals(false, mDisplayStateController.shouldPerformScreenOffTransition()); +    } +}  |