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

Commit 2a2711b8 authored by Fiona Campbell's avatar Fiona Campbell
Browse files

Even Dimmer for manual mode

- Make even dimmer work in manual screen brightness mode too. This
  includes registering for the light sensor itself, and unregistering
  when the display turns off.

Bug: 338416256
Flag: com.android.server.display.feature.flags.even_dimmer
Test: atest DisplayServiceTests
Test: atest EvenDimmerPreferenceControllerTest

Change-Id: I473c4d6ee65411c8aff45336c42955aafc4c897b
parent c4252906
Loading
Loading
Loading
Loading
+1 −7
Original line number Diff line number Diff line
@@ -54,7 +54,6 @@ import com.android.internal.display.BrightnessSynchronizer;
import com.android.internal.os.BackgroundThread;
import com.android.server.EventLogTags;
import com.android.server.display.brightness.BrightnessEvent;
import com.android.server.display.brightness.clamper.BrightnessClamperController;
import com.android.server.display.config.HysteresisLevels;
import com.android.server.display.feature.DisplayManagerFlags;

@@ -256,7 +255,6 @@ public class AutomaticBrightnessController {

    // Controls Brightness range (including High Brightness Mode).
    private final BrightnessRangeController mBrightnessRangeController;
    private final BrightnessClamperController mBrightnessClamperController;

    // Throttles (caps) maximum allowed brightness
    private final BrightnessThrottler mBrightnessThrottler;
@@ -295,7 +293,6 @@ public class AutomaticBrightnessController {
            BrightnessRangeController brightnessModeController,
            BrightnessThrottler brightnessThrottler, int ambientLightHorizonShort,
            int ambientLightHorizonLong, float userLux, float userNits,
            BrightnessClamperController brightnessClamperController,
            DisplayManagerFlags displayManagerFlags) {
        this(new Injector(), callbacks, looper, sensorManager, lightSensor,
                brightnessMappingStrategyMap, lightSensorWarmUpTime, brightnessMin, brightnessMax,
@@ -306,7 +303,7 @@ public class AutomaticBrightnessController {
                screenBrightnessThresholds, ambientBrightnessThresholdsIdle,
                screenBrightnessThresholdsIdle, context, brightnessModeController,
                brightnessThrottler, ambientLightHorizonShort, ambientLightHorizonLong, userLux,
                userNits, brightnessClamperController, displayManagerFlags
                userNits, displayManagerFlags
        );
    }

@@ -325,7 +322,6 @@ public class AutomaticBrightnessController {
            BrightnessRangeController brightnessRangeController,
            BrightnessThrottler brightnessThrottler, int ambientLightHorizonShort,
            int ambientLightHorizonLong, float userLux, float userNits,
            BrightnessClamperController brightnessClamperController,
            DisplayManagerFlags displayManagerFlags) {
        mInjector = injector;
        mClock = injector.createClock(displayManagerFlags.offloadControlsDozeAutoBrightness());
@@ -370,7 +366,6 @@ public class AutomaticBrightnessController {
        mForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
        mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
        mBrightnessRangeController = brightnessRangeController;
        mBrightnessClamperController = brightnessClamperController;
        mBrightnessThrottler = brightnessThrottler;
        mBrightnessMappingStrategyMap = brightnessMappingStrategyMap;
        mDisplayManagerFlags = displayManagerFlags;
@@ -771,7 +766,6 @@ public class AutomaticBrightnessController {
                    mAmbientBrightnessThresholds.getDarkeningThreshold(lux);
        }
        mBrightnessRangeController.onAmbientLuxChange(mAmbientLux);
        mBrightnessClamperController.onAmbientLuxChange(mAmbientLux);

        // If the short term model was invalidated and the change is drastic enough, reset it.
        mShortTermModel.maybeReset(mAmbientLux);
+5 −7
Original line number Diff line number Diff line
@@ -587,7 +587,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
                        mUniqueDisplayId,
                        mThermalBrightnessThrottlingDataId,
                        logicalDisplay.getPowerThrottlingDataIdLocked(),
                        mDisplayDeviceConfig), mContext, flags);
                        mDisplayDeviceConfig), mContext, flags, mSensorManager);
        // Seed the cached brightness
        saveBrightnessInfo(getScreenBrightnessSetting());
        mAutomaticBrightnessStrategy =
