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

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

Merge "BrightnessTracker should accomodate multiple ambient sensors" into tm-qpr-dev

parents 0736fbfd 073fab8f
Loading
Loading
Loading
Loading
+40 −0
Original line number Diff line number Diff line
@@ -602,6 +602,14 @@ class AutomaticBrightnessController {
        mAmbientBrightnessThresholdsIdle.dump(pw);
    }

    public float[] getLastSensorValues() {
        return mAmbientLightRingBuffer.getAllLuxValues();
    }

    public long[] getLastSensorTimestamps() {
        return mAmbientLightRingBuffer.getAllTimestamps();
    }

    private String configStateToString(int state) {
        switch (state) {
        case AUTO_BRIGHTNESS_ENABLED:
@@ -1231,10 +1239,42 @@ class AutomaticBrightnessController {
            return mRingLux[offsetOf(index)];
        }

        public float[] getAllLuxValues() {
            float[] values = new float[mCount];
            if (mCount == 0) {
                return values;
            }

            if (mStart < mEnd) {
                System.arraycopy(mRingLux, mStart, values, 0, mCount);
            } else {
                System.arraycopy(mRingLux, mStart, values, 0, mCapacity - mStart);
                System.arraycopy(mRingLux, 0, values, mCapacity - mStart, mEnd);
            }

            return values;
        }

        public long getTime(int index) {
            return mRingTime[offsetOf(index)];
        }

        public long[] getAllTimestamps() {
            long[] values = new long[mCount];
            if (mCount == 0) {
                return values;
            }

            if (mStart < mEnd) {
                System.arraycopy(mRingTime, mStart, values, 0, mCount);
            } else {
                System.arraycopy(mRingTime, mStart, values, 0, mCapacity - mStart);
                System.arraycopy(mRingTime, 0, values, mCapacity - mStart, mEnd);
            }

            return values;
        }

        public void push(long time, float lux) {
            int next = mEnd;
            if (mCount == mCapacity) {
+18 −71
Original line number Diff line number Diff line
@@ -79,10 +79,8 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Date;
import java.util.Deque;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@@ -101,8 +99,6 @@ public class BrightnessTracker {
    private static final int MAX_EVENTS = 100;
    // Discard events when reading or writing that are older than this.
    private static final long MAX_EVENT_AGE = TimeUnit.DAYS.toMillis(30);
    // Time over which we keep lux sensor readings.
    private static final long LUX_EVENT_HORIZON = TimeUnit.SECONDS.toNanos(10);

    private static final String TAG_EVENTS = "events";
    private static final String TAG_EVENT = "event";
@@ -174,8 +170,6 @@ public class BrightnessTracker {
    // Lock held while collecting data related to brightness changes.
    private final Object mDataCollectionLock = new Object();
    @GuardedBy("mDataCollectionLock")
    private Deque<LightData> mLastSensorReadings = new ArrayDeque<>();
    @GuardedBy("mDataCollectionLock")
    private float mLastBatteryLevel = Float.NaN;
    @GuardedBy("mDataCollectionLock")
    private float mLastBrightness = -1;
@@ -327,7 +321,8 @@ public class BrightnessTracker {
     */
    public void notifyBrightnessChanged(float brightness, boolean userInitiated,
            float powerBrightnessFactor, boolean isUserSetBrightness,
            boolean isDefaultBrightnessConfig, String uniqueDisplayId) {
            boolean isDefaultBrightnessConfig, String uniqueDisplayId, float[] luxValues,
            long[] luxTimestamps) {
        if (DEBUG) {
            Slog.d(TAG, String.format("notifyBrightnessChanged(brightness=%f, userInitiated=%b)",
                        brightness, userInitiated));
@@ -335,7 +330,7 @@ public class BrightnessTracker {
        Message m = mBgHandler.obtainMessage(MSG_BRIGHTNESS_CHANGED,
                userInitiated ? 1 : 0, 0 /*unused*/, new BrightnessChangeValues(brightness,
                        powerBrightnessFactor, isUserSetBrightness, isDefaultBrightnessConfig,
                        mInjector.currentTimeMillis(), uniqueDisplayId));
                        mInjector.currentTimeMillis(), uniqueDisplayId, luxValues, luxTimestamps));
        m.sendToTarget();
    }

@@ -349,7 +344,8 @@ public class BrightnessTracker {

    private void handleBrightnessChanged(float brightness, boolean userInitiated,
            float powerBrightnessFactor, boolean isUserSetBrightness,
            boolean isDefaultBrightnessConfig, long timestamp, String uniqueDisplayId) {
            boolean isDefaultBrightnessConfig, long timestamp, String uniqueDisplayId,
            float[] luxValues, long[] luxTimestamps) {
        BrightnessChangeEvent.Builder builder;

        synchronized (mDataCollectionLock) {
@@ -376,28 +372,22 @@ public class BrightnessTracker {
            builder.setIsDefaultBrightnessConfig(isDefaultBrightnessConfig);
            builder.setUniqueDisplayId(uniqueDisplayId);

            final int readingCount = mLastSensorReadings.size();
            if (readingCount == 0) {
            if (luxValues.length == 0) {
                // No sensor data so ignore this.
                return;
            }

            float[] luxValues = new float[readingCount];
            long[] luxTimestamps = new long[readingCount];

            int pos = 0;
            long[] luxTimestampsMillis = new long[luxTimestamps.length];

            // Convert sensor timestamp in elapsed time nanos to current time millis.
            // Convert lux timestamp in elapsed time to current time.
            long currentTimeMillis = mInjector.currentTimeMillis();
            long elapsedTimeNanos = mInjector.elapsedRealtimeNanos();
            for (LightData reading : mLastSensorReadings) {
                luxValues[pos] = reading.lux;
                luxTimestamps[pos] = currentTimeMillis -
                        TimeUnit.NANOSECONDS.toMillis(elapsedTimeNanos - reading.timestamp);
                ++pos;
            for (int i = 0; i < luxTimestamps.length; i++) {
                luxTimestampsMillis[i] = currentTimeMillis - (TimeUnit.NANOSECONDS.toMillis(
                        elapsedTimeNanos) - luxTimestamps[i]);
            }
            builder.setLuxValues(luxValues);
            builder.setLuxTimestamps(luxTimestamps);
            builder.setLuxTimestamps(luxTimestampsMillis);

            builder.setBatteryLevel(mLastBatteryLevel);
            builder.setLastBrightness(previousBrightness);
@@ -452,9 +442,6 @@ public class BrightnessTracker {
        if (mLightSensor != lightSensor) {
            mLightSensor = lightSensor;
            stopSensorListener();
            synchronized (mDataCollectionLock) {
                mLastSensorReadings.clear();
            }
            // Attempt to restart the sensor listener. It will check to see if it should be running
            // so there is no need to also check here.
            startSensorListener();
@@ -774,12 +761,6 @@ public class BrightnessTracker {
            pw.println("  mLightSensor=" + mLightSensor);
            pw.println("  mLastBatteryLevel=" + mLastBatteryLevel);
            pw.println("  mLastBrightness=" + mLastBrightness);
            pw.println("  mLastSensorReadings.size=" + mLastSensorReadings.size());
            if (!mLastSensorReadings.isEmpty()) {
                pw.println("  mLastSensorReadings time span "
                        + mLastSensorReadings.peekFirst().timestamp + "->"
                        + mLastSensorReadings.peekLast().timestamp);
            }
        }
        synchronized (mEventsLock) {
            pw.println("  mEventsDirty=" + mEventsDirty);
@@ -895,43 +876,6 @@ public class BrightnessTracker {
        return ParceledListSlice.emptyList();
    }

    // Not allowed to keep the SensorEvent so used to copy the data we care about.
    private static class LightData {
        public float lux;
        // Time in elapsedRealtimeNanos
        public long timestamp;
    }

    private void recordSensorEvent(SensorEvent event) {
        long horizon = mInjector.elapsedRealtimeNanos() - LUX_EVENT_HORIZON;
        synchronized (mDataCollectionLock) {
            if (DEBUG) {
                Slog.v(TAG, "Sensor event " + event);
            }
            if (!mLastSensorReadings.isEmpty()
                    && event.timestamp < mLastSensorReadings.getLast().timestamp) {
                // Ignore event that came out of order.
                return;
            }
            LightData data = null;
            while (!mLastSensorReadings.isEmpty()
                    && mLastSensorReadings.getFirst().timestamp < horizon) {
                // Remove data that has fallen out of the window.
                data = mLastSensorReadings.removeFirst();
            }
            // We put back the last one we removed so we know how long
            // the first sensor reading was valid for.
            if (data != null) {
                mLastSensorReadings.addFirst(data);
            }

            data = new LightData();
            data.timestamp = event.timestamp;
            data.lux = event.values[0];
            mLastSensorReadings.addLast(data);
        }
    }

    private void recordAmbientBrightnessStats(SensorEvent event) {
        mAmbientBrightnessStatsTracker.add(mCurrentUserId, event.values[0]);
    }
@@ -945,7 +889,6 @@ public class BrightnessTracker {
    private final class SensorListener implements SensorEventListener {
        @Override
        public void onSensorChanged(SensorEvent event) {
            recordSensorEvent(event);
            recordAmbientBrightnessStats(event);
        }

@@ -1032,7 +975,7 @@ public class BrightnessTracker {
                    handleBrightnessChanged(values.brightness, userInitiatedChange,
                            values.powerBrightnessFactor, values.isUserSetBrightness,
                            values.isDefaultBrightnessConfig, values.timestamp,
                            values.uniqueDisplayId);
                            values.uniqueDisplayId, values.luxValues, values.luxTimestamps);
                    break;
                case MSG_START_SENSOR_LISTENER:
                    startSensorListener();
@@ -1068,16 +1011,20 @@ public class BrightnessTracker {
        public final boolean isDefaultBrightnessConfig;
        public final long timestamp;
        public final String uniqueDisplayId;
        public final float[] luxValues;
        public final long[] luxTimestamps;

        BrightnessChangeValues(float brightness, float powerBrightnessFactor,
                boolean isUserSetBrightness, boolean isDefaultBrightnessConfig,
                long timestamp, String uniqueDisplayId) {
                long timestamp, String uniqueDisplayId, float[] luxValues, long[] luxTimestamps) {
            this.brightness = brightness;
            this.powerBrightnessFactor = powerBrightnessFactor;
            this.isUserSetBrightness = isUserSetBrightness;
            this.isDefaultBrightnessConfig = isDefaultBrightnessConfig;
            this.timestamp = timestamp;
            this.uniqueDisplayId = uniqueDisplayId;
            this.luxValues = luxValues;
            this.luxTimestamps = luxTimestamps;
        }
    }

+3 −1
Original line number Diff line number Diff line
@@ -2471,7 +2471,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
                    : 1.0f;
            mBrightnessTracker.notifyBrightnessChanged(brightnessInNits, userInitiated,
                    powerFactor, hadUserDataPoint,
                    mAutomaticBrightnessController.isDefaultConfig(), mUniqueDisplayId);
                    mAutomaticBrightnessController.isDefaultConfig(), mUniqueDisplayId,
                    mAutomaticBrightnessController.getLastSensorValues(),
                    mAutomaticBrightnessController.getLastSensorTimestamps());
        }
    }

+99 −4
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.display;

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

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
@@ -178,7 +179,7 @@ public class AutomaticBrightnessControllerTest {

        // Send new sensor value and verify
        listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux1));
        assertEquals(normalizedBrightness1, mController.getAutomaticScreenBrightness(), 0.001f);
        assertEquals(normalizedBrightness1, mController.getAutomaticScreenBrightness(), EPSILON);

        // Set up system to return 0.0f (minimum possible brightness) as a brightness value
        float lux2 = 10.0f;
@@ -192,7 +193,7 @@ public class AutomaticBrightnessControllerTest {

        // Send new sensor value and verify
        listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux2));
        assertEquals(normalizedBrightness2, mController.getAutomaticScreenBrightness(), 0.001f);
        assertEquals(normalizedBrightness2, mController.getAutomaticScreenBrightness(), EPSILON);
    }

    @Test
@@ -221,7 +222,7 @@ public class AutomaticBrightnessControllerTest {

        // Send new sensor value and verify
        listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux1));
        assertEquals(normalizedBrightness1, mController.getAutomaticScreenBrightness(), 0.001f);
        assertEquals(normalizedBrightness1, mController.getAutomaticScreenBrightness(), EPSILON);


        // Set up system to return 1.0f as a brightness value (brightness_max)
@@ -236,7 +237,7 @@ public class AutomaticBrightnessControllerTest {

        // Send new sensor value and verify
        listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux2));
        assertEquals(normalizedBrightness2, mController.getAutomaticScreenBrightness(), 0.001f);
        assertEquals(normalizedBrightness2, mController.getAutomaticScreenBrightness(), EPSILON);
    }

    @Test
@@ -418,6 +419,12 @@ public class AutomaticBrightnessControllerTest {
        // ambient lux goes to 0
        listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0));
        assertEquals(0.0f, mController.getAmbientLux(), EPSILON);

        // only the values within the horizon should be kept
        assertArrayEquals(new float[] {10000, 10000, 0, 0, 0}, mController.getLastSensorValues(),
                EPSILON);
        assertArrayEquals(new long[] {4000, 4500, 5000, 5500, 6000},
                mController.getLastSensorTimestamps());
    }

    @Test
@@ -489,4 +496,92 @@ public class AutomaticBrightnessControllerTest {
                0 /* adjustment */, false /* userChanged */, DisplayPowerRequest.POLICY_BRIGHT);
        assertEquals(BRIGHTNESS_MAX_FLOAT, mController.getAutomaticScreenBrightness(), 0.0f);
    }

    @Test
    public void testGetSensorReadings() throws Exception {
        ArgumentCaptor<SensorEventListener> listenerCaptor =
                ArgumentCaptor.forClass(SensorEventListener.class);
        verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor),
                eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
        SensorEventListener listener = listenerCaptor.getValue();

        // Choose values such that the ring buffer's capacity is extended and the buffer is pruned
        int increment = 11;
        int lux = 5000;
        for (int i = 0; i < 1000; i++) {
            lux += increment;
            mClock.fastForward(increment);
            listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux));
        }

        int valuesCount = (int) Math.ceil((double) AMBIENT_LIGHT_HORIZON_LONG / increment + 1);
        float[] sensorValues = mController.getLastSensorValues();
        long[] sensorTimestamps = mController.getLastSensorTimestamps();

        // Only the values within the horizon should be kept
        assertEquals(valuesCount, sensorValues.length);
        assertEquals(valuesCount, sensorTimestamps.length);

        long sensorTimestamp = mClock.now();
        for (int i = valuesCount - 1; i >= 1; i--) {
            assertEquals(lux, sensorValues[i], EPSILON);
            assertEquals(sensorTimestamp, sensorTimestamps[i]);
            lux -= increment;
            sensorTimestamp -= increment;
        }
        assertEquals(lux, sensorValues[0], EPSILON);
        assertEquals(mClock.now() - AMBIENT_LIGHT_HORIZON_LONG, sensorTimestamps[0]);
    }

    @Test
    public void testGetSensorReadingsFullBuffer() throws Exception {
        ArgumentCaptor<SensorEventListener> listenerCaptor =
                ArgumentCaptor.forClass(SensorEventListener.class);
        verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor),
                eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
        SensorEventListener listener = listenerCaptor.getValue();
        int initialCapacity = 150;

        // Choose values such that the ring buffer is pruned
        int increment1 = 200;
        int lux = 5000;
        for (int i = 0; i < 20; i++) {
            lux += increment1;
            mClock.fastForward(increment1);
            listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux));
        }

        int valuesCount = (int) Math.ceil((double) AMBIENT_LIGHT_HORIZON_LONG / increment1 + 1);

        // Choose values such that the buffer becomes full
        int increment2 = 1;
        for (int i = 0; i < initialCapacity - valuesCount; i++) {
            lux += increment2;
            mClock.fastForward(increment2);
            listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux));
        }

        float[] sensorValues = mController.getLastSensorValues();
        long[] sensorTimestamps = mController.getLastSensorTimestamps();

        // The buffer should be full
        assertEquals(initialCapacity, sensorValues.length);
        assertEquals(initialCapacity, sensorTimestamps.length);

        long sensorTimestamp = mClock.now();
        for (int i = initialCapacity - 1; i >= 1; i--) {
            assertEquals(lux, sensorValues[i], EPSILON);
            assertEquals(sensorTimestamp, sensorTimestamps[i]);

            if (i >= valuesCount) {
                lux -= increment2;
                sensorTimestamp -= increment2;
            } else {
                lux -= increment1;
                sensorTimestamp -= increment1;
            }
        }
        assertEquals(lux, sensorValues[0], EPSILON);
        assertEquals(mClock.now() - AMBIENT_LIGHT_HORIZON_LONG, sensorTimestamps[0]);
    }
}
+77 −120

File changed.

Preview size limit exceeded, changes collapsed.