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

Commit 81d5a3ee authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Adding Tests for SuspendBlocker.Display usage"

parents 371fa51b d0894ea2
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -2583,8 +2583,8 @@ public final class DisplayManagerService extends SystemService {
        final BrightnessSetting brightnessSetting = new BrightnessSetting(mPersistentDataStore,
                display, mSyncRoot);
        final DisplayPowerController displayPowerController = new DisplayPowerController(
                mContext, mDisplayPowerCallbacks, mPowerHandler, mSensorManager,
                mDisplayBlanker, display, mBrightnessTracker, brightnessSetting,
                mContext, /* injector= */ null, mDisplayPowerCallbacks, mPowerHandler,
                mSensorManager, mDisplayBlanker, display, mBrightnessTracker, brightnessSetting,
                () -> handleBrightnessChange(display));
        mDisplayPowerControllers.append(display.getDisplayIdLocked(), displayPowerController);
    }
+117 −58
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.FloatProperty;
import android.util.Log;
import android.util.MathUtils;
import android.util.MutableFloat;
@@ -58,6 +59,7 @@ import android.view.Display;

import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.display.BrightnessSynchronizer;
import com.android.internal.logging.MetricsLogger;
@@ -256,6 +258,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
    // to reach the final state.
    private final boolean mBrightnessBucketsInDozeConfig;

    private final Clock mClock;
    private final Injector mInjector;

    //  Maximum time a ramp animation can take.
    private long mBrightnessRampIncreaseMaxTimeMillis;
    private long mBrightnessRampDecreaseMaxTimeMillis;