@@ -1422,7 +1422,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
                        : AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED;

        mBrightnessRangeController.setAutoBrightnessEnabled(autoBrightnessState);
        mBrightnessClamperController.setAutoBrightnessState(autoBrightnessState);

        boolean updateScreenBrightnessSetting =
                displayBrightnessState.shouldUpdateScreenBrightnessSetting();
@@ -1549,7 +1548,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
        // we broadcast this change through setting.
        final float unthrottledBrightnessState = brightnessState;
        DisplayBrightnessState clampedState = mBrightnessClamperController.clamp(mPowerRequest,
                brightnessState, slowChange);
                brightnessState, slowChange, /* displayState= */ state);

        brightnessState = clampedState.getBrightness();
        slowChange = clampedState.isSlowChange();
@@ -2478,7 +2477,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
    public void setBrightnessToFollow(float leadDisplayBrightness, float nits, float ambientLux,
            boolean slowChange) {
        mBrightnessRangeController.onAmbientLuxChange(ambientLux);
        mBrightnessClamperController.onAmbientLuxChange(ambientLux);
        if (nits == BrightnessMappingStrategy.INVALID_NITS) {
            mDisplayBrightnessController.setBrightnessToFollow(leadDisplayBrightness, slowChange);
        } else {
@@ -3194,7 +3192,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
                    screenBrightnessThresholds, ambientBrightnessThresholdsIdle,
                    screenBrightnessThresholdsIdle, context, brightnessModeController,
                    brightnessThrottler, ambientLightHorizonShort, ambientLightHorizonLong, userLux,
                    userNits, brightnessClamperController, displayManagerFlags);
                    userNits, displayManagerFlags);
        }

        BrightnessMappingStrategy getDefaultModeBrightnessMapper(Context context,
@@ -3243,10 +3241,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
        BrightnessClamperController getBrightnessClamperController(Handler handler,
                BrightnessClamperController.ClamperChangeListener clamperChangeListener,
                BrightnessClamperController.DisplayDeviceData data, Context context,
                DisplayManagerFlags flags) {
                DisplayManagerFlags flags, SensorManager sensorManager) {

            return new BrightnessClamperController(handler, clamperChangeListener, data, context,
                    flags);
                    flags, sensorManager);
        }

        DisplayWhiteBalanceController getDisplayWhiteBalanceController(Handler handler,
+127 −32
Original line number Diff line number Diff line
@@ -16,21 +16,30 @@

package com.android.server.display.brightness.clamper;

import static android.view.Display.STATE_ON;

import static com.android.server.display.brightness.clamper.BrightnessClamper.Type;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.display.BrightnessInfo;
import android.hardware.display.DisplayManagerInternal;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.PowerManager;
import android.os.SystemClock;
import android.provider.DeviceConfig;
import android.provider.DeviceConfigInterface;
import android.util.IndentingPrintWriter;
import android.util.Slog;

import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.display.DisplayBrightnessState;
import com.android.server.display.DisplayDeviceConfig;
@@ -41,20 +50,30 @@ import com.android.server.display.brightness.BrightnessReason;
import com.android.server.display.config.SensorData;
import com.android.server.display.feature.DeviceConfigParameterProvider;
import com.android.server.display.feature.DisplayManagerFlags;
import com.android.server.display.utils.AmbientFilter;
import com.android.server.display.utils.AmbientFilterFactory;
import com.android.server.display.utils.DebugUtils;
import com.android.server.display.utils.SensorUtils;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;

/**
 * Clampers controller, all in DisplayControllerHandler
 */
public class BrightnessClamperController {
    private static final String TAG = "BrightnessClamperController";
    // To enable these logs, run:
    // 'adb shell setprop persist.log.tag.BrightnessClamperController DEBUG && adb reboot'
    private static final boolean DEBUG = DebugUtils.isDebuggable(TAG);
    public static final float INVALID_LUX = -1f;

    private final DeviceConfigParameterProvider mDeviceConfigParameterProvider;
    private final Handler mHandler;
    private final SensorManager mSensorManager;
    private final ClamperChangeListener mClamperChangeListenerExternal;
    private final Executor mExecutor;
    private final List<BrightnessClamper<? super DisplayDeviceData>> mClampers;
@@ -66,24 +85,55 @@ public class BrightnessClamperController {
    private float mCustomAnimationRate = DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET;
    @Nullable
    private Type mClamperType = null;
    private int mAutoBrightnessState = -1;
    private final SensorEventListener mLightSensorListener;
    private Sensor mRegisteredLightSensor = null;
    private Sensor mLightSensor;
    private String mLightSensorType;
    private String mLightSensorName;
    private AmbientFilter mAmbientFilter;
    private final DisplayDeviceConfig mDisplayDeviceConfig;
    private final Resources mResources;
    private final int mLightSensorRate;

    private final Injector mInjector;
    private boolean mClamperApplied = false;

    public BrightnessClamperController(Handler handler,
            ClamperChangeListener clamperChangeListener, DisplayDeviceData data, Context context,
            DisplayManagerFlags flags) {
        this(new Injector(), handler, clamperChangeListener, data, context, flags);
            DisplayManagerFlags flags, SensorManager sensorManager) {
        this(null, handler, clamperChangeListener, data, context, flags, sensorManager);
    }

    @VisibleForTesting
    BrightnessClamperController(Injector injector, Handler handler,
            ClamperChangeListener clamperChangeListener, DisplayDeviceData data, Context context,
            DisplayManagerFlags flags) {
        mDeviceConfigParameterProvider = injector.getDeviceConfigParameterProvider();
            DisplayManagerFlags flags, SensorManager sensorManager) {
        mInjector = injector == null ? new Injector() : injector;
        mDeviceConfigParameterProvider = mInjector.getDeviceConfigParameterProvider();
        mHandler = handler;
        mSensorManager = sensorManager;
        mDisplayDeviceConfig = data.mDisplayDeviceConfig;
        mLightSensorListener = new SensorEventListener() {
            @Override
            public void onSensorChanged(SensorEvent event) {
                long now = SystemClock.elapsedRealtime();
                mAmbientFilter.addValue(TimeUnit.NANOSECONDS.toMillis(event.timestamp),
                        event.values[0]);
                final float lux = mAmbientFilter.getEstimate(now);
                mModifiers.forEach(mModifier -> mModifier.setAmbientLux(lux));
            }

            @Override
            public void onAccuracyChanged(Sensor sensor, int accuracy) {
                // unused
            }
        };

        mClamperChangeListenerExternal = clamperChangeListener;
        mExecutor = new HandlerExecutor(handler);
        mResources = context.getResources();
        mLightSensorRate = context.getResources().getInteger(
                R.integer.config_autoBrightnessLightSensorRate);

        Runnable clamperChangeRunnableInternal = this::recalculateBrightnessCap;

@@ -93,10 +143,10 @@ public class BrightnessClamperController {
            }
        };

        mClampers = injector.getClampers(handler, clamperChangeListenerInternal, data, flags,
        mClampers = mInjector.getClampers(handler, clamperChangeListenerInternal, data, flags,
                context);
        mModifiers = injector.getModifiers(flags, context, handler, clamperChangeListener,
                data.mDisplayDeviceConfig);
        mModifiers = mInjector.getModifiers(flags, context, handler, clamperChangeListener,
                data.mDisplayDeviceConfig, mSensorManager);
        mOnPropertiesChangedListener =
                properties -> mClampers.forEach(BrightnessClamper::onDeviceConfigChanged);
        start();
@@ -114,7 +164,7 @@ public class BrightnessClamperController {
     * Called in DisplayControllerHandler
     */
    public DisplayBrightnessState clamp(DisplayManagerInternal.DisplayPowerRequest request,
            float brightnessValue, boolean slowChange) {
            float brightnessValue, boolean slowChange, int displayState) {
        float cappedBrightness = Math.min(brightnessValue, mBrightnessCap);

        DisplayBrightnessState.Builder builder = DisplayBrightnessState.builder();
@@ -133,6 +183,12 @@ public class BrightnessClamperController {
            mClamperApplied = false;
        }

        if (displayState != STATE_ON) {
            unregisterSensorListener();
        } else {
            maybeRegisterLightSensor();
        }

        for (int i = 0; i < mModifiers.size(); i++) {
            mModifiers.get(i).apply(request, builder);
        }
@@ -175,6 +231,8 @@ public class BrightnessClamperController {
        writer.println("  mBrightnessCap: " + mBrightnessCap);
        writer.println("  mClamperType: " + mClamperType);
        writer.println("  mClamperApplied: " + mClamperApplied);
        writer.println("  mLightSensor=" + mLightSensor);
        writer.println("  mRegisteredLightSensor=" + mRegisteredLightSensor);
        IndentingPrintWriter ipw = new IndentingPrintWriter(writer, "    ");
        mClampers.forEach(clamper -> clamper.dump(ipw));
        mModifiers.forEach(modifier -> modifier.dump(ipw));
@@ -191,26 +249,6 @@ public class BrightnessClamperController {
        mModifiers.forEach(BrightnessStateModifier::stop);
    }

    /**
     * Notifies modifiers that ambient lux has changed.
     * @param ambientLux current lux, debounced
     */
    public void onAmbientLuxChange(float ambientLux) {
        mModifiers.forEach(modifier -> modifier.onAmbientLuxChange(ambientLux));
    }

    /**
     * Sets the autobrightness state for clampers that need to be aware of the state.
     * @param state autobrightness state
     */
    public void setAutoBrightnessState(int state) {
        if (state == mAutoBrightnessState) {
            return;
        }
        mModifiers.forEach(modifier -> modifier.setAutoBrightnessState(state));
        mAutoBrightnessState = state;
        recalculateBrightnessCap();
    }

    // Called in DisplayControllerHandler
    private void recalculateBrightnessCap() {
@@ -243,6 +281,10 @@ public class BrightnessClamperController {
        if (!mClampers.isEmpty()) {
            mDeviceConfigParameterProvider.addOnPropertiesChangedListener(
                    mExecutor, mOnPropertiesChangedListener);
            reloadLightSensorData(mDisplayDeviceConfig);
            mLightSensor = mInjector.getLightSensor(
                    mSensorManager, mLightSensorType, mLightSensorName);
            maybeRegisterLightSensor();
        }
    }

@@ -281,7 +323,7 @@ public class BrightnessClamperController {

        List<BrightnessStateModifier> getModifiers(DisplayManagerFlags flags, Context context,
                Handler handler, ClamperChangeListener listener,
                DisplayDeviceConfig displayDeviceConfig) {
                DisplayDeviceConfig displayDeviceConfig, SensorManager sensorManager) {
            List<BrightnessStateModifier> modifiers = new ArrayList<>();
            modifiers.add(new DisplayDimModifier(context));
            modifiers.add(new BrightnessLowPowerModeModifier());
@@ -292,6 +334,12 @@ public class BrightnessClamperController {
            }
            return modifiers;
        }

        Sensor getLightSensor(SensorManager sensorManager, String type, String name) {
            return SensorUtils.findSensor(sensorManager, type,
                    name, Sensor.TYPE_LIGHT);
        }

    }

    /**
@@ -368,4 +416,51 @@ public class BrightnessClamperController {
            return mDisplayDeviceConfig.getTempSensor();
        }
    }

    private void maybeRegisterLightSensor() {
        if (mModifiers.stream().noneMatch(BrightnessStateModifier::shouldListenToLightSensor)) {
            return;
        }

        if (mRegisteredLightSensor == mLightSensor) {
            return;
        }

        if (mRegisteredLightSensor != null) {
            unregisterSensorListener();
        }

        mAmbientFilter = AmbientFilterFactory.createBrightnessFilter(TAG, mResources);
        mSensorManager.registerListener(mLightSensorListener,
                mLightSensor, mLightSensorRate * 1000, mHandler);
        mRegisteredLightSensor = mLightSensor;

        if (DEBUG) {
            Slog.d(TAG, "maybeRegisterLightSensor");
        }
    }

    private void unregisterSensorListener() {
        mSensorManager.unregisterListener(mLightSensorListener);
        mRegisteredLightSensor = null;
        mModifiers.forEach(mModifier -> mModifier.setAmbientLux(INVALID_LUX)); // set lux to invalid
        if (DEBUG) {
            Slog.d(TAG, "unregisterSensorListener");
        }
    }

    private void reloadLightSensorData(DisplayDeviceConfig displayDeviceConfig) {
        // The displayDeviceConfig (ddc) contains display specific preferences. When loaded,
        // it naturally falls back to the global config.xml.
        if (displayDeviceConfig != null
                && displayDeviceConfig.getAmbientLightSensor() != null) {
            // This covers both the ddc and the config.xml fallback
            mLightSensorType = displayDeviceConfig.getAmbientLightSensor().type;
            mLightSensorName = displayDeviceConfig.getAmbientLightSensor().name;
        } else if (mLightSensorName == null && mLightSensorType == null) {
            mLightSensorType = mResources.getString(
                    com.android.internal.R.string.config_displayLightSensorType);
            mLightSensorName = "";
        }
    }
}
+14 −14
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.server.display.brightness.clamper;

import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED;

import android.content.ContentResolver;
import android.content.Context;
@@ -30,6 +29,7 @@ import android.util.Slog;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.display.BrightnessSynchronizer;
import com.android.server.display.BrightnessMappingStrategy;
import com.android.server.display.DisplayBrightnessState;
import com.android.server.display.DisplayDeviceConfig;
import com.android.server.display.brightness.BrightnessReason;
@@ -56,7 +56,6 @@ public class BrightnessLowLuxModifier extends BrightnessModifier {
    private float mBrightnessLowerBound;
    private float mMinNitsAllowed;
    private boolean mIsActive;
    private boolean mAutoBrightnessEnabled;
    private float mAmbientLux;
    private final DisplayDeviceConfig mDisplayDeviceConfig;

@@ -87,15 +86,15 @@ public class BrightnessLowLuxModifier extends BrightnessModifier {
                mContentResolver, Settings.Secure.EVEN_DIMMER_MIN_NITS,
                /* def= */ MIN_NITS_DEFAULT, userId);

        boolean isActive = isSettingEnabled() && mAutoBrightnessEnabled;

        float luxBasedNitsLowerBound = mDisplayDeviceConfig.getMinNitsFromLux(mAmbientLux);
        boolean isActive = isSettingEnabled()
                && mAmbientLux != BrightnessMappingStrategy.INVALID_LUX;

        final int reason;
        float minNitsAllowed = -1f; // undefined, if setting is off.
        final float minBrightnessAllowed;

        if (isActive) {
            float luxBasedNitsLowerBound = mDisplayDeviceConfig.getMinNitsFromLux(mAmbientLux);
            minNitsAllowed = Math.max(settingNitsLowerBound,
                    luxBasedNitsLowerBound);
            minBrightnessAllowed = getBrightnessFromNits(minNitsAllowed);
@@ -126,6 +125,12 @@ public class BrightnessLowLuxModifier extends BrightnessModifier {
        }
    }

    @VisibleForTesting
    public void setAmbientLux(float lux) {
        mAmbientLux = lux;
        recalculateLowerBound();
    }

    @VisibleForTesting
    public boolean isActive() {
        return mIsActive;
@@ -164,10 +169,10 @@ public class BrightnessLowLuxModifier extends BrightnessModifier {
    @Override
    public void apply(DisplayManagerInternal.DisplayPowerRequest request,
            DisplayBrightnessState.Builder stateBuilder) {

        stateBuilder.setMinBrightness(mBrightnessLowerBound);
        float boundedBrightness = Math.max(mBrightnessLowerBound, stateBuilder.getBrightness());
        stateBuilder.setBrightness(boundedBrightness);

        if (BrightnessSynchronizer.floatEquals(stateBuilder.getBrightness(),
                mBrightnessLowerBound)) {
            stateBuilder.getBrightnessReason().addModifier(mReason);
@@ -180,14 +185,8 @@ public class BrightnessLowLuxModifier extends BrightnessModifier {
    }

    @Override
    public void onAmbientLuxChange(float ambientLux) {
        mAmbientLux = ambientLux;
        recalculateLowerBound();
    }

    @Override
    public void setAutoBrightnessState(int state) {
        mAutoBrightnessEnabled = state == AUTO_BRIGHTNESS_ENABLED;
    public boolean shouldListenToLightSensor() {
        return isSettingEnabled();
    }

    @Override
@@ -217,6 +216,7 @@ public class BrightnessLowLuxModifier extends BrightnessModifier {
    }

    private final class SettingsObserver extends ContentObserver {

        SettingsObserver(Handler handler) {
            super(handler);
            mContentResolver.registerContentObserver(
+10 −0
Original line number Diff line number Diff line
@@ -51,4 +51,14 @@ class BrightnessLowPowerModeModifier extends BrightnessModifier {
        IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "    ");
        super.dump(ipw);
    }

    @Override
    public boolean shouldListenToLightSensor() {
        return false;
    }

    @Override
    public void setAmbientLux(float lux) {
        // unused
    }
}
Loading