All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.com.android.server.display.whitebalance.AmbientSensor Maven / Gradle / Ivy

/*
 * Copyright (C) 2019 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.whitebalance;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Handler;
import android.util.Slog;

import com.android.internal.util.Preconditions;
import com.android.server.display.utils.History;

import java.io.PrintWriter;

/**
 * The DisplayWhiteBalanceController uses the AmbientSensor to detect changes in the ambient
 * brightness and color temperature.
 *
 * The AmbientSensor listens on an actual sensor, derives the ambient brightness or color
 * temperature from its events, and calls back into the DisplayWhiteBalanceController to report it.
 */
abstract class AmbientSensor {

    protected String mTag;
    protected boolean mLoggingEnabled;

    private final Handler mHandler;

    protected final SensorManager mSensorManager;
    protected Sensor mSensor;

    private boolean mEnabled;

    private int mRate; // Milliseconds

    // The total events count and the most recent events are kept for debugging purposes.
    private int mEventsCount;
    private static final int HISTORY_SIZE = 50;
    private History mEventsHistory;

    /**
     * @param tag
     *      The tag used for dumping and logging.
     * @param handler
     *      The handler used to determine which thread to run on.
     * @param sensorManager
     *      The sensor manager used to acquire necessary sensors.
     * @param rate
     *      The sensor rate.
     *
     * @throws IllegalArgumentException
     *      - rate is not positive.
     * @throws NullPointerException
     *      - handler is null;
     *      - sensorManager is null.
     * @throws IllegalStateException
     *      - Cannot find the necessary sensor.
     */
    AmbientSensor(String tag, @NonNull Handler handler, @NonNull SensorManager sensorManager,
            int rate) {
        validateArguments(handler, sensorManager, rate);
        mTag = tag;
        mLoggingEnabled = false;
        mHandler = handler;
        mSensorManager = sensorManager;
        mEnabled = false;
        mRate = rate;
        mEventsCount = 0;
        mEventsHistory = new History(HISTORY_SIZE);
    }

    /**
     * Enable/disable the sensor.
     *
     * @param enabled
     *      Whether the sensor should be on/off.
     *
     * @return Whether the method succeeded or not.
     */
    public boolean setEnabled(boolean enabled) {
        if (enabled) {
            return enable();
        } else {
            return disable();
        }
    }

    /**
     * Enable/disable logging.
     *
     * @param loggingEnabled
     *      Whether logging should be on/off.
     *
     * @return Whether the method succeeded or not.
     */
    public boolean setLoggingEnabled(boolean loggingEnabled) {
        if (mLoggingEnabled == loggingEnabled) {
            return false;
        }
        mLoggingEnabled = loggingEnabled;
        return true;
    }

    /**
     * Dump the state.
     *
     * @param writer
     *      The PrintWriter used to dump the state.
     */
    public void dump(PrintWriter writer) {
        writer.println("  " + mTag);
        writer.println("    mLoggingEnabled=" + mLoggingEnabled);
        writer.println("    mHandler=" + mHandler);
        writer.println("    mSensorManager=" + mSensorManager);
        writer.println("    mSensor=" + mSensor);
        writer.println("    mEnabled=" + mEnabled);
        writer.println("    mRate=" + mRate);
        writer.println("    mEventsCount=" + mEventsCount);
        writer.println("    mEventsHistory=" + mEventsHistory);
    }


    private static void validateArguments(Handler handler, SensorManager sensorManager, int rate) {
        Preconditions.checkNotNull(handler, "handler cannot be null");
        Preconditions.checkNotNull(sensorManager, "sensorManager cannot be null");
        if (rate <= 0) {
            throw new IllegalArgumentException("rate must be positive");
        }
    }

    protected abstract void update(float value);

    private boolean enable() {
        if (mEnabled) {
            return false;
        }
        if (mLoggingEnabled) {
            Slog.d(mTag, "enabling");
        }
        mEnabled = true;
        startListening();
        return true;
    }

    private boolean disable() {
        if (!mEnabled) {
            return false;
        }
        if (mLoggingEnabled) {
            Slog.d(mTag, "disabling");
        }
        mEnabled = false;
        mEventsCount = 0;
        stopListening();
        return true;
    }

    private void startListening() {
        if (mSensorManager == null) {
            return;
        }
        mSensorManager.registerListener(mListener, mSensor, mRate * 1000, mHandler);
    }

    private void stopListening() {
        if (mSensorManager == null) {
            return;
        }
        mSensorManager.unregisterListener(mListener);
    }

    private void handleNewEvent(float value) {
        // This shouldn't really happen, except for the race condition where the sensor is disabled
        // with an event already in the handler queue, in which case we discard that event.
        if (!mEnabled) {
            return;
        }
        if (mLoggingEnabled) {
            Slog.d(mTag, "handle new event: " + value);
        }
        mEventsCount++;
        mEventsHistory.add(value);
        update(value);
    }