@@ -495,20 +500,22 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
    /**
     * Creates the display power controller.
     */
    public DisplayPowerController(Context context,
    DisplayPowerController(Context context, Injector injector,
            DisplayPowerCallbacks callbacks, Handler handler,
            SensorManager sensorManager, DisplayBlanker blanker, LogicalDisplay logicalDisplay,
            BrightnessTracker brightnessTracker, BrightnessSetting brightnessSetting,
            Runnable onBrightnessChangeRunnable) {

        mInjector = injector != null ? injector : new Injector();
        mClock = mInjector.getClock();
        mLogicalDisplay = logicalDisplay;
        mDisplayId = mLogicalDisplay.getDisplayIdLocked();
        final String displayIdStr = "[" + mDisplayId + "]";
        TAG = "DisplayPowerController" + displayIdStr;
        mSuspendBlockerIdUnfinishedBusiness = displayIdStr + "unfinished business";
        mSuspendBlockerIdOnStateChanged = displayIdStr + "on state changed";
        mSuspendBlockerIdProxPositive = displayIdStr + "prox positive";
        mSuspendBlockerIdProxNegative = displayIdStr + "prox negative";
        mSuspendBlockerIdProxDebounce = displayIdStr + "prox debounce";
        TAG = "DisplayPowerController[" + mDisplayId + "]";
        mSuspendBlockerIdUnfinishedBusiness = getSuspendBlockerUnfinishedBusinessId(mDisplayId);
        mSuspendBlockerIdOnStateChanged = getSuspendBlockerOnStateChangedId(mDisplayId);
        mSuspendBlockerIdProxPositive = getSuspendBlockerProxPositiveId(mDisplayId);
        mSuspendBlockerIdProxNegative = getSuspendBlockerProxNegativeId(mDisplayId);
        mSuspendBlockerIdProxDebounce = getSuspendBlockerProxDebounceId(mDisplayId);

        mDisplayDevice = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
        mUniqueDisplayId = logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId();
@@ -681,6 +688,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call

    /**
     * Get the {@link BrightnessChangeEvent}s for the specified user.
     *
     * @param userId         userId to fetch data for
     * @param includePackage if false will null out the package name in events
     */
@@ -725,7 +733,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
     *
     * @param request                  The requested power state.
     * @param waitForNegativeProximity If true, issues a request to wait for
     * negative proximity before turning the screen back on, assuming the screen
     *                                 negative proximity before turning the screen back on,
     *                                 assuming the screen
     *                                 was turned off by the proximity sensor.
     * @return True if display is ready, false if there are important changes that must
     * be made asynchronously (such as turning the screen on), in which case the caller
@@ -834,7 +843,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
        synchronized (mLock) {
            mStopped = true;
            Message msg = mHandler.obtainMessage(MSG_STOP);
            mHandler.sendMessage(msg);
            mHandler.sendMessageAtTime(msg, mClock.uptimeMillis());

            if (mDisplayWhiteBalanceController != null) {
                mDisplayWhiteBalanceController.setEnabled(false);
@@ -888,12 +897,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
        if (!mStopped && !mPendingUpdatePowerStateLocked) {
            mPendingUpdatePowerStateLocked = true;
            Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);
            mHandler.sendMessage(msg);
            mHandler.sendMessageAtTime(msg, mClock.uptimeMillis());
        }
    }

    private void initialize(int displayState) {
        mPowerState = new DisplayPowerState(mBlanker,
        mPowerState = mInjector.getDisplayPowerState(mBlanker,
                mColorFadeEnabled ? new ColorFade(mDisplayId) : null, mDisplayId, displayState);

        if (mColorFadeEnabled) {
@@ -908,7 +917,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
            mColorFadeOffAnimator.addListener(mAnimatorListener);
        }

        mScreenBrightnessRampAnimator = new DualRampAnimator<>(mPowerState,
        mScreenBrightnessRampAnimator = mInjector.getDualRampAnimator(mPowerState,
                DisplayPowerState.SCREEN_BRIGHTNESS_FLOAT,
                DisplayPowerState.SCREEN_SDR_BRIGHTNESS_FLOAT);
        mScreenBrightnessRampAnimator.setAnimationTimeLimits(
@@ -1077,13 +1086,16 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
        @Override
        public void onAnimationStart(Animator animation) {
        }

        @Override
        public void onAnimationEnd(Animator animation) {
            sendUpdatePowerState();
        }

        @Override
        public void onAnimationRepeat(Animator animation) {
        }

        @Override
        public void onAnimationCancel(Animator animation) {
        }
@@ -2173,8 +2185,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
                mPowerState.dismissColorFadeResources();
            } else if (performScreenOffTransition
                    && mPowerState.prepareColorFade(mContext,
                            mColorFadeFadesConfig ?
                                    ColorFade.MODE_FADE : ColorFade.MODE_COOL_DOWN)
                    mColorFadeFadesConfig
                            ? ColorFade.MODE_FADE : ColorFade.MODE_COOL_DOWN)
                    && mPowerState.getScreenState() != Display.STATE_OFF) {
                // Perform the screen off animation.
                mColorFadeOffAnimator.start();
@@ -2245,7 +2257,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
        if (mProximitySensorEnabled
                && mPendingProximity != PROXIMITY_UNKNOWN
                && mPendingProximityDebounceTime >= 0) {
            final long now = SystemClock.uptimeMillis();
            final long now = mClock.uptimeMillis();
            if (mPendingProximityDebounceTime <= now) {
                if (mProximity != mPendingProximity) {
                    // if the status of the sensor changed, stop ignoring.
@@ -2740,8 +2752,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
        }
    }



    private final class DisplayControllerHandler extends Handler {
        public DisplayControllerHandler(Looper looper) {
            super(looper, null, true /*async*/);
@@ -2823,7 +2833,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
        @Override
        public void onSensorChanged(SensorEvent event) {
            if (mProximitySensorEnabled) {
                final long time = SystemClock.uptimeMillis();
                final long time = mClock.uptimeMillis();
                final float distance = event.values[0];
                boolean positive = distance >= 0.0f && distance < mProximityThreshold;
                handleProximitySensorEvent(time, positive);
@@ -2892,6 +2902,55 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
        }
    }

    @VisibleForTesting
    String getSuspendBlockerUnfinishedBusinessId(int displayId) {
        return "[" + displayId + "]unfinished business";
    }

    String getSuspendBlockerOnStateChangedId(int displayId) {
        return "[" + displayId + "]on state changed";
    }

    String getSuspendBlockerProxPositiveId(int displayId) {
        return "[" + displayId + "]prox positive";
    }

    String getSuspendBlockerProxNegativeId(int displayId) {
        return "[" + displayId + "]prox negative";
    }

    @VisibleForTesting
    String getSuspendBlockerProxDebounceId(int displayId) {
        return "[" + displayId + "]prox debounce";
    }

    /** Functional interface for providing time. */
    @VisibleForTesting
    interface Clock {
        /**
         * Returns current time in milliseconds since boot, not counting time spent in deep sleep.
         */
        long uptimeMillis();
    }

    @VisibleForTesting
    static class Injector {
        Clock getClock() {
            return SystemClock::uptimeMillis;
        }

        DisplayPowerState getDisplayPowerState(DisplayBlanker blanker, ColorFade colorFade,
                int displayId, int displayState) {
            return new DisplayPowerState(blanker, colorFade, displayId, displayState);
        }

        DualRampAnimator<DisplayPowerState> getDualRampAnimator(DisplayPowerState dps,
                FloatProperty<DisplayPowerState> firstProperty,
                FloatProperty<DisplayPowerState> secondProperty) {
            return new DualRampAnimator(dps, firstProperty, secondProperty);
        }
    }

    static class CachedBrightnessInfo {
        public MutableFloat brightness = new MutableFloat(PowerManager.BRIGHTNESS_INVALID_FLOAT);
        public MutableFloat adjustedBrightness =
+236 −0
Original line number Diff line number Diff line
/*
 * 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;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;


import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Resources;
import android.hardware.Sensor;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
import android.os.Handler;
import android.os.PowerManager;
import android.os.test.TestLooper;
import android.util.FloatProperty;
import android.view.Display;
import android.view.DisplayInfo;

import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import com.android.server.LocalServices;
import com.android.server.display.RampAnimator.DualRampAnimator;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.testutils.OffsettableClock;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.List;


@SmallTest
@RunWith(AndroidJUnit4.class)
public final class DisplayPowerControllerTest {
    private static final String UNIQUE_DISPLAY_ID = "unique_id_test123";
    private static final int DISPLAY_ID = 42;

    private OffsettableClock mClock;
    private TestLooper mTestLooper;
    private Handler mHandler;
    private DisplayPowerController.Injector mInjector;
    private Context mContextSpy;

    @Mock
    private DisplayPowerCallbacks mDisplayPowerCallbacksMock;
    @Mock
    private SensorManager mSensorManagerMock;
    @Mock
    private DisplayBlanker mDisplayBlankerMock;
    @Mock
    private LogicalDisplay mLogicalDisplayMock;
    @Mock
    private DisplayDevice mDisplayDeviceMock;
    @Mock
    private BrightnessTracker mBrightnessTrackerMock;
    @Mock
    private BrightnessSetting mBrightnessSettingMock;
    @Mock
    private WindowManagerPolicy mWindowManagerPolicyMock;
    @Mock
    private PowerManager mPowerManagerMock;
    @Mock
    private Resources mResourcesMock;
    @Mock
    private DisplayDeviceConfig mDisplayDeviceConfigMock;
    @Mock
    private DisplayPowerState mDisplayPowerStateMock;
    @Mock
    private DualRampAnimator<DisplayPowerState> mDualRampAnimatorMock;

    @Captor
    private ArgumentCaptor<SensorEventListener> mSensorEventListenerCaptor;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        mContextSpy = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
        mClock = new OffsettableClock.Stopped();
        mTestLooper = new TestLooper(mClock::now);
        mHandler = new Handler(mTestLooper.getLooper());
        mInjector = new DisplayPowerController.Injector() {
            @Override
            DisplayPowerController.Clock getClock() {
                return mClock::now;
            }

            @Override
            DisplayPowerState getDisplayPowerState(DisplayBlanker blanker, ColorFade colorFade,
                    int displayId, int displayState) {
                return mDisplayPowerStateMock;
            }

            @Override
            DualRampAnimator<DisplayPowerState> getDualRampAnimator(DisplayPowerState dps,
                    FloatProperty<DisplayPowerState> firstProperty,
                    FloatProperty<DisplayPowerState> secondProperty) {
                return mDualRampAnimatorMock;
            }
        };

        addLocalServiceMock(WindowManagerPolicy.class, mWindowManagerPolicyMock);

        when(mContextSpy.getSystemService(eq(PowerManager.class))).thenReturn(mPowerManagerMock);
        when(mContextSpy.getResources()).thenReturn(mResourcesMock);
    }

    @After
    public void tearDown() {
        LocalServices.removeServiceForTest(WindowManagerPolicy.class);
    }

    @Test
    public void testReleaseProxSuspendBlockersOnExit() throws Exception {
        setUpDisplay(DISPLAY_ID, UNIQUE_DISPLAY_ID);

        Sensor proxSensor = setUpProxSensor();

        DisplayPowerController dpc = new DisplayPowerController(
                mContextSpy, mInjector, mDisplayPowerCallbacksMock, mHandler,
                mSensorManagerMock, mDisplayBlankerMock, mLogicalDisplayMock,
                mBrightnessTrackerMock, mBrightnessSettingMock, () -> {
        });

        when(mDisplayPowerStateMock.getScreenState()).thenReturn(Display.STATE_ON);
        // send a display power request
        DisplayPowerRequest dpr = new DisplayPowerRequest();
        dpr.policy = DisplayPowerRequest.POLICY_BRIGHT;
        dpr.useProximitySensor = true;
        dpc.requestPowerState(dpr, false /* waitForNegativeProximity */);

        // Run updatePowerState to start listener for the prox sensor
        advanceTime(1);

        SensorEventListener listener = getSensorEventListener(proxSensor);
        assertNotNull(listener);

        listener.onSensorChanged(TestUtils.createSensorEvent(proxSensor, 5 /* lux */));
        advanceTime(1);

        // two times, one for unfinished business and one for proximity
        verify(mDisplayPowerCallbacksMock).acquireSuspendBlocker(
                dpc.getSuspendBlockerUnfinishedBusinessId(DISPLAY_ID));
        verify(mDisplayPowerCallbacksMock).acquireSuspendBlocker(
                dpc.getSuspendBlockerProxDebounceId(DISPLAY_ID));

        dpc.stop();
        advanceTime(1);

        // two times, one for unfinished business and one for proximity
        verify(mDisplayPowerCallbacksMock).releaseSuspendBlocker(
                dpc.getSuspendBlockerUnfinishedBusinessId(DISPLAY_ID));
        verify(mDisplayPowerCallbacksMock).releaseSuspendBlocker(
                dpc.getSuspendBlockerProxDebounceId(DISPLAY_ID));
    }

    /**
     * Creates a mock and registers it to {@link LocalServices}.
     */
    private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
        LocalServices.removeServiceForTest(clazz);
        LocalServices.addService(clazz, mock);
    }

    private void advanceTime(long timeMs) {
        mClock.fastForward(timeMs);
        mTestLooper.dispatchAll();
    }

    private Sensor setUpProxSensor() throws Exception {
        Sensor proxSensor = TestUtils.createSensor(
                Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_PROXIMITY);
        when(mSensorManagerMock.getSensorList(eq(Sensor.TYPE_ALL)))
                .thenReturn(List.of(proxSensor));
        return proxSensor;
    }

    private SensorEventListener getSensorEventListener(Sensor sensor) {
        verify(mSensorManagerMock).registerListener(mSensorEventListenerCaptor.capture(),
                eq(sensor), eq(SensorManager.SENSOR_DELAY_NORMAL), isA(Handler.class));
        return mSensorEventListenerCaptor.getValue();
    }

    private void setUpDisplay(int displayId, String uniqueId) {
        DisplayInfo info = new DisplayInfo();
        DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo();

        when(mLogicalDisplayMock.getDisplayIdLocked()).thenReturn(displayId);
        when(mLogicalDisplayMock.getPrimaryDisplayDeviceLocked()).thenReturn(mDisplayDeviceMock);
        when(mLogicalDisplayMock.getDisplayInfoLocked()).thenReturn(info);
        when(mLogicalDisplayMock.isEnabled()).thenReturn(true);
        when(mLogicalDisplayMock.getPhase()).thenReturn(LogicalDisplay.DISPLAY_PHASE_ENABLED);
        when(mDisplayDeviceMock.getDisplayDeviceInfoLocked()).thenReturn(deviceInfo);
        when(mDisplayDeviceMock.getUniqueId()).thenReturn(uniqueId);
        when(mDisplayDeviceMock.getDisplayDeviceConfig()).thenReturn(mDisplayDeviceConfigMock);
        when(mDisplayDeviceConfigMock.getProximitySensor()).thenReturn(
                new DisplayDeviceConfig.SensorData() {
                    {
                        type = Sensor.STRING_TYPE_PROXIMITY;
                        name = null;
                    }
                });
        when(mDisplayDeviceConfigMock.getNits()).thenReturn(new float[]{2, 500});
    }
}
+2 −1
Original line number Diff line number Diff line
@@ -135,8 +135,9 @@ android_test {
java_library {
    name: "servicestests-core-utils",
    srcs: [
        "src/com/android/server/pm/PackageSettingBuilder.java",
        "src/com/android/server/am/DeviceConfigSession.java",
        "src/com/android/server/display/TestUtils.java",
        "src/com/android/server/pm/PackageSettingBuilder.java",
    ],
    static_libs: [
        "services.core",