blob: 6b0798bdce2282e6cd3c429bf60984dab1ad0bdd [file] [log] [blame]
Anthony Han04c78a92019-05-03 13:34:57 -07001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.display.whitebalance;
18
19import com.android.internal.R;
20import com.google.common.collect.ImmutableList;
21
22import static org.junit.Assert.assertEquals;
23import static org.mockito.Mockito.mock;
24import static org.mockito.Mockito.spy;
25import static org.mockito.Mockito.when;
Anthony Han0c8297c2019-06-18 16:56:11 -070026import static org.mockito.Mockito.doAnswer;
27import static org.mockito.Matchers.any;
Anthony Han04c78a92019-05-03 13:34:57 -070028import static org.mockito.Matchers.anyLong;
Anthony Han0c8297c2019-06-18 16:56:11 -070029import static org.mockito.Matchers.eq;
30import org.mockito.stubbing.Answer;
31import org.mockito.invocation.InvocationOnMock;
Anthony Han04c78a92019-05-03 13:34:57 -070032import org.mockito.Mock;
33import org.mockito.MockitoAnnotations;
34import org.mockito.Spy;
35
36import android.content.ContextWrapper;
37import android.content.res.Resources;
38import android.content.res.TypedArray;
39import android.hardware.Sensor;
40import android.hardware.SensorEvent;
41import android.hardware.SensorEventListener;
42import android.hardware.SensorManager;
43import android.os.Handler;
44import android.os.Looper;
45import android.util.TypedValue;
46
47import androidx.test.InstrumentationRegistry;
48
49import org.junit.Before;
50import org.junit.After;
51import org.junit.Test;
52import org.junit.runner.RunWith;
53import org.junit.runners.JUnit4;
54
55import java.lang.reflect.Constructor;
56import java.lang.reflect.Field;
57import java.lang.reflect.Method;
58import java.util.List;
59
60@RunWith(JUnit4.class)
61public final class AmbientLuxTest {
62 private static final int AMBIENT_COLOR_TYPE = 20705;
63 private static final String AMBIENT_COLOR_TYPE_STR = "colorSensoryDensoryDoc";
Anthony Han0c8297c2019-06-18 16:56:11 -070064 private static final float LOW_LIGHT_AMBIENT_COLOR_TEMPERATURE = 5432.1f;
65 private static final float HIGH_LIGHT_AMBIENT_COLOR_TEMPERATURE = 3456.7f;
Anthony Han04c78a92019-05-03 13:34:57 -070066
67 private Handler mHandler = new Handler(Looper.getMainLooper());
68 private Sensor mLightSensor;
69 private Sensor mAmbientColorSensor;
70 private ContextWrapper mContextSpy;
71 private Resources mResourcesSpy;
72
73 @Mock private SensorManager mSensorManagerMock;
74
75 @Mock private TypedArray mBrightnesses;
76 @Mock private TypedArray mBiases;
Anthony Han0c8297c2019-06-18 16:56:11 -070077 @Mock private TypedArray mHighLightBrightnesses;
78 @Mock private TypedArray mHighLightBiases;
Anthony Han04c78a92019-05-03 13:34:57 -070079
80 @Before
81 public void setUp() throws Exception {
82 MockitoAnnotations.initMocks(this);
83 mLightSensor = createSensor(Sensor.TYPE_LIGHT, null);
84 mAmbientColorSensor = createSensor(AMBIENT_COLOR_TYPE, AMBIENT_COLOR_TYPE_STR);
85 mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
86 mResourcesSpy = spy(mContextSpy.getResources());
87 when(mContextSpy.getResources()).thenReturn(mResourcesSpy);
88 when(mSensorManagerMock.getDefaultSensor(Sensor.TYPE_LIGHT)).thenReturn(mLightSensor);
89 final List<Sensor> sensorList = ImmutableList.of(mLightSensor, mAmbientColorSensor);
90 when(mSensorManagerMock.getSensorList(Sensor.TYPE_ALL)).thenReturn(sensorList);
91 when(mResourcesSpy.getString(
92 R.string.config_displayWhiteBalanceColorTemperatureSensorName))
93 .thenReturn(AMBIENT_COLOR_TYPE_STR);
94 when(mResourcesSpy.getInteger(
95 R.integer.config_displayWhiteBalanceDecreaseDebounce))
96 .thenReturn(0);
97 when(mResourcesSpy.getInteger(
98 R.integer.config_displayWhiteBalanceIncreaseDebounce))
99 .thenReturn(0);
Anthony Han0c8297c2019-06-18 16:56:11 -0700100 mockResourcesFloat(R.dimen.config_displayWhiteBalanceLowLightAmbientColorTemperature,
101 LOW_LIGHT_AMBIENT_COLOR_TEMPERATURE);
102 mockResourcesFloat(R.dimen.config_displayWhiteBalanceHighLightAmbientColorTemperature,
103 HIGH_LIGHT_AMBIENT_COLOR_TEMPERATURE);
Anthony Han04c78a92019-05-03 13:34:57 -0700104 when(mResourcesSpy.obtainTypedArray(
105 R.array.config_displayWhiteBalanceAmbientColorTemperatures))
106 .thenReturn(createTypedArray());
107 when(mResourcesSpy.obtainTypedArray(
108 R.array.config_displayWhiteBalanceDisplayColorTemperatures))
109 .thenReturn(createTypedArray());
110
111 when(mResourcesSpy.obtainTypedArray(
112 R.array.config_displayWhiteBalanceLowLightAmbientBrightnesses))
113 .thenReturn(mBrightnesses);
114 when(mResourcesSpy.obtainTypedArray(
115 R.array.config_displayWhiteBalanceLowLightAmbientBiases))
116 .thenReturn(mBiases);
Anthony Han0c8297c2019-06-18 16:56:11 -0700117 when(mResourcesSpy.obtainTypedArray(
118 R.array.config_displayWhiteBalanceHighLightAmbientBrightnesses))
119 .thenReturn(mHighLightBrightnesses);
120 when(mResourcesSpy.obtainTypedArray(
121 R.array.config_displayWhiteBalanceHighLightAmbientBiases))
122 .thenReturn(mHighLightBiases);
123 mockThrottler();
Anthony Han04c78a92019-05-03 13:34:57 -0700124 }
125
126 @Test
127 public void testNoSpline() throws Exception {
128 setBrightnesses();
129 setBiases();
130
131 DisplayWhiteBalanceController controller =
132 DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
133 final float ambientColorTemperature = 8000.0f;
134 setEstimatedColorTemperature(controller, ambientColorTemperature);
135 controller.mBrightnessFilter = spy(controller.mBrightnessFilter);
136
137 for (float luxOverride = 0.1f; luxOverride <= 10000; luxOverride *= 10) {
138 setEstimatedBrightnessAndUpdate(controller, luxOverride);
139 assertEquals(controller.mPendingAmbientColorTemperature,
140 ambientColorTemperature, 0.001);
141 }
142 }
143
144 @Test
145 public void testSpline_OneSegment() throws Exception {
146 final float lowerBrightness = 10.0f;
147 final float upperBrightness = 50.0f;
148 setBrightnesses(lowerBrightness, upperBrightness);
149 setBiases(0.0f, 1.0f);
150
151 DisplayWhiteBalanceController controller =
152 DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
153 final float ambientColorTemperature = 8000.0f;
154 setEstimatedColorTemperature(controller, ambientColorTemperature);
155 controller.mBrightnessFilter = spy(controller.mBrightnessFilter);
156
157 for (float t = 0.0f; t <= 1.0f; t += 0.1f) {
158 setEstimatedBrightnessAndUpdate(controller,
159 mix(lowerBrightness, upperBrightness, t));
160 assertEquals(controller.mPendingAmbientColorTemperature,
161 mix(LOW_LIGHT_AMBIENT_COLOR_TEMPERATURE, ambientColorTemperature, t), 0.001);
162 }
163
164 setEstimatedBrightnessAndUpdate(controller, 0.0f);
165 assertEquals(controller.mPendingAmbientColorTemperature,
166 LOW_LIGHT_AMBIENT_COLOR_TEMPERATURE, 0.001);
167
168 setEstimatedBrightnessAndUpdate(controller, upperBrightness + 1.0f);
169 assertEquals(controller.mPendingAmbientColorTemperature, ambientColorTemperature, 0.001);
170 }
171
172 @Test
173 public void testSpline_TwoSegments() throws Exception {
174 final float brightness0 = 10.0f;
175 final float brightness1 = 50.0f;
176 final float brightness2 = 60.0f;
177 setBrightnesses(brightness0, brightness1, brightness2);
178 final float bias0 = 0.0f;
179 final float bias1 = 0.25f;
180 final float bias2 = 1.0f;
181 setBiases(bias0, bias1, bias2);
182
183 DisplayWhiteBalanceController controller =
184 DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
185 final float ambientColorTemperature = 8000.0f;
186 setEstimatedColorTemperature(controller, ambientColorTemperature);
187 controller.mBrightnessFilter = spy(controller.mBrightnessFilter);
188
189 for (float t = 0.0f; t <= 1.0f; t += 0.1f) {
190 float luxOverride = mix(brightness0, brightness1, t);
191 setEstimatedBrightnessAndUpdate(controller, luxOverride);
192 float bias = mix(bias0, bias1, t);
193 assertEquals(controller.mPendingAmbientColorTemperature,
194 mix(LOW_LIGHT_AMBIENT_COLOR_TEMPERATURE, ambientColorTemperature, bias), 0.001);
195 }
196
197 for (float t = 0.0f; t <= 1.0f; t += 0.1f) {
198 float luxOverride = mix(brightness1, brightness2, t);
199 setEstimatedBrightnessAndUpdate(controller, luxOverride);
200 float bias = mix(bias1, bias2, t);
201 assertEquals(controller.mPendingAmbientColorTemperature,
202 mix(LOW_LIGHT_AMBIENT_COLOR_TEMPERATURE, ambientColorTemperature, bias), 0.001);
203 }
204
205 setEstimatedBrightnessAndUpdate(controller, 0.0f);
206 assertEquals(controller.mPendingAmbientColorTemperature,
207 LOW_LIGHT_AMBIENT_COLOR_TEMPERATURE, 0.001);
208
209 setEstimatedBrightnessAndUpdate(controller, brightness2 + 1.0f);
210 assertEquals(controller.mPendingAmbientColorTemperature, ambientColorTemperature, 0.001);
211 }
212
213 @Test
214 public void testSpline_VerticalSegment() throws Exception {
215 final float lowerBrightness = 10.0f;
216 final float upperBrightness = 10.0f;
217 setBrightnesses(lowerBrightness, upperBrightness);
218 setBiases(0.0f, 1.0f);
219
220 DisplayWhiteBalanceController controller =
221 DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
222 final float ambientColorTemperature = 8000.0f;
223 setEstimatedColorTemperature(controller, ambientColorTemperature);
224 controller.mBrightnessFilter = spy(controller.mBrightnessFilter);
225
226 setEstimatedBrightnessAndUpdate(controller, 0.0f);
227 assertEquals(controller.mPendingAmbientColorTemperature,
228 LOW_LIGHT_AMBIENT_COLOR_TEMPERATURE, 0.001);
229
230 setEstimatedBrightnessAndUpdate(controller, upperBrightness + 1.0f);
231 assertEquals(controller.mPendingAmbientColorTemperature, ambientColorTemperature, 0.001);
232 }
233
234 @Test
Anthony Han0c8297c2019-06-18 16:56:11 -0700235 public void testSpline_InvalidEndBias() throws Exception {
236 setBrightnesses(10.0f, 1000.0f);
237 setBiases(0.0f, 2.0f);
238
239 DisplayWhiteBalanceController controller =
240 DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
241 final float ambientColorTemperature = 8000.0f;
242 setEstimatedColorTemperature(controller, ambientColorTemperature);
243 controller.mBrightnessFilter = spy(controller.mBrightnessFilter);
244
245 for (float luxOverride = 0.1f; luxOverride <= 10000; luxOverride *= 10) {
246 setEstimatedBrightnessAndUpdate(controller, luxOverride);
247 assertEquals(controller.mPendingAmbientColorTemperature,
248 ambientColorTemperature, 0.001);
249 }
250 }
251
252 @Test
253 public void testSpline_InvalidBeginBias() throws Exception {
254 setBrightnesses(10.0f, 1000.0f);
255 setBiases(0.1f, 1.0f);
256
257 DisplayWhiteBalanceController controller =
258 DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
259 final float ambientColorTemperature = 8000.0f;
260 setEstimatedColorTemperature(controller, ambientColorTemperature);
261 controller.mBrightnessFilter = spy(controller.mBrightnessFilter);
262
263 for (float luxOverride = 0.1f; luxOverride <= 10000; luxOverride *= 10) {
264 setEstimatedBrightnessAndUpdate(controller, luxOverride);
265 assertEquals(controller.mPendingAmbientColorTemperature,
266 ambientColorTemperature, 0.001);
267 }
268 }
269
270 @Test
271 public void testSpline_OneSegmentHighLight() throws Exception {
272 final float lowerBrightness = 10.0f;
273 final float upperBrightness = 50.0f;
274 setHighLightBrightnesses(lowerBrightness, upperBrightness);
275 setHighLightBiases(0.0f, 1.0f);
276
277 DisplayWhiteBalanceController controller =
278 DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
279 final float ambientColorTemperature = 8000.0f;
280 setEstimatedColorTemperature(controller, ambientColorTemperature);
281 controller.mBrightnessFilter = spy(controller.mBrightnessFilter);
282
283 for (float t = 0.0f; t <= 1.0f; t += 0.1f) {
284 setEstimatedBrightnessAndUpdate(controller,
285 mix(lowerBrightness, upperBrightness, t));
286 assertEquals(controller.mPendingAmbientColorTemperature,
287 mix(HIGH_LIGHT_AMBIENT_COLOR_TEMPERATURE, ambientColorTemperature, 1.0f - t),
288 0.001);
289 }
290
291 setEstimatedBrightnessAndUpdate(controller, upperBrightness + 1.0f);
292 assertEquals(controller.mPendingAmbientColorTemperature,
293 HIGH_LIGHT_AMBIENT_COLOR_TEMPERATURE, 0.001);
294
295 setEstimatedBrightnessAndUpdate(controller, 0.0f);
296 assertEquals(controller.mPendingAmbientColorTemperature, ambientColorTemperature, 0.001);
297 }
298
299 @Test
300 public void testSpline_TwoSegmentsHighLight() throws Exception {
301 final float brightness0 = 10.0f;
302 final float brightness1 = 50.0f;
303 final float brightness2 = 60.0f;
304 setHighLightBrightnesses(brightness0, brightness1, brightness2);
305 final float bias0 = 0.0f;
306 final float bias1 = 0.25f;
307 final float bias2 = 1.0f;
308 setHighLightBiases(bias0, bias1, bias2);
309
310 DisplayWhiteBalanceController controller =
311 DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
312 final float ambientColorTemperature = 6000.0f;
313 setEstimatedColorTemperature(controller, ambientColorTemperature);
314 controller.mBrightnessFilter = spy(controller.mBrightnessFilter);
315
316 for (float t = 0.0f; t <= 1.0f; t += 0.1f) {
317 float luxOverride = mix(brightness0, brightness1, t);
318 setEstimatedBrightnessAndUpdate(controller, luxOverride);
319 float bias = mix(bias0, bias1, t);
320 assertEquals(controller.mPendingAmbientColorTemperature,
321 mix(HIGH_LIGHT_AMBIENT_COLOR_TEMPERATURE, ambientColorTemperature, 1.0f - bias),
322 0.01);
323 }
324
325 for (float t = 0.0f; t <= 1.0f; t += 0.1f) {
326 float luxOverride = mix(brightness1, brightness2, t);
327 setEstimatedBrightnessAndUpdate(controller, luxOverride);
328 float bias = mix(bias1, bias2, t);
329 assertEquals(controller.mPendingAmbientColorTemperature,
330 mix(HIGH_LIGHT_AMBIENT_COLOR_TEMPERATURE, ambientColorTemperature, 1.0f - bias),
331 0.01);
332 }
333
334 setEstimatedBrightnessAndUpdate(controller, brightness2 + 1.0f);
335 assertEquals(controller.mPendingAmbientColorTemperature,
336 HIGH_LIGHT_AMBIENT_COLOR_TEMPERATURE, 0.001);
337
338 setEstimatedBrightnessAndUpdate(controller, 0.0f);
339 assertEquals(controller.mPendingAmbientColorTemperature, ambientColorTemperature, 0.001);
340 }
341
342 @Test
343 public void testSpline_InvalidCombinations() throws Exception {
344 setBrightnesses(100.0f, 200.0f);
345 setBiases(0.0f, 1.0f);
346 setHighLightBrightnesses(150.0f, 250.0f);
347 setHighLightBiases(0.0f, 1.0f);
Anthony Han04c78a92019-05-03 13:34:57 -0700348
349 DisplayWhiteBalanceController controller =
350 DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
351 final float ambientColorTemperature = 8000.0f;
352 setEstimatedColorTemperature(controller, ambientColorTemperature);
353 controller.mBrightnessFilter = spy(controller.mBrightnessFilter);
354
355 for (float luxOverride = 0.1f; luxOverride <= 10000; luxOverride *= 10) {
356 setEstimatedBrightnessAndUpdate(controller, luxOverride);
357 assertEquals(controller.mPendingAmbientColorTemperature,
358 ambientColorTemperature, 0.001);
359 }
Anthony Han0c8297c2019-06-18 16:56:11 -0700360 }
361
Anthony Han35df7e22019-06-27 17:27:24 -0700362 @Test
363 public void testLowLight_DefaultAmbient() throws Exception {
364 final float lowerBrightness = 10.0f;
365 final float upperBrightness = 50.0f;
366 setBrightnesses(lowerBrightness, upperBrightness);
367 setBiases(0.0f, 1.0f);
368
369 DisplayWhiteBalanceController controller =
370 DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
371 final float ambientColorTemperature = -1.0f;
372 setEstimatedColorTemperature(controller, ambientColorTemperature);
373 controller.mBrightnessFilter = spy(controller.mBrightnessFilter);
374
375 for (float t = 0.0f; t <= 1.0f; t += 0.1f) {
376 setEstimatedBrightnessAndUpdate(controller,
377 mix(lowerBrightness, upperBrightness, t));
378 assertEquals(controller.mPendingAmbientColorTemperature, ambientColorTemperature,
379 0.001);
380 }
381
382 setEstimatedBrightnessAndUpdate(controller, 0.0f);
383 assertEquals(controller.mPendingAmbientColorTemperature, ambientColorTemperature, 0.001);
384
385 setEstimatedBrightnessAndUpdate(controller, upperBrightness + 1.0f);
386 assertEquals(controller.mPendingAmbientColorTemperature, ambientColorTemperature, 0.001);
387 }
388
Anthony Han0c8297c2019-06-18 16:56:11 -0700389 void mockThrottler() {
390 when(mResourcesSpy.getInteger(
391 R.integer.config_displayWhiteBalanceDecreaseDebounce)).thenReturn(0);
392 when(mResourcesSpy.getInteger(
393 R.integer.config_displayWhiteBalanceIncreaseDebounce)).thenReturn(0);
394 TypedArray base = mResourcesSpy.obtainTypedArray(
395 R.array.config_displayWhiteBalanceBaseThresholds);
396 TypedArray inc = mResourcesSpy.obtainTypedArray(
397 R.array.config_displayWhiteBalanceIncreaseThresholds);
398 TypedArray dec = mResourcesSpy.obtainTypedArray(
399 R.array.config_displayWhiteBalanceDecreaseThresholds);
400 base = spy(base);
401 inc = spy(inc);
402 dec = spy(dec);
403 when(mResourcesSpy.obtainTypedArray(
404 R.array.config_displayWhiteBalanceBaseThresholds)).thenReturn(base);
405 when(mResourcesSpy.obtainTypedArray(
406 R.array.config_displayWhiteBalanceIncreaseThresholds)).thenReturn(inc);
407 when(mResourcesSpy.obtainTypedArray(
408 R.array.config_displayWhiteBalanceDecreaseThresholds)).thenReturn(dec);
409 setFloatArrayResource(base, new float[]{0.0f});
410 setFloatArrayResource(inc, new float[]{0.0f});
411 setFloatArrayResource(dec, new float[]{0.0f});
412 }
413
414 private void mockResourcesFloat(int id, float floatValue) {
415 doAnswer(new Answer<Void>() {
416 public Void answer(InvocationOnMock invocation) {
417 TypedValue value = (TypedValue)invocation.getArgument(1);
418 value.type = TypedValue.TYPE_FLOAT;
419 value.data = Float.floatToIntBits(floatValue);
420 return null;
421 }
422 }).when(mResourcesSpy).getValue(
423 eq(id),
424 any(TypedValue.class), eq(true));
Anthony Han04c78a92019-05-03 13:34:57 -0700425 }
426
427 private void setEstimatedColorTemperature(DisplayWhiteBalanceController controller,
428 float ambientColorTemperature) {
429 AmbientFilter colorTemperatureFilter = spy(controller.mColorTemperatureFilter);
430 controller.mColorTemperatureFilter = colorTemperatureFilter;
431 when(colorTemperatureFilter.getEstimate(anyLong())).thenReturn(ambientColorTemperature);
432 }
433
434 private void setEstimatedBrightnessAndUpdate(DisplayWhiteBalanceController controller,
435 float brightness) {
436 when(controller.mBrightnessFilter.getEstimate(anyLong())).thenReturn(brightness);
437 controller.updateAmbientColorTemperature();
438 }
439
440 private void setBrightnesses(float... vals) {
441 setFloatArrayResource(mBrightnesses, vals);
442 }
443
444 private void setBiases(float... vals) {
445 setFloatArrayResource(mBiases, vals);
446 }
447
Anthony Han0c8297c2019-06-18 16:56:11 -0700448 private void setHighLightBrightnesses(float... vals) {
449 setFloatArrayResource(mHighLightBrightnesses, vals);
450 }
451
452 private void setHighLightBiases(float... vals) {
453 setFloatArrayResource(mHighLightBiases, vals);
454 }
455
Anthony Han04c78a92019-05-03 13:34:57 -0700456 private void setFloatArrayResource(TypedArray array, float[] vals) {
457 when(array.length()).thenReturn(vals.length);
458 for (int i = 0; i < vals.length; i++) {
459 when(array.getFloat(i, Float.NaN)).thenReturn(vals[i]);
460 }
461 }
462
463 private void setSensorType(Sensor sensor, int type, String strType) throws Exception {
464 Method setter = Sensor.class.getDeclaredMethod("setType", Integer.TYPE);
465 setter.setAccessible(true);
466 setter.invoke(sensor, type);
467 if (strType != null) {
468 Field f = sensor.getClass().getDeclaredField("mStringType");
469 f.setAccessible(true);
470 f.set(sensor, strType);
471 }
472 }
473
474 private Sensor createSensor(int type, String strType) throws Exception {
475 Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor();
476 constr.setAccessible(true);
477 Sensor sensor = constr.newInstance();
478 setSensorType(sensor, type, strType);
479 return sensor;
480 }
481
482 private TypedArray createTypedArray() throws Exception {
483 TypedArray mockArray = mock(TypedArray.class);
484 return mockArray;
485 }
486
487 private static float mix(float a, float b, float t) {
488 return (1.0f - t) * a + t * b;
489 }
490}