AmbientLightRingBuffer是AutomaticBrightnessController的一个静态内部类,其主要实现了一个循环buffer,用于存放light sensor上报的光感值和对应的时刻,可以直接抽象描述为一个含有lux和time两种属性的元素所构成的循环数组,由于数组中的元素是依次添加的,所以后一个元素的time值肯定大于前一个元素的time值,即从头部到尾部,各元素的time值逐渐增大,尾部为最新的元素。
1.成员变量
该循环数组实际上通过两个同样大小的数组实现的,一个存放光感数据lux,另一个存放获取光感数据的时刻time。
// frameworks/base/services/core/java/com/android/server/display/AutomaticBrightnessController.java
/**
* A ring buffer of ambient light measurements sorted by time.
*
* Each entry consists of a timestamp and a lux measurement, and the overall buffer is sorted
* from oldest to newest.
*/
private static final class AmbientLightRingBuffer {
// Proportional extra capacity of the buffer beyond the expected number of light samples
// in the horizon
// 一个缩放因子,在构造函数中用于计算初始数组的大小
private static final float BUFFER_SLACK = 1.5f;
// 环境光lux数组
private float[] mRingLux;
// 环境光对应的时刻time数组
private long[] mRingTime;
// buffer的容量
private int mCapacity;
// The first valid element and the next open slot.
// Note that if mCount is zero then there are no valid elements.
// 循环数组的头部
private int mStart;
// 循环数组的尾部
private int mEnd;
// 有效元素的个数,循环数组中不存在有效信息时其为0
private int mCount;
}
复制代码
2.构造方法
/**
* @param lightSensorRate 稳定阶段的light sensor的采样率(毫秒)
* @param ambientLightHorizon 作为一个环境光样本所包含的时间间隔(毫秒 在aosp默认为10000ms)
*/
public AmbientLightRingBuffer(long lightSensorRate, int ambientLightHorizon) {
if (lightSensorRate <= 0) {
throw new IllegalArgumentException("lightSensorRate must be above 0");
}
// 计算初始数组大小
mCapacity = (int) Math.ceil(ambientLightHorizon * BUFFER_SLACK / lightSensorRate);
mRingLux = new float[mCapacity];
mRingTime = new long[mCapacity];
}
复制代码
在构造方法中,会根据传入的light sensor采样频率——lightSensorRate和一个环境光样本所包含的时间间隔——ambientLightHorizon,计算出在正常的稳定状态下,环境光样本所能包含的light sensor上报数据数目,最后乘上缩放因子BUFFER_SLACK,得到初始数组的大小,确保该大小足够容纳一般情况下上报的sensor数据量。
3.成员方法
- 3.1获取某一位置的数据
3.1.1获取某一位置的lux值
public float getLux(int index) {
return mRingLux[offsetOf(index)];
}
复制代码
3.1.2获取某一位置的time值
public long getTime(int index) {
return mRingTime[offsetOf(index)];
}
复制代码
- 3.2获取buffer中有效数据的大小
public int size() {
return mCount;
}
复制代码
- 3.3清空buffer
public void clear() {
mStart = 0;
mEnd = 0;
mCount = 0;
}
复制代码
- 3.4获取循环buffer上的真实位置,即在一维数组上的位置
private int offsetOf(int index) {
if (index >= mCount || index < 0) {
throw new ArrayIndexOutOfBoundsException(index);
}
index += mStart;
// 计算index在基于数组上实现的循环buffer上的真实位置
if (index >= mCapacity) {
index -= mCapacity;
}
return index;
}
复制代码
- 3.5添加元素
/**
* @param time light sensor上报事件的时刻
* @param lux light sensor上报的环境光
*/
public void push(long time, float lux) {
int next = mEnd;
// 循环数组已经满
if (mCount == mCapacity) {
// 扩容两倍
int newSize = mCapacity * 2;
float[] newRingLux = new float[newSize];
long[] newRingTime = new long[newSize];
// 下面的拷贝过程就是对循环数组的扩容处理
// 先将循环数组的头部位置到一维数组实际末端的数据拷贝到新的扩容数组中
int length = mCapacity - mStart;
System.arraycopy(mRingLux, mStart, newRingLux, 0, length);
System.arraycopy(mRingTime, mStart, newRingTime, 0, length);
// 再将一维数组实际起始位置到循环列表头部之前的数据拷贝到新的扩容数组中
if (mStart != 0) {
System.arraycopy(mRingLux, 0, newRingLux, length, mStart);
System.arraycopy(mRingTime, 0, newRingTime, length, mStart);
}
// 更新数组信息
mRingLux = newRingLux;
mRingTime = newRingTime;
next = mCapacity;
mCapacity = newSize;
mStart = 0;
}
// 循环数组未满,则直接插入
mRingTime[next] = time;
mRingLux[next] = lux;
mEnd = next + 1;
if (mEnd == mCapacity) {
mEnd = 0;
}
mCount++;
}
复制代码
- 3.6删除某个时刻前的元素
/**
* @param horizon 时刻信息,开机到某一时刻毫秒数
*/
public void prune(long horizon) {
if (mCount == 0) {
return;
}
// 这里循环条件可以看到,当非空循环数组进行删除时,一定会至少保留一个元素
while (mCount > 1) {
int next = mStart + 1;
if (next >= mCapacity) {
next -= mCapacity;
}
if (mRingTime[next] > horizon) {
// Some light sensors only produce data upon a change in the ambient light
// levels, so we need to consider the previous measurement as the ambient light
// level for all points in time up until we receive a new measurement. Thus, we
// always want to keep the youngest element that would be removed from the
// buffer and just set its measurement time to the horizon time since at that
// point it is the ambient light level, and to remove it would be to drop a
// valid data point within our horizon.
break;
}
mStart = next;
mCount -= 1;
}
if (mRingTime[mStart] < horizon) {
mRingTime[mStart] = horizon;
}
}
复制代码
在删除某个时刻前的元素时,由于某些light sensor只有在检测到环境光的级别发生变化时,才会上报sensor事件,因此AOSP在这里采取了一个策略,那就是保留小于等于horizon时刻的最近一个元素,并将该元素的时刻信息time更新为horizon,以保证环境光采样样本内不会丢失有效数据。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END