    private SensorEventListener mListener = new SensorEventListener() {

        @Override
        public void onSensorChanged(SensorEvent event) {
            final float value = event.values[0];
            handleNewEvent(value);
        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
            // Not used.
        }

    };

    /**
     * A sensor that reports the ambient brightness.
     */
    static class AmbientBrightnessSensor extends AmbientSensor {

        private static final String TAG = "AmbientBrightnessSensor";

        // To decouple the DisplayWhiteBalanceController from the AmbientBrightnessSensor, the
        // DWBC implements Callbacks and passes itself to the ABS so it can call back into it
        // without knowing about it.
        @Nullable
        private Callbacks mCallbacks;

        /**
         * @param handler
         *      The handler used to determine which thread to run on.
         * @param sensorManager
         *      The sensor manager used to acquire necessary sensors.
         * @param rate
         *      The sensor rate.
         *
         * @throws IllegalArgumentException
         *      - rate is not positive.
         * @throws NullPointerException
         *      - handler is null;
         *      - sensorManager is null.
         * @throws IllegalStateException
         *      - Cannot find the light sensor.
         */
        AmbientBrightnessSensor(@NonNull Handler handler, @NonNull SensorManager sensorManager,
                int rate) {
            super(TAG, handler, sensorManager, rate);
            mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
            if (mSensor == null) {
                throw new IllegalStateException("cannot find light sensor");
            }
            mCallbacks = null;
        }

        /**
         * Set an object to call back to when the ambient brightness changes.
         *
         * @param callbacks
         *      The object to call back to.
         *
         * @return Whether the method succeeded or not.
         */
        public boolean setCallbacks(Callbacks callbacks) {
            if (mCallbacks == callbacks) {
                return false;
            }
            mCallbacks = callbacks;
            return true;
        }

        /**
         * See {@link AmbientSensor#dump base class}.
         */
        @Override
        public void dump(PrintWriter writer) {
            super.dump(writer);
            writer.println("    mCallbacks=" + mCallbacks);
        }

        interface Callbacks {
            void onAmbientBrightnessChanged(float value);
        }

        @Override
        protected void update(float value) {
            if (mCallbacks != null) {
                mCallbacks.onAmbientBrightnessChanged(value);
            }
        }

    }

    /**
     * A sensor that reports the ambient color temperature.
     */
    static class AmbientColorTemperatureSensor extends AmbientSensor {

        private static final String TAG = "AmbientColorTemperatureSensor";

        // To decouple the DisplayWhiteBalanceController from the
        // AmbientColorTemperatureSensor, the DWBC implements Callbacks and passes itself to the
        // ACTS so it can call back into it without knowing about it.
        @Nullable
        private Callbacks mCallbacks;

        /**
         * @param handler
         *      The handler used to determine which thread to run on.
         * @param sensorManager
         *      The sensor manager used to acquire necessary sensors.
         * @param name
         *      The color sensor name.
         * @param rate
         *      The sensor rate.
         *
         * @throws IllegalArgumentException
         *      - rate is not positive.
         * @throws NullPointerException
         *      - handler is null;
         *      - sensorManager is null.
         * @throws IllegalStateException
         *      - Cannot find the color sensor.
         */
        AmbientColorTemperatureSensor(@NonNull Handler handler,
                @NonNull SensorManager sensorManager, String name, int rate) {
            super(TAG, handler, sensorManager, rate);
            mSensor = null;
            for (Sensor sensor : mSensorManager.getSensorList(Sensor.TYPE_ALL)) {
                if (sensor.getStringType().equals(name)) {
                    mSensor = sensor;
                    break;
                }
            }
            if (mSensor == null) {
                throw new IllegalStateException("cannot find sensor " + name);
            }
            mCallbacks = null;
        }

        /**
         * Set an object to call back to when the ambient color temperature changes.
         *
         * @param callbacks
         *      The object to call back to.
         *
         * @return Whether the method succeeded or not.
         */
        public boolean setCallbacks(Callbacks callbacks) {
            if (mCallbacks == callbacks) {
                return false;
            }
            mCallbacks = callbacks;
            return true;
        }

        /**
         * See {@link AmbientSensor#dump base class}.
         */
        @Override
        public void dump(PrintWriter writer) {
            super.dump(writer);
            writer.println("    mCallbacks=" + mCallbacks);
        }

        interface Callbacks {
            void onAmbientColorTemperatureChanged(float value);
        }

        @Override
        protected void update(float value) {
            if (mCallbacks != null) {
                mCallbacks.onAmbientColorTemperatureChanged(value);
            }
        }

    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy